diff --git a/changelog/17005.txt b/changelog/17005.txt new file mode 100644 index 000000000..04273d956 --- /dev/null +++ b/changelog/17005.txt @@ -0,0 +1,13 @@ +```release-note:change +auth: `auth enable` returns an error and `POST /sys/auth/:type` endpoint +reports an error for `Pending Removal` auth methods. +``` +```release-note:change +secrets: `secrets enable` returns an error and `POST /sys/mount/:type` endpoint +reports an error for `Pending Removal` secrets engines. +``` +```release-note:improvement +core: Handle and log deprecated builtin mounts. Introduces +`VAULT_ALLOW_PENDING_REMOVAL_MOUNTS` to override shutdown and error when +attempting to mount `Pending Removal` builtin plugins. +``` diff --git a/command/auth_enable_test.go b/command/auth_enable_test.go index 0cc125fc9..0ba9621e3 100644 --- a/command/auth_enable_test.go +++ b/command/auth_enable_test.go @@ -2,6 +2,7 @@ package command import ( "io/ioutil" + "os" "strings" "testing" @@ -49,6 +50,18 @@ func TestAuthEnableCommand_Run(t *testing.T) { "", 2, }, + { + "deprecated builtin with standard mount", + []string{"app-id"}, + "", + 2, + }, + { + "deprecated builtin with different mount", + []string{"-path=/tmp", "app-id"}, + "", + 2, + }, } for _, tc := range cases { @@ -211,6 +224,16 @@ func TestAuthEnableCommand_Run(t *testing.T) { } for _, b := range backends { + var expectedResult int = 0 + status, _ := builtinplugins.Registry.DeprecationStatus(b, consts.PluginTypeCredential) + allowDeprecated := os.Getenv(consts.VaultAllowPendingRemovalMountsEnv) + + // Need to handle deprecated builtins specially + if (status == consts.PendingRemoval && allowDeprecated == "") || status == consts.Removed { + expectedResult = 2 + } + + // Not a builtin if b == "token" { continue } @@ -218,11 +241,11 @@ func TestAuthEnableCommand_Run(t *testing.T) { ui, cmd := testAuthEnableCommand(t) cmd.client = client - code := cmd.Run([]string{ + actualResult := cmd.Run([]string{ b, }) - if exp := 0; code != exp { - t.Errorf("type %s, expected %d to be %d - %s", b, code, exp, ui.OutputWriter.String()+ui.ErrorWriter.String()) + if actualResult != expectedResult { + t.Errorf("type: %s - got: %d, expected: %d - %s", b, actualResult, expectedResult, ui.OutputWriter.String()+ui.ErrorWriter.String()) } } }) diff --git a/sdk/helper/consts/deprecation_status.go b/sdk/helper/consts/deprecation_status.go index cffee1bd1..5591924a7 100644 --- a/sdk/helper/consts/deprecation_status.go +++ b/sdk/helper/consts/deprecation_status.go @@ -1,5 +1,7 @@ package consts +const VaultAllowPendingRemovalMountsEnv = "VAULT_ALLOW_PENDING_REMOVAL_MOUNTS" + // DeprecationStatus represents the current deprecation state for builtins type DeprecationStatus uint32 diff --git a/vault/logical_system.go b/vault/logical_system.go index 828bd911b..6a301ca15 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -2385,6 +2385,11 @@ func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Reque Version: version, } + err = b.Core.handleDeprecatedMountEntry(ctx, me, consts.PluginTypeCredential) + if err != nil { + return handleError(err) + } + // Attempt enabling if err := b.Core.enableCredential(ctx, me); err != nil { b.Backend.Logger().Error("error occurred during enable credential", "path", me.Path, "error", err) diff --git a/vault/mount.go b/vault/mount.go index c0e143738..8f82dbe0e 100644 --- a/vault/mount.go +++ b/vault/mount.go @@ -463,6 +463,12 @@ func (c *Core) decodeMountTable(ctx context.Context, raw []byte) (*MountTable, e continue } + // Immediately shutdown the core if deprecated mounts are detected and VAULT_ALLOW_PENDING_REMOVAL_MOUNTS is unset + if err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeUnknown); err != nil { + c.logger.Error("shutting down core", "error", err) + c.Shutdown() + } + entry.namespace = ns mountEntries = append(mountEntries, entry) } @@ -585,6 +591,11 @@ func (c *Core) mountInternal(ctx context.Context, entry *MountEntry, updateStora addFilterablePath(c, viewPath) } + // Detect and handle deprecated secrets engines + if err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeSecrets); err != nil { + return err + } + nilMount, err := preprocessMount(c, entry, view) if err != nil { return err @@ -904,6 +915,54 @@ func (c *Core) taintMountEntry(ctx context.Context, nsID, mountPath string, upda return nil } +// handleDeprecatedMountEntry handles the Deprecation Status of the specified +// mount entry's builtin engine as follows: +// +// * Supported - do nothing +// * Deprecated - log a warning about builtin deprecation +// * PendingRemoval - log an error about builtin deprecation and return an error +// if VAULT_ALLOW_PENDING_REMOVAL_MOUNTS is unset +// * Removed - log an error about builtin deprecation and return an error +func (c *Core) handleDeprecatedMountEntry(ctx context.Context, entry *MountEntry, pluginType consts.PluginType) error { + if c.builtinRegistry == nil || entry == nil { + return nil + } + + // Allow type to be determined from mount entry when not otherwise specified + if pluginType == consts.PluginTypeUnknown { + pluginType = c.builtinTypeFromMountEntry(ctx, entry) + } + + // Handle aliases + t := entry.Type + if alias, ok := mountAliases[t]; ok { + t = alias + } + + status, ok := c.builtinRegistry.DeprecationStatus(t, pluginType) + if ok { + // Deprecation sublogger with some identifying information + dl := c.logger.With("name", t, "type", pluginType, "status", status, "path", entry.Path) + errDeprecatedMount := fmt.Errorf("mount entry associated with %s builtin", status) + + switch status { + case consts.Deprecated: + dl.Warn(errDeprecatedMount.Error()) + + case consts.PendingRemoval: + dl.Error(errDeprecatedMount.Error()) + if allow := os.Getenv(consts.VaultAllowPendingRemovalMountsEnv); allow == "" { + return fmt.Errorf("could not mount %q: %w", t, errDeprecatedMount) + } + c.Logger().Info("mount allowed by environment variable", "env", consts.VaultAllowPendingRemovalMountsEnv) + + case consts.Removed: + return fmt.Errorf("could not mount %s: %w", t, errDeprecatedMount) + } + } + return nil +} + // remountForceInternal takes a copy of the mount entry for the path and fully unmounts // and remounts the backend to pick up any changes, such as filtered paths. // Should be only used for internal usage. diff --git a/website/content/docs/commands/server.mdx b/website/content/docs/commands/server.mdx index 929aa5281..1ccb3faa4 100644 --- a/website/content/docs/commands/server.mdx +++ b/website/content/docs/commands/server.mdx @@ -60,6 +60,14 @@ flags](/docs/commands) included on all commands. are "standard" and "json". This can also be specified via the VAULT_LOG_FORMAT environment variable. +- `VAULT_ALLOW_PENDING_REMOVAL_MOUNTS` `(string: "")` - (environment variable) +Allow Vault to be started with builtin engines which have the `Pending Removal` +deprecation state. This is a temporary stopgap in place in order to perform an +upgrade and disable these engines. Once these engines are marked `Removed` (in +the next major release of Vault), the environment variable will no longer work +and a downgrade must be performed in order to remove the offending engines. For +more information, see the [deprecation faq](/docs/deprecation/faq). + ### Dev Options - `-dev` `(bool: false)` - Enable development mode. In this mode, Vault runs diff --git a/website/content/docs/deprecation/faq.mdx b/website/content/docs/deprecation/faq.mdx index b6fe8bf37..1c784b4b3 100644 --- a/website/content/docs/deprecation/faq.mdx +++ b/website/content/docs/deprecation/faq.mdx @@ -29,7 +29,7 @@ If you are an Enterprise user, we recommend that you consider migrating to Hashi ### Q: What should I do if I use Mount Filters, AppID, or any of the standalone DB engines? -These features were deprecated in prior releases of Vault. We are targeting the removal of these features from the product in the Vault 1.11 release. Please plan to upgrade to these features before the release of Vault 1.11. Refer to the table below for a list of alternative features. +These features were deprecated in prior releases of Vault. We are targeting the removal of these features from the product in the Vault 1.12 release. Please plan to upgrade to these features before the release of Vault 1.12. Refer to the table below for a list of alternative features. | Deprecated Feature | Alternative Feature | | --------------------- | ------------------------------------------------------------------------------------------------------------------- | @@ -37,6 +37,8 @@ These features were deprecated in prior releases of Vault. We are targeting the | AppID | [AppRole auth method](/docs/auth/approle) | | Standalone DB engines | [Combined DB engines](/docs/secrets/databases) | +**Note:** After upgrading to 1.12, any attempt to unseal a core with one of the following features enabled will result in a core shutdown. This may temporarily be overridden using the `VAULT_ALLOW_PENDING_REMOVAL_MOUNTS` environment variable when launching the Vault server. These features will be officially removed from Vault in version 1.13 and this environment variable will not work. In order to upgrade to 1.13, you will have to completely disable all removed features. + ### Q: What is the impact of removing support for X.509 certificates with signatures that use SHA-1? Starting with Vault 1.12.0, Vault will be built with Go 1.18. diff --git a/website/content/docs/deprecation/index.mdx b/website/content/docs/deprecation/index.mdx index 7534f02b7..3dcce9e93 100644 --- a/website/content/docs/deprecation/index.mdx +++ b/website/content/docs/deprecation/index.mdx @@ -33,4 +33,5 @@ This announcement page is maintained and updated periodically to communicate imp *If you use **Standalone DB Engines** or **AppID (OSS)**, you should actively plan to migrate away from their usage. If you use these features and upgrade to Release 1.12, Vault will log error messages and shut down, and any attempts to add new mounts will result in an error. +This behavior may temporarily be overridden when starting the Vault server by using the `VAULT_ALLOW_PENDING_REMOVAL_MOUNTS` environment variable until they are officially removed in Vault version 1.13. If you are still using these deprecated features and attempt to upgrade to 1.13 (the target feature removal timeframe), you will not be able to start up Vault without downgrading and migrating away from these features.