From aebc75ecd7b52e52d9d1af75394db26fe7b14ee6 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto Date: Wed, 24 Aug 2022 16:24:09 -0400 Subject: [PATCH] cli: Move deprecation status lookup into backend --- api/sys_mounts.go | 1 + command/auth_list.go | 6 +----- command/secrets_list.go | 6 +----- http/sys_auth_test.go | 8 +++++--- vault/logical_system.go | 27 +++++++++++++++++++-------- vault/mount.go | 34 ++++++++++++++++++++++++++++++++++ vault/testing.go | 11 ++++++++++- 7 files changed, 71 insertions(+), 22 deletions(-) diff --git a/api/sys_mounts.go b/api/sys_mounts.go index 52f51139f77b..08afbbaf6409 100644 --- a/api/sys_mounts.go +++ b/api/sys_mounts.go @@ -281,6 +281,7 @@ type MountOutput struct { Local bool `json:"local"` SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"` + DeprecationStatus string `json:"deprecation_status" mapstructure:"deprecation_status"` } type MountConfigOutput struct { diff --git a/command/auth_list.go b/command/auth_list.go index eadc5046bde3..08317fd4dc63 100644 --- a/command/auth_list.go +++ b/command/auth_list.go @@ -7,8 +7,6 @@ import ( "strings" "github.com/hashicorp/vault/api" - "github.com/hashicorp/vault/helper/builtinplugins" - "github.com/hashicorp/vault/sdk/helper/consts" "github.com/mitchellh/cli" "github.com/posener/complete" ) @@ -164,8 +162,6 @@ func (c *AuthListCommand) detailedMounts(auths map[string]*api.AuthMount) []stri pluginName = mount.Config.PluginName } - status, _ := builtinplugins.Registry.DeprecationStatus(mount.Type, consts.PluginTypeCredential) - out = append(out, fmt.Sprintf("%s | %s | %s | %s | %s | %s | %s | %t | %v | %s | %s | %s | %s", path, pluginName, @@ -179,7 +175,7 @@ func (c *AuthListCommand) detailedMounts(auths map[string]*api.AuthMount) []stri mount.Options, mount.Description, mount.UUID, - status.String(), + mount.DeprecationStatus, )) } diff --git a/command/secrets_list.go b/command/secrets_list.go index d40c96934374..e67a1e821575 100644 --- a/command/secrets_list.go +++ b/command/secrets_list.go @@ -7,8 +7,6 @@ import ( "strings" "github.com/hashicorp/vault/api" - "github.com/hashicorp/vault/helper/builtinplugins" - "github.com/hashicorp/vault/sdk/helper/consts" "github.com/mitchellh/cli" "github.com/posener/complete" ) @@ -164,8 +162,6 @@ func (c *SecretsListCommand) detailedMounts(mounts map[string]*api.MountOutput) pluginName = mount.Config.PluginName } - status, _ := builtinplugins.Registry.DeprecationStatus(mount.Type, consts.PluginTypeSecrets) - out = append(out, fmt.Sprintf("%s | %s | %s | %s | %s | %t | %s | %t | %v | %s | %s | %s | %s", path, pluginName, @@ -179,7 +175,7 @@ func (c *SecretsListCommand) detailedMounts(mounts map[string]*api.MountOutput) mount.Options, mount.Description, mount.UUID, - status.String(), + mount.DeprecationStatus, )) } diff --git a/http/sys_auth_test.go b/http/sys_auth_test.go index e180959173c0..58b4e809152f 100644 --- a/http/sys_auth_test.go +++ b/http/sys_auth_test.go @@ -88,7 +88,7 @@ func TestSysEnableAuth(t *testing.T) { TestServerAuth(t, addr, token) resp := testHttpPost(t, token, addr+"/v1/sys/auth/foo", map[string]interface{}{ - "type": "noop", + "type": "approle", "description": "foo", }) testResponseStatus(t, resp, 204) @@ -106,8 +106,9 @@ func TestSysEnableAuth(t *testing.T) { "data": map[string]interface{}{ "foo/": map[string]interface{}{ "description": "foo", - "type": "noop", + "type": "approle", "external_entropy_access": false, + "deprecation_status": "supported", "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), @@ -135,8 +136,9 @@ func TestSysEnableAuth(t *testing.T) { }, "foo/": map[string]interface{}{ "description": "foo", - "type": "noop", + "type": "approle", "external_entropy_access": false, + "deprecation_status": "supported", "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), diff --git a/vault/logical_system.go b/vault/logical_system.go index 3771e536b01b..127966b4f99d 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -811,7 +811,7 @@ func (b *SystemBackend) handleRekeyDeleteRecovery(ctx context.Context, req *logi return b.handleRekeyDelete(ctx, req, data, true) } -func mountInfo(entry *MountEntry) map[string]interface{} { +func (b *SystemBackend) mountInfo(ctx context.Context, entry *MountEntry) map[string]interface{} { info := map[string]interface{}{ "type": entry.Type, "description": entry.Description, @@ -851,6 +851,12 @@ func mountInfo(entry *MountEntry) map[string]interface{} { entryConfig["token_type"] = entry.Config.TokenType.String() } + // Add deprecation status only if it exists + pluginType, _ := b.Core.pluginTypeFromMountEntry(ctx, entry) + if status, ok := b.Core.builtinRegistry.DeprecationStatus(entry.Type, pluginType); ok { + info["deprecation_status"] = status.String() + } + info["config"] = entryConfig return info @@ -885,7 +891,8 @@ func (b *SystemBackend) handleMountTable(ctx context.Context, req *logical.Reque } // Populate mount info - info := mountInfo(entry) + info := b.mountInfo(ctx, entry) + resp.Data[entry.Path] = info } @@ -1078,7 +1085,7 @@ func (b *SystemBackend) handleReadMount(ctx context.Context, req *logical.Reques } return &logical.Response{ - Data: mountInfo(entry), + Data: b.mountInfo(ctx, entry), }, nil } @@ -2068,7 +2075,11 @@ func (b *SystemBackend) handleAuthTable(ctx context.Context, req *logical.Reques continue } - info := mountInfo(entry) + info := b.mountInfo(ctx, entry) + status, ok := b.Core.builtinRegistry.DeprecationStatus(entry.Type, consts.PluginTypeCredential) + if ok { + info["deprecation_status"] = status.String() + } resp.Data[entry.Path] = info } @@ -2102,7 +2113,7 @@ func (b *SystemBackend) handleReadAuth(ctx context.Context, req *logical.Request } return &logical.Response{ - Data: mountInfo(entry), + Data: b.mountInfo(ctx, entry), }, nil } @@ -3759,7 +3770,7 @@ func (b *SystemBackend) pathInternalUIMountsRead(ctx context.Context, req *logic if ns.ID == entry.NamespaceID && hasAccess(ctx, entry) { if isAuthed { // If this is an authed request return all the mount info - secretMounts[entry.Path] = mountInfo(entry) + secretMounts[entry.Path] = b.mountInfo(ctx, entry) } else { secretMounts[entry.Path] = map[string]interface{}{ "type": entry.Type, @@ -3786,7 +3797,7 @@ func (b *SystemBackend) pathInternalUIMountsRead(ctx context.Context, req *logic if ns.ID == entry.NamespaceID && hasAccess(ctx, entry) { if isAuthed { // If this is an authed request return all the mount info - authMounts[entry.Path] = mountInfo(entry) + authMounts[entry.Path] = b.mountInfo(ctx, entry) } else { authMounts[entry.Path] = map[string]interface{}{ "type": entry.Type, @@ -3844,7 +3855,7 @@ func (b *SystemBackend) pathInternalUIMountRead(ctx context.Context, req *logica return errResp, logical.ErrPermissionDenied } resp := &logical.Response{ - Data: mountInfo(me), + Data: b.mountInfo(ctx, me), } resp.Data["path"] = me.Path diff --git a/vault/mount.go b/vault/mount.go index 06671ba99ae3..bfb28e6f4b1d 100644 --- a/vault/mount.go +++ b/vault/mount.go @@ -659,6 +659,40 @@ func (c *Core) mountInternal(ctx context.Context, entry *MountEntry, updateStora return nil } +// pluginTypeFromMountEntry attempts to find a pluginType associated with the +// specified MountEntry. Returns consts.PluginTypeUnknown in the following cases: +// +// * Multiple types match (also returns an error) +// * No types match (no error) +func (c *Core) pluginTypeFromMountEntry(ctx context.Context, entry *MountEntry) (consts.PluginType, error) { + var pluginTypes []consts.PluginType + if c.builtinRegistry == nil || entry == nil { + return consts.PluginTypeUnknown, nil + } + + pluginType, _ := consts.ParsePluginType(entry.Table) + if pluginType != consts.PluginTypeUnknown { + pluginTypes = append(pluginTypes, pluginType) + } + + if c.builtinRegistry.Contains(entry.Type, consts.PluginTypeSecrets) { + pluginTypes = append(pluginTypes, consts.PluginTypeSecrets) + } + + if c.builtinRegistry.Contains(entry.Type, consts.PluginTypeDatabase) { + pluginTypes = append(pluginTypes, consts.PluginTypeDatabase) + } + + switch len(pluginTypes) { + case 0: + return consts.PluginTypeUnknown, nil + case 1: + return pluginTypes[0], nil + default: + return consts.PluginTypeUnknown, fmt.Errorf("too many plugin types for mount entry") + } +} + // Unmount is used to unmount a path. The boolean indicates whether the mount // was found. func (c *Core) unmount(ctx context.Context, path string) error { diff --git a/vault/testing.go b/vault/testing.go index 8a42c617309e..24c2c21c5d65 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -2244,11 +2244,20 @@ func (m *mockBuiltinRegistry) Keys(pluginType consts.PluginType) []string { } func (m *mockBuiltinRegistry) Contains(name string, pluginType consts.PluginType) bool { + for _, key := range m.Keys(pluginType) { + if key == name { + return true + } + } return false } func (m *mockBuiltinRegistry) DeprecationStatus(name string, pluginType consts.PluginType) (consts.DeprecationStatus, bool) { - return consts.Supported, true + if m.Contains(name, pluginType) { + return consts.Supported, true + } + + return consts.Unknown, false } type NoopAudit struct {