HashiCorp Vault's PKI mount vulnerable to denial of service
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
Details
HashiCorp Vault's PKI mount issuer endpoints did not correctly authorize access to remove an issuer or modify issuer metadata, potentially resulting in denial of service of the PKI mount. This bug did not affect public or private key material, trust chains or certificate issuance. Fixed in Vault 1.13.1, 1.12.5, and 1.11.9.
The fix
Release delta 1.12.0 → 1.12.5 (contains the fix)
website/content/docs/concepts/policies.mdx+19 −19
@@ -181,10 +181,10 @@ also match `"secret/foobar"`. Specifically, when there are potentially multiplematching policy paths, `P1` and `P2`, the following matching criteria is applied:1. If the first wildcard (`+`) or glob (`*`) occurs earlier in `P1`, `P1` is lower priority-2. If `P1` ends in `*` and `P2` doesn't, `P1` is lower priority-3. If `P1` has more `+` (wildcard) segments, `P1` is lower priority-4. If `P1` is shorter, it is lower priority-5. If `P1` is smaller lexicographically, it is lower priority+1. If `P1` ends in `*` and `P2` doesn't, `P1` is lower priority+1. If `P1` has more `+` (wildcard) segments, `P1` is lower priority+1. If `P1` is shorter, it is lower priority+1. If `P1` is smaller lexicographically, it is lower priorityFor example, given the two paths, `"secret/*"` and `"secret/+/+/foo/*"`, the firstwildcard appears in the same place, both end in `*` and the latter has two wildcard@@ -263,19 +263,19 @@ injected, and currently the `path` keys in policies allow injection.### Parameters-| Name | Description |-| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------- |-| `identity.entity.id` | The entity's ID |-| `identity.entity.name` | The entity's name |-| `identity.entity.metadata.<metadata key>` | Metadata associated with the entity for the given key |-| `identity.entity.aliases.<mount accessor>.id` | Entity alias ID for the given mount |-| `identity.entity.aliases.<mount accessor>.name` | Entity alias name for the given mount |-| `identity.entity.aliases.<mount accessor>.metadata.<metadata key>` | Metadata associated with the alias for the given mount and metadata key |-| `identity.entity.aliases.<mount accessor>.custom_metadata.<custom_metadata key>` | Custom metadata associated with the alias for the given mount and custom metadata key |-| `identity.groups.ids.<group id>.name` | The group name for the given group ID |-| `identity.groups.names.<group name>.id` | The group ID for the given group name |-| `identity.groups.ids.<group id>.metadata.<metadata key>` | Metadata associated with the group for the given key |-| `identity.groups.names.<group name>.metadata.<metadata key>` | Metadata associated with the group for the given key |+| Name | Description |+| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------ |+| `identity.entity.id` | The entity's ID |+| `identity.entity.name` | The entity's name |+| `identity.entity.metadata.<metadata key>` | Metadata associated with the entity for the given key |+| `identity.entity.aliases.<mount accessor>.id` | Entity alias ID for the given mount |+| `identity.entity.aliases.<mount accessor>.name` | Entity alias name for the given mount |+| `identity.entity.aliases.<mount accessor>.metadata.<metadata key>` | Metadata associated with the alias for the given mount and metadata key |+| `identity.entity.aliases.<mount accessor>.custom_metadata.<custom_metadata key>` | Custom metadata associated with the alias for the given mount and custom metadata key |+| `identity.groups.ids.<group id>.name` | The group name for the given group ID |+| `identity.groups.names.<group name>.id` | The group ID for the given group name |+| `identity.groups.ids.<group id>.metadata.<metadata key>` | Metadata associated with the group for the given key |+| `identity.groups.names.<group name>.metadata.<metadata key>` | Metadata associated with the group for the given key |### Examples@@ -614,8 +614,8 @@ $ curl \For more information, please read:-- [Production Hardening](/guides/operations/production)-- [Generating a Root Token](/guides/operations/generate-root)+- [Production Hardening](https://learn.hashicorp.com/tutorials/vault/production-hardening)+- [Generating a Root Token](https://learn.hashicorp.com/tutorials/vault/generate-root)## Managing Policies
website/content/docs/upgrading/plugins.mdx+127 −151
@@ -6,58 +6,76 @@ description: These are general upgrade instructions for Vault plugins.# Upgrading Vault Plugins-## External Plugin Upgrade Procedure+## Plugin Upgrade Procedure-The following procedure details steps for upgrading an external plugin that has-been registered to the catalog on a running server. This procedure is-applicable to secret engines, auth methods, and database plugins.+The following procedures detail steps for upgrading a plugin that has been mounted+at a path on a running server. The steps are the same whether the plugin being+upgraded is built-in or external.-Vault executes plugin binaries when they are configured and roles are established-around them. The binary cannot be modified or replaced while running, so-upgrades cannot be performed by simply swapping the binary and updating the hash-in the plugin catalog.+~> Plugin versioning was introduced with Vault 1.12.0, so if your Vault server is+on 1.11.x or earlier, see the [1.11.x version of this page](/docs/v1.11.x/upgrading/plugins)+for plugin upgrade instructions.-Instead, you can restart or reload a plugin with the-`sys/plugins/reload/backend` [API][plugin_reload_api]. Follow these steps to-replace or upgrade a Vault plugin binary:+### Upgrading auth and secrets plugins-1. [Register][plugin_registration] version 1 of `my-db-plugin` to the catalog.-Skip this step if your plugin is already registered.+The process is nearly identical for auth and secret plugins. If you are upgrading+an auth plugin, just replace all usages of `secrets` or `secret` with `auth`.++1. [Register][plugin_registration] the first version of your plugin to the catalog.+Skip this step if your initial plugin is built-in or already registered.```shell-session-$ vault plugin register -sha256=<SHA256 Hex value of the plugin binary> \-database \ # type-my-db-plugin+$ vault plugin register+-sha256=<SHA256 Hex value of the plugin binary> \+secret \+my-secret-plugin```-2. [Mount][plugin_management] the plugin backend. Skip this step if the backend+1. [Mount][plugin_management] the plugin. Skip this step if your initial pluginis already mounted.```shell-session-$ vault secrets enable database+$ vault secrets enable my-secret-plugin```-3. Register version 2 of `my-db-plugin` to the catalog under the same plugin-name, but with updated command to run version 2 of `my-db-plugin` and updated-sha256 of the new binary+1. Register a second version of your plugin. You **must** use the same plugin+type and name (the last two arguments) as the plugin being upgraded. This is+true regardless of whether the plugin being upgraded is built-in or external.```shell-session-$ vault plugin register -sha256=<SHA256 Hex value of the plugin binary> \-database \ # type-my-db-plugin+$ vault plugin register \+-sha256=<SHA256 Hex value of the plugin binary> \+-command=my-secret-plugin-1.0.1 \+-version=v1.0.1 \+secret \+my-secret-plugin```-4. Trigger a [plugin reload](/docs/commands/plugin/reload) to reload all+1. Tune the existing mount to configure it to use the newly registered version.++```shell-session+$ vault secrets tune -plugin-version=v1.0.1 my-secret-plugin+```++1. If you wish, you can check the updated configuration. Notice the "Version" is+now different from the "Running Version".++```shell-session+$ vault secrets list -detailed+```++1. Finally, trigger a [plugin reload](/docs/commands/plugin/reload) to reload allmounted backends using that plugin or a subset of the mounts using that plugin-with either the `plugin` or `mounts` parameter respectively.+with either the `plugin` or `mounts` flag respectively.```shell-session-$ vault plugin reload -plugin my-db-plugin+$ vault plugin reload -plugin my-secret-plugin```-Until step 4, the mount will still use version 1 of `my-db-plugin`, and when-the reload is triggered, Vault will kill `my-db-plugin`’s process and start the-new plugin process for `my-db-plugin` version 2.+Until the last step, the mount will still run the first version of `my-secret-plugin`. When+the reload is triggered, Vault will kill `my-secret-plugin`’s process and start the+new plugin process for `my-secret-plugin` version 1.0.1. The "Running Version" should also+now match the "Version" when you run `vault secrets list -detailed`.-> **Important:** Plugin reload of a new plugin binary must beperformed on each Vault instance. Performing a plugin upgrade on a single@@ -65,147 +83,101 @@ instance or through a load balancer can result in mismatchedplugin binaries within a cluster. On a replicated cluster this may be accomplishedby setting the 'scope' parameter of the reload to 'global'.-## Overriding Built-in Plugins--### Background--Vault's auth methods and secrets engines are structured as plugins, but this-design is not obvious since many of them are built into Vault.--You can see them with the Vault plugin list command, for example, the list of-Secrets engines:--```shell-session-$ vault plugin list secret-Plugins-ad-alicloud-aws-azure-cassandra-consul-gcp-gcpkms-kv-ldap-mongodb-mongodbatlas-mssql-mysql-nomad-openldap-pki-postgresql-rabbitmq-ssh-terraform-totp-transit-```--This will list all Secrets engines, internal (built-in) or external. To find-out if a plugin is built-in, we can query its info:--```shell-session-$ vault plugin info secret azure-Key Value-args []-builtin true-command n/a-name azure-sha256 n/a-```--Because these built-in engines are plugins, they can be overridden. This can be-a useful way to leverage features or bug fixes in plugins that are newer than-the version of Vault you're using, without updating or even restarting Vault,-and while retaining the data for your existing mount.--Assume you have a new version of Azure Secrets and the binary is called-"azure_new". The binary needs to be in the [plugin directory](/docs/plugins/plugin-architecture#plugin-directory)-and can then be registered as either a distinct plugin, or overriding the-current one.--~> **Important:** do not disable (`vault secrets disable ...`) any mount that has-data you're interested in; that would erase storage. For the in-place update,-register a new plugin atop the built-in one and leave any mounts alone.--### Procedure for Overriding Built-in Plugins--The syntax is the same as an external plugin, with the difference being you-name it the same as a built-in:+### Upgrading database plugins-```shell-session-$ vault plugin register \--sha256=<SHA256 Hex value of the plugin binary> \--command=azure_new \-secret \-azure-```+1. [Register][plugin_registration] the first version of your plugin to the catalog.+Skip this step if your initial plugin is built-in or already registered.-"-command=azure_new" is the name of the binary, "secret" is the plugin type,-and "azure" is the name of the built-in plugin that we're overriding. We can-verify that the override is in place:--```shell-session-$ vault plugin info secret azure-Key Value-args []-builtin false-command azure_new-name azure-sha256 f6f6ec45d37484c257aa9ff80444b9f244aaef1c650edf8a42a2a1d3f00db2c5-```+```shell-session+$ vault plugin register+-sha256=<SHA256 Hex value of the plugin binary> \+database \+my-db-plugin+```-At this point we've overridden the built-in, but it is not yet actively-handling requests. For that we run:+1. [Mount][plugin_management] the plugin. Skip this step if your initial plugin+is already mounted.-```shell-session-$ vault plugin reload -plugin=azure-```+```shell-session+$ vault secrets enable database+$ vault write database/config/my-db \+plugin_name=my-db-plugin \+# ...+```-### Procedure for Reverting After Overriding A Built-in Plugin+1. Register a second version of your plugin. You **must** use the same plugin+type and name (the last two arguments) as the plugin being upgraded. This is+true regardless of whether the plugin being upgraded is built-in or external.-To revert the override, first deregister the plugin:+```shell-session+$ vault plugin register \+-sha256=<SHA256 Hex value of the plugin binary> \+-command=my-db-plugin-1.0.1 \+-version=v1.0.1 \+database \+my-db-plugin+```-```shell-session-$ vault plugin deregister secret azure-```+1. Update the database config with the new version. The database secrets+engine will immediately reload the plugin, using the new version. Any omitted+config parameters will not be updated.++```shell-session+$ vault write database/config/my-db \+plugin_version=v1.0.1+```-Next, verify the override has been reverted and we are now using the built-in-plugin:+Until the last step, the mount will still run the first version of `my-db-plugin`. When+the reload is triggered, Vault will kill `my-db-plugin`’s process and start the+new plugin process for `my-db-plugin` version 1.0.1.-```shell-session-$ vault plugin info secret azure-Key Value-args []-builtin true-command n/a-name azure-sha256 n/a-```+### Downgrading Plugins-Finally, reload the plugin:+Plugin downgrades follow the same procedure as upgrades. You can use the Vault+plugin list command to check what plugin versions are available to downgrade to:```shell-session-$ vault plugin reload -plugin=azure+$ vault plugin list secret+Name Version+---- -------+ad v0.14.0+builtin+alicloud v0.13.0+builtin+aws v1.12.0+builtin.vault+azure v0.14.0+builtin+cassandra v1.12.0+builtin.vault+consul v1.12.0+builtin.vault+gcp v0.14.0+builtin+gcpkms v0.13.0+builtin+kv v0.13.3+builtin+ldap v1.12.0+builtin.vault+mongodb v1.12.0+builtin.vault+mongodbatlas v0.8.0+builtin+mssql v1.12.0+builtin.vault+mysql v1.12.0+builtin.vault+nomad v1.12.0+builtin.vault+openldap v0.9.0+builtin+pki v1.12.0+builtin.vault+postgresql v1.12.0+builtin.vault+rabbitmq v1.12.0+builtin.vault+ssh v1.12.0+builtin.vault+terraform v0.6.0+builtin+totp v1.12.0+builtin.vault+transit v1.12.0+builtin.vault```-### Caveats to Overriding Built-in Plugins+### Additional Upgrade Notes* As mentioned earlier, disabling existing mounts will wipe the existing data.-* This type of upgrade affects all uses of the plugin. So if you have 5-different Azure Secrets mounts, they'll all change after the replacement. If-you don't want that, you'll need to register the plugin under a different name-and start with a fresh mount.-* In most cases, data upgrade and downgrade is not an issue. If the "new" version-introduces new data and you downgrade, the "old" version will ignore the-extraneous data. In some cases upgrading changes existing data in non-backwards-compatible ways, so it is good to check whether this is an issue.+* Overwriting an existing version in the catalog will affect all uses of that+plugin version. So if you have 5 different Azure Secrets mounts using v1.0.0,+they'll all start using the new binary if you overwrite it. We recommend+treating plugin versions in the catalog as immutable, much like version control+tags.+* Each plugin has its own data within Vault storage. While it is rare for HashiCorp+maintained plugins to update their storage schema, it is up to plugin authors+to manage schema upgrades and downgrades. Check the plugin release notes for+any unsupported upgrade or downgrade transitions, especially before moving to+a new major version or downgrading.[plugin_reload_api]: /api-docs/system/plugins-reload-backend[plugin_registration]: /docs/plugins/plugin-architecture#plugin-registration<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>6cb818993eaf8537f65816daf7123645adc7d926 (#17505)builtin/logical/pki/path_tidy.go | 11 -----------changelog/17497.txt | 3 +++2 files changed, 3 insertions(+), 11 deletions(-)create mode 100644 changelog/17497.txt
website/content/api-docs/system/auth.mdx+62 −32
@@ -30,18 +30,52 @@ $ curl \```json{-"github/": {-"type": "github",-"description": "GitHub auth"-},-"token/": {-"config": {-"default_lease_ttl": 0,-"max_lease_ttl": 0+"request_id": "9bc0fab8-d65c-3961-afe6-d05f50c5fd22",+"lease_id": "",+"lease_duration": 0,+"renewable": false,+"data": {+"github/": {+"accessor": "auth_github_badd7fd0",+"config": {+"default_lease_ttl": 0,+"force_no_cache": false,+"max_lease_ttl": 0,+"token_type": "default-service"+},+"deprecation_status": "supported",+"description": "",+"external_entropy_access": false,+"local": false,+"options": null,+"plugin_version": "",+"running_plugin_version": "v1.12.0+builtin.vault",+"running_sha256": "",+"seal_wrap": false,+"type": "github",+"uuid": "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be"},-"description": "token based credentials",-"type": "token"-}+"token/": {+"accessor": "auth_token_bd90f507",+"config": {+"default_lease_ttl": 0,+"force_no_cache": false,+"max_lease_ttl": 0,+"token_type": "default-service"+},+"description": "token based credentials",+"external_entropy_access": false,+"local": false,+"options": null,+"plugin_version": "",+"running_plugin_version": "v1.12.0+builtin.vault",+"running_sha256": "",+"seal_wrap": false,+"type": "token",+"uuid": "e162baec-721b-7657-7913-c960df402f8a"+}+},+"warnings": null}```@@ -99,6 +133,11 @@ For example, enable the "foo" auth method will make it accessible at- `allowed_response_headers` `(array: [])` - List of headers to whitelist,allowing a plugin to include them in the response.+- `plugin_version` `(string: "")` – Specifies the semantic version of the plugin+to use, e.g. "v1.0.0". If unspecified, the server will select any matching+unversioned plugin that may have been registered, the latest versioned plugin+registered, or a built-in plugin in that order of precendence.+Additionally, the following options are allowed in Vault open-source, butrelevant functionality is only supported in Vault Enterprise:@@ -145,9 +184,9 @@ $ curl \This endpoints returns the configuration of the auth method at the given path.-| Method | Path |-| :----- | :--------------- |-| `GET` | `/sys/auth/path` |+| Method | Path |+| :----- | :---------------- |+| `GET` | `/sys/auth/:path` |### Sample Request@@ -161,24 +200,10 @@ $ curl \```json{-"uuid": "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be",-"type": "github",-"accessor": "auth_github_badd7fd0",-"local": false,-"seal_wrap": false,-"external_entropy_access": false,-"options": null,-"config": {-"default_lease_ttl": 0,-"force_no_cache": false,-"max_lease_ttl": 0,-"token_type": "default-service"-},-"description": "","request_id": "8d2a1e33-4c00-46a5-f50d-4dc5f5d96f12","lease_id": "",-"renewable": false,"lease_duration": 0,+"renewable": false,"data": {"accessor": "auth_github_badd7fd0","config": {@@ -187,17 +212,19 @@ $ curl \"max_lease_ttl": 0,"token_type": "default-service"},+"deprecation_status": "supported","description": "","external_entropy_access": false,"local": false,"options": null,+"plugin_version": "",+"running_plugin_version": "v1.12.0+builtin.vault",+"running_sha256": "","seal_wrap": false,"type": "github","uuid": "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be"},-"wrap_info": null,-"warnings": null,-"auth": null+"warnings": null}```@@ -316,6 +343,9 @@ can be achieved without `sudo` via `sys/mounts/auth/[auth-path]/tune`._- `batch`: Override any auth method preference and always issue batch tokensfrom this mount+- `plugin_version` `(string: "")` – Specifies the semantic version of the plugin+to use, e.g. "v1.0.0". Changes will not take effect until the mount is reloaded.+### Sample Payload```json
website/content/docs/commands/secrets/list.mdx+27 −11
@@ -17,34 +17,48 @@ that the system default is in use.## Deprecation Status Column-As of 1.12, all builtin secrets engines will have an associated Deprecation+As of 1.12, all built-in secrets engines will have an associated DeprecationStatus. This status will be reflected in the `Deprecation Status` column, seen-below. All secrets engines which are not provided by builtin plugins will show a+below. All secrets engines which are not provided by built-in plugins will show a`Deprecation Status` of "n/a".+## Version Columns++The `-detailed` view displays some version information for each mount.++The Version field indicates the configured version for the plugin. Empty, or "n/a",+indicates the built-in or any matching unversioned plugin that may have been registered.++Running Version indicates the actual plugin version running, which may differ from+Version if the plugin hasn't been reloaded since the configured version was updated+using the `secrets tune` command. Finally, the Running SHA256 field indicates the+SHA256 sum of the running plugin's binary. This may be different from the SHA256+registered in the catalog if the plugin hasn't been reloaded since the plugin+version was overwritten in the catalog.+## ExamplesList all enabled secrets engines:```shell-session$ vault secrets list-Path Type Description-cubbyhole/ cubbyhole per-token private secret storage-secret/ kv key/value secret storage-sys/ system system endpoints used for control, policy and debugging+Path Type Accessor Description+---- ---- -------- -----------+cubbyhole/ cubbyhole cubbyhole_548b4dc5 per-token private secret storage+secret/ kv identity_aa00c06d key/value secret storage+sys/ system system_547412e3 system endpoints used for control, policy and debugging```List all enabled secrets engines with detailed output:```shell-session$ vault secrets list -detailed-Path Plugin Accessor Default TTL Max TTL Force No Cache Replication Seal Wrap External Entropy Access Options Description UUID Deprecation Status-cubbyhole/ cubbyhole cubbyhole_b16d1bc0 n/a n/a false local false false map[] per-token private secret storage 8c64d56b-9d46-d667-1155-a8c1a83a5d01 n/a-identity/ identity identity_3d67c936 system system false replicated false false map[] identity store 5aa1e59c-33b5-9dec-05d6-c80c9a800557 n/a-postgresql/ postgresql postgresql_f0a54308 system system false replicated false false map[] n/a 8cdc1d2d-0713-eaa6-17e3-49790a60650b deprecated-sys/ system system_c86bd362 n/a n/a false replicated true false map[] system endpoints used for control, policy and debugging e3193999-0875-d38d-3458-21d9f2762c80 n/a+Path Plugin Accessor Default TTL Max TTL Force No Cache Replication Seal Wrap External Entropy Access Options Description UUID Version Running Version Running SHA256 Deprecation Status+---- ------ -------- ----------- ------- -------------- ----------- --------- ----------------------- ------- ----------- ---- ------- --------------- -------------- ------------------+cubbyhole/ cubbyhole cubbyhole_b16d1bc0 n/a n/a false local false false map[] per-token private secret storage 8c64d56b-9d46-d667-1155-a8c1a83a5d01 n/a v1.12.0+builtin.vault n/a n/a+identity/ identity identity_3d67c936 system system false replicated false false map[] identity store 5aa1e59c-33b5-9dec-05d6-c80c9a800557 n/a v1.12.0+builtin.vault n/a n/a+postgresql/ postgresql postgresql_f0a54308 system system false replicated false false map[] n/a 8cdc1d2d-0713-eaa6-17e3-49790a60650b n/a v1.12.0+builtin.vault n/a deprecated+sys/ system system_c86bd362 n/a n/a false replicated true false map[] system endpoints used for control, policy and debugging e3193999-0875-d38d-3458-21d9f2762c80 n/a v1.12.0+builtin.vault n/a n/a```## Usage
website/content/docs/plugins/index.mdx+58 −15
@@ -7,21 +7,24 @@ description: Learn about Vault's plugin system.# Plugin System-All Vault auth methods and secrets engines are considered plugins. This concept-allows both built-in and external plugins to be treated like building blocks.-Any plugin can exist at multiple different mount paths. Different versions of a-plugin may be at each location, with each version differing from Vault's-version.+Vault supports 3 types of plugins; auth methods, secret engines, and database+plugins. This concept allows both built-in and external plugins to be treated+like building blocks. Any plugin can exist at multiple different mount paths.+Different versions of a plugin may be at each location, with each version differing+from Vault's version.-## Built-In Plugins+A plugin is uniquely identified by its type (one of `secret`, `auth`, or+`database`), name (e.g. `aws`), and version (e.g `v1.0.0`). An empty version+implies either the built-in plugin or the single unversioned plugin that can+be registered.++See [Plugin Upgrade Procedure](/docs/upgrading/plugins#plugin-upgrade-procedure)+for details on how to upgrade a built-in plugin in-place.-Built-in plugins are shipped with Vault, often for commonly used implementations,-and require no additional operator intervention to run. Built-in plugins are-just like any other backend code inside Vault.+## Built-In Plugins-To use a different or edited version of a built-in plugin, the plugin must be-run as an external plugin. See [Overriding Built-in Plugins](/docs/upgrading/plugins#overriding-built-in-plugins)-for details on how to override a built-in plugin in-place.+Built-in plugins are shipped with Vault, often for commonly used integrations,+and can be used without any prerequisite steps.## External Plugins@@ -33,8 +36,48 @@ binaries can be obtained from [releases.hashicorp.com](https://releases.hashicoror they can be [built from source](/docs/plugins/plugin-development#building-a-plugin-from-source).Vault's external plugins are completely separate, standalone applications that-Vault executes and communicates with over RPC. Each time a Vault secret engine-or auth method is mounted, a new process is spawned. However, plugins can be-made to implement [plugin multiplexing](/docs/plugins/plugin-architecture#plugin-multiplexing)+Vault executes and communicates with over RPC. Each time a Vault secret engine,+auth method, or database plugin is mounted, a new process is spawned. However,+plugins can be made to implement [plugin multiplexing](/docs/plugins/plugin-architecture#plugin-multiplexing)to improve performance. Plugin multiplexing allows plugin processes to bereused across all mounts of a given type.++## Plugin Versioning++Vault supports managing, running and upgrading plugins using semantic version+information.++The plugin catalog optionally supports specifying a semantic version when+registering an external plugin. Multiple versions of a plugin can be registered+in the catalog simultaneously, and a version can be selected when mounting a+plugin or tuning an existing mount in-place.++If no version is specified when creating a new mount, the following precedence is used+for any available plugins whose type and name match:++* The plugin registered with no version+* The plugin with the most recent semantic version among any registered versions+* The plugin built into Vault++### Built-In Versions++Vault will report a version for built-in plugins to indicate what version of the+plugin code got built into Vault as a dependency. For example:++```shell-session+$ vault plugin list secret+Name Version+---- -------+ad v0.14.0+builtin+alicloud v0.13.0+builtin+aws v1.12.0+builtin.vault+# ...+```++Here, Vault has a dependency on `v0.14.0` of the [hashicorp/vault-plugin-secrets-ad](https://github.com/hashicorp/vault-plugin-secrets-ad)+repo, and the `vault` metadata identifier for `aws` indicates that plugin's code was+within the Vault repo. For plugins within the Vault repo, Vault's own major, minor,+and patch versions are used to form the plugin version.++The `builtin` metadata identifier is reserved and cannot be used when registering+external plugins.
website/content/docs/interoperability-matrix.mdx+85 −0
@@ -0,0 +1,85 @@+---+layout: docs+page_title: Vault Interoperability Matrix+description: Guide to viewing which partners Vault integrates with.+---++# Vault Interoperability Matrix++Vault integrates with various appliances, platforms and applications for different use cases. Below are two tables indicating the partner’s product that has been verified to work with Vault for [Auto Unsealing](/docs/concepts/seal#auto-unseal) / [HSM Support](/docs/enterprise/hsm) and [External Key Management](/use-cases/key-management).++Auto Unseal and HSM Support was developed to aid in reducing the operational complexity of keeping the unseal key secure. This feature delegates the responsibility of securing the unseal key from users to a trusted device or service. At startup Vault will connect to the device or service implementing the seal and ask it to decrypt the root key Vault read from storage.++Vault centrally manages and automates encryption keys across environments allowing customers to control their own encryption keys used in third party services or products.++## Vault Seal and HSM Interoperability++The below table shows the partner product and if the partner’s technology works with each individual seal component.++| Partner | Product | Auto Unseal <br/> (Vault 0.9+) | Entropy Augmentation <br/>(Vault 1.3+) | Seal Wrap <br/>(Vault 0.9+) | Managed Keys <br/> (Vault 1.10+) | Min. Vault Version Verified |+| ----------------- | -------------------------------------- | ------------ | -------------------- | ------------ |-------------- | --------------------------- |+| AliCloud | AliCloud KMS | Yes | No | Yes | No | 0.11.2 |+| Atos | Trustway Proteccio HSM | Yes | Yes | Yes | No | 1.9 |+| AWS | AWS KMS | Yes | No | Yes | Yes | 0.9 |+| Crypto4a | QxEDGE™️ HSP | Yes | Yes | Yes | Yes | 1.9 |+| Entrust | nShield HSM | Yes | Yes | Yes | Yes | 1.3 |+| Fortanix | FX2200 Series | Yes | Yes | Yes | No | 0.10 |+| FutureX | Vectera Plus, KMES Series 3 | Yes | Yes | Yes | Yes | 1.5 |+| FutureX | VirtuCrypt cloud HSM | Yes | Yes | Yes | Yes | 1.5 |+| Google | GCP Cloud KMS | Yes | No | Yes | Yes | 0.9 |+| Microsoft | Azure Key Vault | Yes | No | Yes | Yes | 0.10.2 |+| Oracle | OCI KMS | Yes | No | Yes | No | 1.2.3 |+| PrimeKey | SignServer Hardware Appliance | Yes | Yes | Yes | No | 1.6 |+| Qrypt | Quantum Entropy Service | No | Yes | No | No | 1.11 |+| Quintessence Labs | TSF 400 | Yes | Yes | Yes | No | 1.4 |+| Securosys SA | Primus HSM | Yes | Yes | Yes | Yes | 1.7 |+| Thales | Luna HSM | Yes | Yes | Yes | Yes | 1.4 |+| Thales | Luna TCT HSM | Yes | Yes | Yes | Yes | 1.4 |+| Thales | CipherTrust Manager | Yes | Yes | Yes | No | 1.7 |+| Utimaco | HSM | Yes | Yes | Yes | Yes | 1.4 |+| Yubico | YubiHSM 2 | Yes | Yes | Yes | No | 1.5 |+<span style={{display:'block', textAlign:'right', fontSize:'12px'}}><em>Last Updated September 29, 2022</em></span>++## Vault as an External Key Management System (EKMS)++Partners who integrate with Vault to have Vault store and/or manage encryption keys with their products++~> Note: HCP Vault Verified means that the integration has been verified to work with HCP Vault. All integrations have been verified with Vaut self-managed.++<span style={{fontSize:'12px'}}>+Vault Secrets Engine Key: K/V = <a href="/docs/secrets/kv">K/V secrets engine</a>; KMSE = <a href="/docs/secrets/key-management">Key Management Secrets Engine</a>; KMIP = <a href="/docs/secrets/kmip">KMIP Secrets Engine</a>; Transit = <a href="/docs/secrets/transit">Transit Secrets Engine</a>+</span>++| Partner | Product | Vault Secrets Engine | Min. Vault Version Verified | HCP Vault Verified |+| ----------------- | ---------------------- | -------------------- | --------------------------- | ------------------- |+| AWS | AWS KMS | KMSE | 1.8 | Yes |+| Baffle | Shield | K/V | 1.3 | No |+| Bloombase | StoreSafe | KMIP | 1.9 | N/A |+| Cockroach Labs | Cockroach Cloud DB | KMSE | 1.10 | N/A |+| Cockroach Labs | Cockroach DB | Transit | 1.10 | Yes |+| Commvault Systems | CommVault | KMIP | 1.9 | N/A |+| Cribl | Cribl Stream | K/V | 1.8 | Yes |+| DataStax | DataStax Enterprise | KMIP | 1.11 | Yes |+| Garantir | GaraSign | Transit | 1.5 | Yes |+| Google | Google KMS | KMSE | 1.9 | N/A |+| HPE | Exmeral Data Fabric | KMIP | 1.2 | N/A |+| Intel | Key Broker Service | KMIP | 1.11 | N/A |+| Micro Focus | Connected Mx | Transit | 1.7 | No |+| Microsoft | Azure Key Vault | KMSE | 1.6 | N/A |+| MinIO | Key Encryption Service | K/V | 1.11 | No |+| MongoDB | Atlas | KMSE | 1.6 | N/A |+| MongoDB | MongoDB Enterprise | KMIP | 1.2 | N/A |+| MongoDB | Client Libraries | KMIP | 1.9 | N/A |+| NetApp | ONTAP | KMIP | 1.2 | N/A |+| Ondat | Trousseau | Transit | 1.9 | Yes |+| Percona | Server 8.0 | KMIP | 1.9 | N/A |+| Percona | XtraBackup 8.0 | KMIP | 1.9 | N/A |+| Snowflake | Snowflake | KMSE | 1.6 | N/A |+| VMware | vSphere 7.0 | KMIP | 1.2 | N/A |+| VMware | vSan | KMIP | 1.2 | N/A |+| Yugabyte | Yugabyte Platform | Transit | 1.9 | No |+<span style={{display:'block', textAlign:'right', fontSize:'12px'}}><em>Last Updated September 29, 2022</em></span>++Please reach out to [technologypartners@hashicorp.com](mailto:technologypartners@hashicorp.com) if there are any questions on the above tables.++Missing an integration? Join the [Vault Integration Program](/docs/partnerships) and get the integration listed.
website/content/docs/concepts/client-count/faq.mdx+2 −2
@@ -89,7 +89,7 @@ Although client counts have been available via the usage metrics UI since Vault- Changed the non-entity token computation logic to deduplicate non-entity tokens, reducing the overall client count. Moving forward, non-entity tokens, where there is no entity to map tokens, Vault will use the contents of the token to generate a unique client identifier based on the namespace ID and associated policies. The clientID will prevent duplicating the same token in the overall client count when the token is used again during the billing period.- Changed the tracking of non-entity tokens to complete on access instead of creation.- Changed the computation logic to not include root tokens in the client count aggregate.-- Changed the local auth mount computation logic such that local auth mounts count towards clients but not as non-entity tokens. Prior to Vault 1.9, local auth mounts counted towards non-entity tokens. Refer to the [What is a Client?](docs/concepts/client-count) documentation to learn more.+- Changed the local auth mount computation logic such that local auth mounts count towards clients but not as non-entity tokens. Prior to Vault 1.9, local auth mounts counted towards non-entity tokens. Refer to the [What is a Client?](/docs/concepts/client-count) documentation to learn more.- Added ability to display clients per namespace (top 10, descending order) in the UI and export data for all namespaces. Prior to Vault 1.9, you could not view view the split of clients per namespace on the UI, nor could you export this data via the UI.- Added ability to display clients earlier than a month (within ten minutes of enabling the feature) in the UI. Prior to Vault 1.9, after enabling the counting of clients, you had to wait for a month to view the client aggregates in the UI.- Changed functionality to disallow creating two aliases from the same auth mount under a single entity. For more information, refer to the question [Starting in Vault 1.9, Vault does not allow creating two aliases from the same auth mount under a single entity. What changed and how does this impact client counting?](#q-starting-in-vault-1-9-vault-does-not-allow-creating-two-aliases-from-the-same-auth-mount-under-a-single-entity-what-changed-and-how-does-this-impact-client-counting)@@ -257,7 +257,7 @@ However, creating a new token across a parent/child namespace boundary could res### Q: How does the Nomad Vault integration affect client counts?-The [Nomad Vault integration](https://www.nomadproject.io/docs/integrations/vault-integration#token-role-based-integration) uses [token roles](https://www.nomadproject.io/docs/integrations/vault-integration#vault-token-role-configuration). A single token role creates tokens for many Nomad jobs. If no [explicit identity aliases](/api-docs/auth/token#entity_alias) are provided (which is not currently supported in the integration), this would create a non-entity token for every running instance of a Nomad job.+The [Nomad Vault integration](https://www.nomadproject.io/docs/integrations/vault-integration#token-role-based-integration) uses [token roles](https://www.nomadproject.io/docs/integrations/vault-integration#vault-token-role-configuration#vault-token-role-configuration). A single token role creates tokens for many Nomad jobs. If no [explicit identity aliases](/api-docs/auth/token#entity_alias) are provided (which is not currently supported in the integration), this would create a non-entity token for every running instance of a Nomad job.Prior to Vault 1.9, the Nomad Vault integration caused duplicate clients, resulting in an elevated client count. Post Vault 1.9, with the introduction of the deduplication logic, the number of clients created by the integration is reduced. For more information on improvements made to client count in Vault 1.9, refer to the question [Which version of Vault reflects the most accurate count of clients with Vault?](#q-which-vault-version-reflects-the-most-accurate-client-counts).### Q: Starting in Vault 1.7, Vault does not allow creating two aliases from the same auth mount under a single entity. What changed and how does this impact client counting?
website/content/docs/concepts/tokens.mdx+12 −12
@@ -60,9 +60,9 @@ there are only three ways to create root tokens:1. The initial root token generated at `vault operator init` time -- this token has noexpiration-2. By using another root token; a root token with an expiration cannot create a+1. By using another root token; a root token with an expiration cannot create aroot token that never expires-3. By using `vault operator generate-root` ([example](/guides/operations/generate-root))+1. By using `vault operator generate-root` ([example](https://learn.hashicorp.com/tutorials/vault/generate-root))with the permission of a quorum of unseal key holdersRoot tokens are useful in development but should be extremely carefully guarded@@ -91,10 +91,10 @@ Often this behavior is not desired, so users with appropriate access can createtoken tree. These orphan tokens can be created:1. Via `write` access to the `auth/token/create-orphan` endpoint-2. By having `sudo` or `root` access to the `auth/token/create`+1. By having `sudo` or `root` access to the `auth/token/create`and setting the `no_parent` parameter to `true`-3. Via token store roles-4. By logging in with any other (non-`token`) auth method+1. Via token store roles+1. By logging in with any other (non-`token`) auth methodUsers with appropriate permissions can also use the `auth/token/revoke-orphan`endpoint, which revokes the given token but rather than revoke the rest of the@@ -108,9 +108,9 @@ accessor is a value that acts as a reference to a token and can only be used toperform limited actions:1. Look up a token's properties (not including the actual token ID)-2. Look up a token's capabilities on a path-3. Renew the token-4. Revoke the token+1. Look up a token's capabilities on a path+1. Renew the token+1. Revoke the tokenThe token _making the call_, _not_ the token associated with the accessor, musthave appropriate permissions for these functions.@@ -159,11 +159,11 @@ token's information is looked up. It is based on a combination of factors:1. The system max TTL, which is 32 days but can be changed in Vault'sconfiguration file.-2. The max TTL set on a mount using [mount+1. The max TTL set on a mount using [mounttuning](/api-docs/system/mounts). This valueis allowed to override the system max TTL -- it can be longer or shorter,and if set this value will be respected.-3. A value suggested by the auth method that issued the token. This+1. A value suggested by the auth method that issued the token. Thismight be configured on a per-role, per-group, or per-user basis. This valueis allowed to be less than the mount max TTL (or, if not set, the system maxTTL), but it is not allowed to be longer.@@ -194,8 +194,8 @@ can be created in a few ways:1. By having `sudo` capability or a `root` token with the `auth/token/create`endpoint-2. By using token store roles-3. By using an auth method that supports issuing these, such as+1. By using token store roles+1. By using an auth method that supports issuing these, such asAppRoleAt issue time, the TTL of a periodic token will be equal to the configured
website/content/docs/partnerships.mdx+21 −11
@@ -16,9 +16,11 @@ This program is intended to be largely a self-service process with links and guiVault is an Identity-based security solution that leverages trusted sources of identity to keep secrets and application data secured with one centralized, audited workflow for tightly controlling access to secrets across applications, systems, and infrastructure while encrypting data both in flight and at rest. For a full description of the current features please refer to the Vault [website](/).-Vault has a secure [plugin](/docs/plugins) architecture. Vault’s plugins are completely separate, standalone applications that Vault executes and communicates with over RPC. This means the plugin process does not share the same memory space as Vault and therefore can only access the interfaces and arguments given to it.+There are two main types of integrations with Vault. The first is Runtime Integrations which use Vault as part of a workflow. Many partners have integrations that use existing Vault deployments to retrieve various types of secrets for use in a partner’s application or platform. The use cases can range from Vault storing and providing secrets, issuing or managing PKI certificates or acting as an external key management system.-Vault plugins can be built-in and bundled with the Vault binary, or be external that has to be manually mounted. Built-in plugins are developed by HashiCorp, while external plugins can be developed by HashiCorp, technology partners, or the community. There is a curated collection of all plugins, both built-in and external, located on the [Plugin Portal](/docs/plugin-portal).+The second type is where a partner develops a custom plugin. Vault has a secure [plugin](/docs/plugins) architecture. Vault’s plugins are completely separate, standalone applications that Vault executes and communicates with over RPC.++Plugins can be broken into two categories, Secrets Engines and Auth Methods. They can be built-in and bundled with the Vault binary, or be external that has to be manually registered. Built-in plugins are developed by HashiCorp, while external plugins can be developed by HashiCorp, technology partners, or the community. There is a curated collection of all plugins, both built-in and external, located on the [Plugin Portal](/docs/plugins/plugin-portal).The diagram below depicts the key Vault integration categories and types.@@ -26,21 +28,29 @@ The diagram below depicts the key Vault integration categories and types.Main Vault categories for partners to integrate with include:-**Authentication Methods**: Authentication (or Auth) methods are plugin components in Vault that perform authentication and are responsible for assigning identity along with a set of policies to a user. Vault supports multiple auth methods/identity models to better support your business use case. You can find more information about Vault Auth Methods [here](/docs/auth/).+**Authentication Methods**: Authentication (or Auth) methods are plugin components in Vault that perform authentication and are responsible for assigning identity along with a set of policies to a user. Vault supports multiple auth methods/identity models and partners can build a plugin that allows Vault to authenticate against the partners’ platform. You can find more information about Vault Auth Methods [here](/docs/auth/).-**Runtime Integrations**: These types of integrations include integrations developed by partners that work with existing customer deployments of Vault and the partner’s solution.+**Runtime Integrations**: These types of integrations include integrations developed by partners that work with existing deployments of Vault and the partner’s product as part of the customer's identity/security workflow.-HSM (Hardware Security Module) are specific types of runtime integrations and provide an added level of security and compliance. The HSM communicates with Vault using the PKCS#11 protocol, thereby resulting in the integration to primarily involve verification of the operation of the functionality. You can find more information about Vault's HSM support [here](/docs/enterprise/hsm).+Oftentimes these integrations involve modifying a partner’s product to become “Vault aware”. There are two main components that need to be considered for this type of integration:+1. How is the application going to authenticate itself to Vault?+1. Support of Namespaces--> **Note:** Integrations related Vault’s [storage](/docs/concepts/storage) backend, [auto auth](/docs/agent/autoauth), and [auto unseal](/docs/concepts/seal#auto-unseal) functionality are not encouraged. Please reach out to [technologypartners@hashicorp.com](mailto:technologypartners@hashicorp.com) for any questions related to this.+There are many ways for an application to authenticate itself to Vault (see [Auth Methods](/docs/auth/)), but we recommend partners use one of the following methods: [AppRole](/docs/auth/approle), [JWT / OIDC](/docs/auth/jwt), [TLS Certificates](/docs/auth/cert) or [Username / Password](/docs/auth/userpass). For an integration to be verified as production ready by HashiCorp, there needs to be at least one other Auth method supported besides [Token](/docs/auth/token). Token is not recommended for use in production since it involves creating a manual long lived token (which is against best practice and poses a security risk). Using one of the above mentioned auth methods automatically creates short lived tokens and eliminates the need to manually generate a new token on a regular basis.++As the number of customers using Vault Enterprise increases, partners are encouraged to support [Namespaces](https://learn.hashicorp.com/tutorials/vault/namespaces). By supporting Namespaces, there is an additional benefit that an integration should be able to work with HCP Vault.++HSM (Hardware Security Module) are specific types of runtime integrations and can be configured to work with new or existing Vault deployments. They provide an added level of security and compliance. The HSM communicates with Vault using the PKCS#11 protocol thereby resulting in the integration to primarily involve verification of the operation of the functionality. You can find more information about Vault’s HSM support [here](/docs/enterprise/hsm). A list of HSMs that have been verified to work with Vault is shown in our [interoperability matrix](/docs/interoperability-matrix).**Audit/Monitoring & Compliance**: Audit/Monitoring and Compliance are components in Vault that keep a detailed log of all requests and responses to Vault. Because every operation with Vault is an API request/response, the audit log contains every authenticated interaction with Vault, including errors. Vault supports multiple audit devices to support your business use case. You can find more information about Vault Audit Devices [here](/docs/audit/).-**Secrets Engines**: Secrets engines are plugin components which store, generate, or encrypt data. Secrets engines are provided with some set of data that perform actions on that data, and then return a result. Some secrets engines store and read data, like encrypted in-memory data structure, and secrets engines connect to other services. Examples of secrets engines include identity modules of Cloud providers like AWS, Azure IAM models, Cloud (LDAP), database or key management. You can find more information about Vault secrets engines [here](/docs/secrets/).+**Secrets Engines**: Secrets engines are plugin components which store, generate, or encrypt data. Secrets engines are provided with some set of data, that take some action on that data, and then return a result. Some secrets engines store and read data, like encrypted in-memory data structure, other secrets engines connect to other services. Examples of Secrets Engines include identity modules of Cloud providers like AWS, Azure IAM models, Cloud (LDAP), database or certificate management. You can find more information about Vault Secrets Engines [here](/docs/secrets/).++-> **Note:** Integrations related Vault’s [storage](/docs/concepts/storage) backend, [auto auth](/docs/agent/autoauth), and [auto unseal](/docs/concepts/seal#auto-unseal) functionality are not encouraged. Please reach out to [technologypartners@hashicorp.com](mailto:technologypartners@hashicorp.com) for any questions related to this.### HCP Vault-HCP Vault is a managed version of Vault which is operated by HashiCorp to allow customers to quickly get up and running. HCP Vault uses the same binary as self-managed Vault, and offers a consistent user experience. You can use the same Vault clients to communicate with HCP Vault as you use to communicate with Vault. Most runtime integrations can be verified with HCP Vault.+HCP Vault is a managed version of Vault which is operated by HashiCorp to allow customers to quickly get up and running. HCP Vault uses the same binary as self-managed Vault Enterprise, and offers a consistent user experience. You can use the same Vault clients to communicate with HCP Vault as you use to communicate with Vault. Most runtime integrations can be verified with HCP Vault.Sign up for HCP Vault [here](https://portal.cloud.hashicorp.com/) and check out [this](https://learn.hashicorp.com/collections/vault/cloud) learn guide for quickly getting started.@@ -150,9 +160,9 @@ Once the integration has been verified, the partner is requested to sign the HasAt this stage, it is expected that the integration is fully complete, the necessary documentation has been written, and HashiCorp has reviewed the integration.-For Auth or Secret Engine plugins specifically, once the plugin has been validated by HashiCorp, it is recommended the plugin be hosted on Github so it can more easily be downloaded and installed within Vault. We also encourage partners to list their plugin on the [Vault Plugin Portal](/docs/plugin-portal). This is in addition to the listing of the plugin on the technology partners’ dedicated HashiCorp partner page. To have the plugin listed on the portal page, please do a pull request via the “edit in GitHub” link on the bottom of the page and add the plugin in the partner section.+For Auth or Secret Engine plugins specifically, once the plugin has been verified by HashiCorp, it is recommended the plugin be hosted on Github so it can more easily be downloaded and installed within Vault. We also encourage partners to list their plugin on the [Vault Plugin Portal](/docs/plugins/plugin-portal). This is in addition to the listing of the plugin on the technology partners’ dedicated HashiCorp partner page. To have the plugin listed on the portal page, please do a pull request via the “edit in GitHub” link on the bottom of the page and add the plugin in the partner section.-For HCP Vault validations, the partner will be issued an HCP Vault Verified badge and will have this displayed on their partner page.+For HCP Vault verifications, the partner will be issued an HCP Vault Verified badge and will have this displayed on their partner page.### 6. Support@@ -174,4 +184,4 @@ Below is a checklist of steps that should be followed during the Vault integrati## Contact Us-For any questions or feedback, please contact us at: [technologypartners@hashicorp.com](mailto:technologypartners@hashicorp.com)+For any questions or feedback, please contact us at: [technologypartners@hashicorp.com](mailto:technologypartners@hashicorp.com)
vault/mount.go+2 −2
@@ -679,7 +679,7 @@ func (c *Core) mountInternal(ctx context.Context, entry *MountEntry, updateStora}if c.logger.IsInfo() {-c.logger.Info("successful mount", "namespace", entry.Namespace().Path, "path", entry.Path, "type", entry.Type)+c.logger.Info("successful mount", "namespace", entry.Namespace().Path, "path", entry.Path, "type", entry.Type, "version", entry.Version)}return nil}@@ -1495,7 +1495,7 @@ func (c *Core) setupMounts(ctx context.Context) error {}if c.logger.IsInfo() {-c.logger.Info("successfully mounted backend", "type", entry.Type, "path", entry.Path)+c.logger.Info("successfully mounted backend", "type", entry.Type, "version", entry.Version, "path", entry.Path)}// Ensure the path is tainted if set in the mount table
vault/plugin_reload.go+3 −3
@@ -62,7 +62,7 @@ func (c *Core) reloadMatchingPluginMounts(ctx context.Context, mounts []string)errors = multierror.Append(errors, fmt.Errorf("cannot reload plugin on %q: %w", mount, err))continue}-c.logger.Info("successfully reloaded plugin", "plugin", entry.Accessor, "path", entry.Path)+c.logger.Info("successfully reloaded plugin", "plugin", entry.Accessor, "path", entry.Path, "version", entry.Version)}return errors}@@ -92,7 +92,7 @@ func (c *Core) reloadMatchingPlugin(ctx context.Context, pluginName string) erroif err != nil {return err}-c.logger.Info("successfully reloaded plugin", "plugin", pluginName, "path", entry.Path)+c.logger.Info("successfully reloaded plugin", "plugin", pluginName, "path", entry.Path, "version", entry.Version)}}@@ -108,7 +108,7 @@ func (c *Core) reloadMatchingPlugin(ctx context.Context, pluginName string) erroif err != nil {return err}-c.logger.Info("successfully reloaded plugin", "plugin", entry.Accessor, "path", entry.Path)+c.logger.Info("successfully reloaded plugin", "plugin", entry.Accessor, "path", entry.Path, "version", entry.Version)}}<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>into release/1.12.x (#17569)website/Makefile | 3 +-website/content/api-docs/auth/jwt.mdx | 2 +-website/content/api-docs/index.mdx | 2 +-website/content/api-docs/relatedtools.mdx | 3 +-website/content/api-docs/secret/azure.mdx | 2 +-website/content/api-docs/secret/cassandra.mdx | 6 +-website/content/api-docs/secret/consul.mdx | 4 +-.../api-docs/secret/databases/cassandra.mdx | 2 +-.../api-docs/secret/databases/couchbase.mdx | 2 +-.../api-docs/secret/databases/elasticdb.mdx | 2 +-.../api-docs/secret/databases/hanadb.mdx | 2 +-.../api-docs/secret/databases/influxdb.mdx | 2 +-.../api-docs/secret/databases/mongodb.mdx | 2 +-.../secret/databases/mongodbatlas.mdx | 2 +-.../api-docs/secret/databases/mssql.mdx | 2 +-.../api-docs/secret/databases/mysql-maria.mdx | 2 +-.../api-docs/secret/databases/oracle.mdx | 2 +-.../api-docs/secret/databases/postgresql.mdx | 2 +-.../api-docs/secret/databases/redshift.mdx | 2 +-.../api-docs/secret/databases/snowflake.mdx | 2 +-website/content/api-docs/secret/gcp.mdx | 2 +-.../api-docs/secret/identity/mfa/duo.mdx | 12 +-.../api-docs/secret/identity/mfa/index.mdx | 12 +-.../api-docs/secret/identity/mfa/okta.mdx | 10 +-.../api-docs/secret/identity/mfa/pingid.mdx | 10 +-.../api-docs/secret/identity/mfa/totp.mdx | 20 +--website/content/api-docs/secret/kv/index.mdx | 4 +-website/content/api-docs/secret/kv/kv-v2.mdx | 2 +-website/content/api-docs/secret/nomad.mdx | 2 +-website/content/api-docs/secret/terraform.mdx | 2 +-website/content/api-docs/secret/transit.mdx | 2 +-website/content/api-docs/system/mfa/index.mdx | 8 +-website/content/api-docs/system/mounts.mdx | 5 +-website/content/docs/audit/index.mdx | 2 +-website/content/docs/auth/azure.mdx | 2 +-website/content/docs/auth/jwt/index.mdx | 86 ++++++------.../docs/commands/operator/generate-root.mdx | 2 +-.../content/docs/commands/operator/rekey.mdx | 4 +-.../docs/concepts/client-count/faq.mdx | 4 +-website/content/docs/concepts/dev-server.mdx | 2 +-.../concepts/integrated-storage/autopilot.mdx | 2 -website/content/docs/concepts/policies.mdx | 38 +++---website/content/docs/concepts/storage.mdx | 4 +-website/content/docs/concepts/tokens.mdx | 24 ++--website/content/docs/configuration/index.mdx | 2 +-.../content/docs/configuration/sentinel.mdx | 2 +-.../service-registration/consul.mdx | 2 +-.../service-registration/index.mdx | 2 +-.../docs/configuration/storage/index.mdx | 2 +-.../content/docs/enterprise/license/faq.mdx | 2 +-website/content/docs/faq/ssct.mdx | 2 +-website/content/docs/index.mdx | 2 +-website/content/docs/internals/limits.mdx | 2 +-website/content/docs/internals/telemetry.mdx | 24 +++-website/content/docs/partnerships.mdx | 16 +--.../content/docs/platform/k8s/helm/index.mdx | 2 +-.../docs/platform/k8s/helm/terraform.mdx | 2 +-website/content/docs/release-notes/1.10.0.mdx | 2 +-website/content/docs/release-notes/1.9.0.mdx | 4 +-website/content/docs/secrets/consul.mdx | 2 +-.../docs/secrets/databases/elasticdb.mdx | 124 +++++++++---------.../content/docs/secrets/databases/index.mdx | 6 +-.../docs/secrets/databases/mysql-maria.mdx | 90 ++++++-------website/content/docs/secrets/nomad.mdx | 4 +-.../docs/secrets/pki/considerations.mdx | 2 +-website/content/docs/secrets/terraform.mdx | 6 +-website/content/docs/what-is-vault.mdx | 2 +-website/data/api-docs-nav-data.json | 41 ++++--website/data/docs-nav-data.json | 56 ++++++--website/scripts/website-build.sh | 4 +-website/scripts/website-start.sh | 4 +-71 files changed, 405 insertions(+), 313 deletions(-)
website/content/api-docs/secret/consul.mdx+2 −2
@@ -160,11 +160,11 @@ To create a client token with service identities attached:- `token_type` <sup>DEPRECATED (1.11)</sup> `(string: "client")` - Specifies the type of token to createwhen using this role. Valid values are `"client"` or `"management"`. If a `"management"`token, the `policy` parameter is not required. Defaults to `"client`". [Deprecated from Consul as of 1.4 and-removed as of Consul 1.11.](https://www.consul.io/api/acl/legacy)+removed as of Consul 1.11.](https://www.consul.io/api-docs/acl/legacy)- `policy` <sup>DEPRECATED (1.11)</sup> `(string: "")` – Specifies the base64-encoded ACL policy.This is required unless the `token_type` is `"management"`. [Deprecated from Consul as of 1.4 and-removed as of Consul 1.11.](https://www.consul.io/api/acl/legacy)+removed as of Consul 1.11.](https://www.consul.io/api-docs/acl/legacy)- `policies` <sup>DEPRECATED (1.11)</sup> `(list: <policy or policies>)` - Same as `consul_policies`.Deprecated in favor of using `consul_policies`.
website/content/api-docs/secret/kv/kv-v2.mdx+1 −1
@@ -95,7 +95,7 @@ This endpoint retrieves the secret at the specified location. The metadatafields `created_time`, `deletion_time`, `destroyed`, and `version` are versionspecific. The `custom_metadata` field is part of the secret's key metadata andis included in the response whether or not the calling token has `read` access to-the associated [metadata endpoint](/api/secret/kv/kv-v2#read-secret-metadata).+the associated [metadata endpoint](/api-docs/secret/kv/kv-v2#read-secret-metadata).| Method | Path || :----- | :------------------------------------------- |
website/content/docs/auth/jwt/index.mdx+46 −40
@@ -140,15 +140,20 @@ EOF```- Monitor Vault's log output. Important information about OIDC validation failures will be emitted.+- Ensure Redirect URIs are correct in Vault and on the provider. They need to match exactly. Check:http/https, 127.0.0.1/localhost, port numbers, whether trailing slashes are present.+- Start simple. The only claim configuration a role requires is `user_claim`. After authentication isknown to work, you can add additional claims bindings and metadata copying.+- `bound_audiences` is optional for OIDC roles and typically not required. OIDC providers will usethe client_id as the audience and OIDC validation expects this.+- Check your provider for what scopes are required in order to receive allof the information you need. The scopes "profile" and "groups" often need to berequested, and can be added by setting `oidc_scopes="profile,groups"` on the role.+- If you're seeing claim-related errors in logs, review the provider's docs very carefully to seehow they're naming and structuring their claims. Depending on the provider, you may be able toconstruct a simple `curl` implicit grant request to obtain a JWT that you can inspect. An example@@ -161,6 +166,7 @@ EOFbe helpful when debugging provider setup and verifying that the received claims are what you expect.Since claims data is logged verbatim and may contain sensitive information, this option should not beused in production.+- Azure requires some additional configuration when a user is a member of morethan 200 groups, described in [Azure-specific handlingconfiguration](/docs/auth/jwt/oidc-providers/azuread#optional-azure-specific-configuration)@@ -231,46 +237,46 @@ Auth methods must be configured in advance before users or machines canauthenticate. These steps are usually completed by an operator or configurationmanagement tool.-1. Enable the JWT auth method. Either the "jwt" or "oidc" name may be used. The-backend will be mounted at the chosen name.--```text-$ vault auth enable jwt-or-$ vault auth enable oidc-```--1. Use the `/config` endpoint to configure Vault. To support JWT roles, either local keys, a JWKS URL, or an OIDC-Discovery URL must be present. For OIDC roles, OIDC Discovery URL, OIDC Client ID and OIDC Client Secret are required. For the-list of available configuration options, please see the [API documentation](/api-docs/auth/jwt).--```text-$ vault write auth/jwt/config \-oidc_discovery_url="https://myco.auth0.com/" \-oidc_client_id="m5i8bj3iofytj" \-oidc_client_secret="f4ubv72nfiu23hnsj" \-default_role="demo"-```--1. Create a named role:--```text-vault write auth/jwt/role/demo \-allowed_redirect_uris="http://localhost:8250/oidc/callback" \-bound_subject="r3qX9DljwFIWhsiqwFiu38209F10atW6@clients" \-bound_audiences="https://vault.plugin.auth.jwt.test" \-user_claim="https://vault/user" \-groups_claim="https://vault/groups" \-policies=webapps \-ttl=1h-```--This role authorizes JWTs with the given subject and audience claims, gives-it the `webapps` policy, and uses the given user/groups claims to set up-Identity aliases.--For the complete list of configuration options, please see the API-documentation.+1. Enable the JWT auth method. Either the "jwt" or "oidc" name may be used. The+backend will be mounted at the chosen name.++```text+$ vault auth enable jwt+or+$ vault auth enable oidc+```++1. Use the `/config` endpoint to configure Vault. To support JWT roles, either local keys, a JWKS URL, or an OIDC+Discovery URL must be present. For OIDC roles, OIDC Discovery URL, OIDC Client ID and OIDC Client Secret are required. For the+list of available configuration options, please see the [API documentation](/api-docs/auth/jwt).++```text+$ vault write auth/jwt/config \+oidc_discovery_url="https://myco.auth0.com/" \+oidc_client_id="m5i8bj3iofytj" \+oidc_client_secret="f4ubv72nfiu23hnsj" \+default_role="demo"+```++1. Create a named role:++```text+vault write auth/jwt/role/demo \+allowed_redirect_uris="http://localhost:8250/oidc/callback" \+bound_subject="r3qX9DljwFIWhsiqwFiu38209F10atW6@clients" \+bound_audiences="https://vault.plugin.auth.jwt.test" \+user_claim="https://vault/user" \+groups_claim="https://vault/groups" \+policies=webapps \+ttl=1h+```++This role authorizes JWTs with the given subject and audience claims, gives+it the `webapps` policy, and uses the given user/groups claims to set up+Identity aliases.++For the complete list of configuration options, please see the API+documentation.### Bound Claims
builtin/logical/pki/path_tidy.go+0 −11
@@ -13,7 +13,6 @@ import ("github.com/hashicorp/go-hclog""github.com/hashicorp/vault/sdk/framework"-"github.com/hashicorp/vault/sdk/helper/consts""github.com/hashicorp/vault/sdk/logical")@@ -442,10 +441,6 @@ func (b *backend) doTidyRevocationStore(ctx context.Context, req *logical.Reques}func (b *backend) pathTidyCancelWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {-if b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary) && !b.System().LocalMount() {-return nil, logical.ErrReadOnly-}-if atomic.LoadUint32(b.tidyCASGuard) == 0 {resp := &logical.Response{}resp.AddWarning("Tidy operation cannot be cancelled as none is currently running.")@@ -469,12 +464,6 @@ func (b *backend) pathTidyCancelWrite(ctx context.Context, req *logical.Request,}func (b *backend) pathTidyStatusRead(_ context.Context, _ *logical.Request, _ *framework.FieldData) (*logical.Response, error) {-// If this node is a performance secondary return an ErrReadOnly so that the request gets forwarded,-// but only if the PKI backend is not a local mount.-if b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary) && !b.System().LocalMount() {-return nil, logical.ErrReadOnly-}-b.tidyStatusLock.RLock()defer b.tidyStatusLock.RUnlock()
Release delta 1.13.0 → 1.13.1 (contains the fix)
builtin/logical/pki/backend_test.go+396 −0
@@ -6399,6 +6399,433 @@ func TestStandby_Operations(t *testing.T) {require.NotNil(t, resp, "got nil response from revoke request")}+type pathAuthCheckerFunc func(t *testing.T, client *api.Client, path string, token string)++func isPermDenied(err error) bool {+return err != nil && strings.Contains(err.Error(), "permission denied")+}++func isUnsupportedPathOperation(err error) bool {+return err != nil && (strings.Contains(err.Error(), "unsupported path") || strings.Contains(err.Error(), "unsupported operation"))+}++func isDeniedOp(err error) bool {+return isPermDenied(err) || isUnsupportedPathOperation(err)+}++func pathShouldBeAuthed(t *testing.T, client *api.Client, path string, token string) {+client.SetToken("")+resp, err := client.Logical().ReadWithContext(ctx, path)+if err == nil || !isPermDenied(err) {+t.Fatalf("expected failure to read %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().ListWithContext(ctx, path)+if err == nil || !isPermDenied(err) {+t.Fatalf("expected failure to list %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().WriteWithContext(ctx, path, map[string]interface{}{})+if err == nil || !isPermDenied(err) {+t.Fatalf("expected failure to write %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().DeleteWithContext(ctx, path)+if err == nil || !isPermDenied(err) {+t.Fatalf("expected failure to delete %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().JSONMergePatch(ctx, path, map[string]interface{}{})+if err == nil || !isPermDenied(err) {+t.Fatalf("expected failure to patch %v while unauthed: %v / %v", path, err, resp)+}+}++func pathShouldBeUnauthedReadList(t *testing.T, client *api.Client, path string, token string) {+// Should be able to read both with and without a token.+client.SetToken("")+resp, err := client.Logical().ReadWithContext(ctx, path)+if err != nil && isPermDenied(err) {+// Read will sometimes return permission denied, when the handler+// does not support the given operation. Retry with the token.+client.SetToken(token)+resp2, err2 := client.Logical().ReadWithContext(ctx, path)+if err2 != nil && !isUnsupportedPathOperation(err2) {+t.Fatalf("unexpected failure to read %v while unauthed: %v / %v\nWhile authed: %v / %v", path, err, resp, err2, resp2)+}+client.SetToken("")+}+resp, err = client.Logical().ListWithContext(ctx, path)+if err != nil && isPermDenied(err) {+// List will sometimes return permission denied, when the handler+// does not support the given operation. Retry with the token.+client.SetToken(token)+resp2, err2 := client.Logical().ListWithContext(ctx, path)+if err2 != nil && !isUnsupportedPathOperation(err2) {+t.Fatalf("unexpected failure to list %v while unauthed: %v / %v\nWhile authed: %v / %v", path, err, resp, err2, resp2)+}+client.SetToken("")+}++// These should all be denied.+resp, err = client.Logical().WriteWithContext(ctx, path, map[string]interface{}{})+if err == nil || !isDeniedOp(err) {+if !strings.Contains(path, "ocsp") || !strings.Contains(err.Error(), "Code: 40") {+t.Fatalf("unexpected failure during write on read-only path %v while unauthed: %v / %v", path, err, resp)+}+}+resp, err = client.Logical().DeleteWithContext(ctx, path)+if err == nil || !isDeniedOp(err) {+t.Fatalf("unexpected failure during delete on read-only path %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().JSONMergePatch(ctx, path, map[string]interface{}{})+if err == nil || !isDeniedOp(err) {+t.Fatalf("unexpected failure during patch on read-only path %v while unauthed: %v / %v", path, err, resp)+}++// Retrying with token should allow read/list, but not modification still.+client.SetToken(token)+resp, err = client.Logical().ReadWithContext(ctx, path)+if err != nil && isPermDenied(err) {+t.Fatalf("unexpected failure to read %v while authed: %v / %v", path, err, resp)+}+resp, err = client.Logical().ListWithContext(ctx, path)+if err != nil && isPermDenied(err) {+t.Fatalf("unexpected failure to list %v while authed: %v / %v", path, err, resp)+}++// Should all be denied.+resp, err = client.Logical().WriteWithContext(ctx, path, map[string]interface{}{})+if err == nil || !isDeniedOp(err) {+if !strings.Contains(path, "ocsp") || !strings.Contains(err.Error(), "Code: 40") {+t.Fatalf("unexpected failure during write on read-only path %v while authed: %v / %v", path, err, resp)+}+}+resp, err = client.Logical().DeleteWithContext(ctx, path)+if err == nil || !isDeniedOp(err) {+t.Fatalf("unexpected failure during delete on read-only path %v while authed: %v / %v", path, err, resp)+}+resp, err = client.Logical().JSONMergePatch(ctx, path, map[string]interface{}{})+if err == nil || !isDeniedOp(err) {+t.Fatalf("unexpected failure during patch on read-only path %v while authed: %v / %v", path, err, resp)+}+}++func pathShouldBeUnauthedWriteOnly(t *testing.T, client *api.Client, path string, token string) {+client.SetToken("")+resp, err := client.Logical().WriteWithContext(ctx, path, map[string]interface{}{})+if err != nil && isPermDenied(err) {+t.Fatalf("unexpected failure to write %v while unauthed: %v / %v", path, err, resp)+}++// These should all be denied. However, on OSS, we might end up with+// a regular 404, which looks like err == resp == nil; hence we only+// fail when there's a non-nil response and/or a non-nil err.+resp, err = client.Logical().ReadWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during read on write-only path %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().ListWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during list on write-only path %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().DeleteWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during delete on write-only path %v while unauthed: %v / %v", path, err, resp)+}+resp, err = client.Logical().JSONMergePatch(ctx, path, map[string]interface{}{})+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during patch on write-only path %v while unauthed: %v / %v", path, err, resp)+}++// Retrying with token should allow writing, but nothing else.+client.SetToken(token)+resp, err = client.Logical().WriteWithContext(ctx, path, map[string]interface{}{})+if err != nil && isPermDenied(err) {+t.Fatalf("unexpected failure to write %v while unauthed: %v / %v", path, err, resp)+}++// These should all be denied.+resp, err = client.Logical().ReadWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during read on write-only path %v while authed: %v / %v", path, err, resp)+}+resp, err = client.Logical().ListWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+if resp != nil || err != nil {+t.Fatalf("unexpected failure during list on write-only path %v while authed: %v / %v", path, err, resp)+}+}+resp, err = client.Logical().DeleteWithContext(ctx, path)+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during delete on write-only path %v while authed: %v / %v", path, err, resp)+}+resp, err = client.Logical().JSONMergePatch(ctx, path, map[string]interface{}{})+if (err == nil && resp != nil) || (err != nil && !isDeniedOp(err)) {+t.Fatalf("unexpected failure during patch on write-only path %v while authed: %v / %v", path, err, resp)+}+}++type pathAuthChecker int++const (+shouldBeAuthed pathAuthChecker = iota+shouldBeUnauthedReadList+shouldBeUnauthedWriteOnly+)++var pathAuthChckerMap = map[pathAuthChecker]pathAuthCheckerFunc{+shouldBeAuthed: pathShouldBeAuthed,+shouldBeUnauthedReadList: pathShouldBeUnauthedReadList,+shouldBeUnauthedWriteOnly: pathShouldBeUnauthedWriteOnly,+}++func TestProperAuthing(t *testing.T) {+t.Parallel()+ctx := context.Background()+coreConfig := &vault.CoreConfig{+LogicalBackends: map[string]logical.Factory{+"pki": Factory,+},+}+cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{+HandlerFunc: vaulthttp.Handler,+})+cluster.Start()+defer cluster.Cleanup()+client := cluster.Cores[0].Client+token := client.Token()++// Mount PKI.+err := client.Sys().MountWithContext(ctx, "pki", &api.MountInput{+Type: "pki",+Config: api.MountConfigInput{+DefaultLeaseTTL: "16h",+MaxLeaseTTL: "60h",+},+})+if err != nil {+t.Fatal(err)+}++// Setup basic configuration.+_, err = client.Logical().WriteWithContext(ctx, "pki/root/generate/internal", map[string]interface{}{+"ttl": "40h",+"common_name": "myvault.com",+})+if err != nil {+t.Fatal(err)+}++_, err = client.Logical().WriteWithContext(ctx, "pki/roles/test", map[string]interface{}{+"allow_localhost": true,+})+if err != nil {+t.Fatal(err)+}++resp, err := client.Logical().WriteWithContext(ctx, "pki/issue/test", map[string]interface{}{+"common_name": "localhost",+})+if err != nil || resp == nil {+t.Fatal(err)+}+serial := resp.Data["serial_number"].(string)++paths := map[string]pathAuthChecker{+"ca_chain": shouldBeUnauthedReadList,+"cert/ca_chain": shouldBeUnauthedReadList,+"ca": shouldBeUnauthedReadList,+"ca/pem": shouldBeUnauthedReadList,+"cert/" + serial: shouldBeUnauthedReadList,+"cert/" + serial + "/raw": shouldBeUnauthedReadList,+"cert/" + serial + "/raw/pem": shouldBeUnauthedReadList,+"cert/crl": shouldBeUnauthedReadList,+"cert/crl/raw": shouldBeUnauthedReadList,+"cert/crl/raw/pem": shouldBeUnauthedReadList,+"cert/delta-crl": shouldBeUnauthedReadList,+"cert/delta-crl/raw": shouldBeUnauthedReadList,+"cert/delta-crl/raw/pem": shouldBeUnauthedReadList,+"cert/unified-crl": shouldBeUnauthedReadList,+"cert/unified-crl/raw": shouldBeUnauthedReadList,+"cert/unified-crl/raw/pem": shouldBeUnauthedReadList,+"cert/unified-delta-crl": shouldBeUnauthedReadList,+"cert/unified-delta-crl/raw": shouldBeUnauthedReadList,+"cert/unified-delta-crl/raw/pem": shouldBeUnauthedReadList,+"certs": shouldBeAuthed,+"certs/revoked": shouldBeAuthed,+"certs/revocation-queue": shouldBeAuthed,+"certs/unified-revoked": shouldBeAuthed,+"config/auto-tidy": shouldBeAuthed,+"config/ca": shouldBeAuthed,+"config/cluster": shouldBeAuthed,+"config/crl": shouldBeAuthed,+"config/issuers": shouldBeAuthed,+"config/keys": shouldBeAuthed,+"config/urls": shouldBeAuthed,+"crl": shouldBeUnauthedReadList,+"crl/pem": shouldBeUnauthedReadList,+"crl/delta": shouldBeUnauthedReadList,+"crl/delta/pem": shouldBeUnauthedReadList,+"crl/rotate": shouldBeAuthed,+"crl/rotate-delta": shouldBeAuthed,+"intermediate/cross-sign": shouldBeAuthed,+"intermediate/generate/exported": shouldBeAuthed,+"intermediate/generate/internal": shouldBeAuthed,+"intermediate/generate/existing": shouldBeAuthed,+"intermediate/generate/kms": shouldBeAuthed,+"intermediate/set-signed": shouldBeAuthed,+"issue/test": shouldBeAuthed,+"issuer/default": shouldBeAuthed,+"issuer/default/der": shouldBeUnauthedReadList,+"issuer/default/json": shouldBeUnauthedReadList,+"issuer/default/pem": shouldBeUnauthedReadList,+"issuer/default/crl": shouldBeUnauthedReadList,+"issuer/default/crl/pem": shouldBeUnauthedReadList,+"issuer/default/crl/der": shouldBeUnauthedReadList,+"issuer/default/crl/delta": shouldBeUnauthedReadList,+"issuer/default/crl/delta/der": shouldBeUnauthedReadList,+"issuer/default/crl/delta/pem": shouldBeUnauthedReadList,+"issuer/default/unified-crl": shouldBeUnauthedReadList,+"issuer/default/unified-crl/pem": shouldBeUnauthedReadList,+"issuer/default/unified-crl/der": shouldBeUnauthedReadList,+"issuer/default/unified-crl/delta": shouldBeUnauthedReadList,+"issuer/default/unified-crl/delta/der": shouldBeUnauthedReadList,+"issuer/default/unified-crl/delta/pem": shouldBeUnauthedReadList,+"issuer/default/issue/test": shouldBeAuthed,+"issuer/default/resign-crls": shouldBeAuthed,+"issuer/default/revoke": shouldBeAuthed,+"issuer/default/sign-intermediate": shouldBeAuthed,+"issuer/default/sign-revocation-list": shouldBeAuthed,+"issuer/default/sign-self-issued": shouldBeAuthed,+"issuer/default/sign-verbatim": shouldBeAuthed,+"issuer/default/sign-verbatim/test": shouldBeAuthed,+"issuer/default/sign/test": shouldBeAuthed,+"issuers": shouldBeUnauthedReadList,+"issuers/generate/intermediate/exported": shouldBeAuthed,+"issuers/generate/intermediate/internal": shouldBeAuthed,+"issuers/generate/intermediate/existing": shouldBeAuthed,+"issuers/generate/intermediate/kms": shouldBeAuthed,+"issuers/generate/root/exported": shouldBeAuthed,+"issuers/generate/root/internal": shouldBeAuthed,+"issuers/generate/root/existing": shouldBeAuthed,+"issuers/generate/root/kms": shouldBeAuthed,+"issuers/import/cert": shouldBeAuthed,+"issuers/import/bundle": shouldBeAuthed,+"key/default": shouldBeAuthed,+"keys": shouldBeAuthed,+"keys/generate/internal": shouldBeAuthed,+"keys/generate/exported": shouldBeAuthed,+"keys/generate/kms": shouldBeAuthed,+"keys/import": shouldBeAuthed,+"ocsp": shouldBeUnauthedWriteOnly,+"ocsp/dGVzdAo=": shouldBeUnauthedReadList,+"revoke": shouldBeAuthed,+"revoke-with-key": shouldBeAuthed,+"roles/test": shouldBeAuthed,+"roles": shouldBeAuthed,+"root": shouldBeAuthed,+"root/generate/exported": shouldBeAuthed,+"root/generate/internal": shouldBeAuthed,+"root/generate/existing": shouldBeAuthed,+"root/generate/kms": shouldBeAuthed,+"root/replace": shouldBeAuthed,+"root/rotate/internal": shouldBeAuthed,+"root/rotate/exported": shouldBeAuthed,+"root/rotate/existing": shouldBeAuthed,+"root/rotate/kms": shouldBeAuthed,+"root/sign-intermediate": shouldBeAuthed,+"root/sign-self-issued": shouldBeAuthed,+"sign-verbatim": shouldBeAuthed,+"sign-verbatim/test": shouldBeAuthed,+"sign/test": shouldBeAuthed,+"tidy": shouldBeAuthed,+"tidy-cancel": shouldBeAuthed,+"tidy-status": shouldBeAuthed,+"unified-crl": shouldBeUnauthedReadList,+"unified-crl/pem": shouldBeUnauthedReadList,+"unified-crl/delta": shouldBeUnauthedReadList,+"unified-crl/delta/pem": shouldBeUnauthedReadList,+"unified-ocsp": shouldBeUnauthedWriteOnly,+"unified-ocsp/dGVzdAo=": shouldBeUnauthedReadList,+}+for path, checkerType := range paths {+checker := pathAuthChckerMap[checkerType]+checker(t, client, "pki/"+path, token)+}++client.SetToken(token)+openAPIResp, err := client.Logical().ReadWithContext(ctx, "sys/internal/specs/openapi")+if err != nil {+t.Fatalf("failed to get openapi data: %v", err)+}++validatedPath := false+for openapi_path, raw_data := range openAPIResp.Data["paths"].(map[string]interface{}) {+if !strings.HasPrefix(openapi_path, "/pki/") {+t.Logf("Skipping path: %v", openapi_path)+continue+}++t.Logf("Validating path: %v", openapi_path)+validatedPath = true+// Substitute values in from our testing map.+raw_path := openapi_path[5:]+if strings.Contains(raw_path, "roles/") && strings.Contains(raw_path, "{name}") {+raw_path = strings.ReplaceAll(raw_path, "{name}", "test")+}+if strings.Contains(raw_path, "{role}") {+raw_path = strings.ReplaceAll(raw_path, "{role}", "test")+}+if strings.Contains(raw_path, "ocsp/") && strings.Contains(raw_path, "{req}") {+raw_path = strings.ReplaceAll(raw_path, "{req}", "dGVzdAo=")+}+if strings.Contains(raw_path, "{issuer_ref}") {+raw_path = strings.ReplaceAll(raw_path, "{issuer_ref}", "default")+}+if strings.Contains(raw_path, "{key_ref}") {+raw_path = strings.ReplaceAll(raw_path, "{key_ref}", "default")+}+if strings.Contains(raw_path, "{exported}") {+raw_path = strings.ReplaceAll(raw_path, "{exported}", "internal")+}+if strings.Contains(raw_path, "{serial}") {+raw_path = strings.ReplaceAll(raw_path, "{serial}", serial)+}++handler, present := paths[raw_path]+if !present {+t.Fatalf("OpenAPI reports PKI mount contains %v->%v but was not tested to be authed or authed.", openapi_path, raw_path)+}++openapi_data := raw_data.(map[string]interface{})… diff truncated
http/sys_mount_test.go+66 −0
@@ -416,6 +416,72 @@ func TestSysMount_put(t *testing.T) {// for more info.}+// TestSysRemountSpacesFrom ensure we succeed in a remount where the 'from' mount has spaces in the name+func TestSysRemountSpacesFrom(t *testing.T) {+core, _, token := vault.TestCoreUnsealed(t)+ln, addr := TestServer(t, core)+defer ln.Close()+TestServerAuth(t, addr, token)++resp := testHttpPost(t, token, addr+"/v1/sys/mounts/foo%20bar", map[string]interface{}{+"type": "kv",+"description": "foo",+})+testResponseStatus(t, resp, 204)++resp = testHttpPost(t, token, addr+"/v1/sys/remount", map[string]interface{}{+"from": "foo bar",+"to": "baz",+})+testResponseStatus(t, resp, 200)+}++// TestSysRemountSpacesTo ensure we succeed in a remount where the 'to' mount has spaces in the name+func TestSysRemountSpacesTo(t *testing.T) {+core, _, token := vault.TestCoreUnsealed(t)+ln, addr := TestServer(t, core)+defer ln.Close()+TestServerAuth(t, addr, token)++resp := testHttpPost(t, token, addr+"/v1/sys/mounts/foo%20bar", map[string]interface{}{+"type": "kv",+"description": "foo",+})+testResponseStatus(t, resp, 204)++resp = testHttpPost(t, token, addr+"/v1/sys/remount", map[string]interface{}{+"from": "foo bar",+"to": "bar baz",+})+testResponseStatus(t, resp, 200)+}++// TestSysRemountTrailingSpaces ensures we fail on trailing spaces+func TestSysRemountTrailingSpaces(t *testing.T) {+core, _, token := vault.TestCoreUnsealed(t)+ln, addr := TestServer(t, core)+defer ln.Close()+TestServerAuth(t, addr, token)++resp := testHttpPost(t, token, addr+"/v1/sys/mounts/foo%20bar", map[string]interface{}{+"type": "kv",+"description": "foo",+})+testResponseStatus(t, resp, 204)++resp = testHttpPost(t, token, addr+"/v1/sys/remount", map[string]interface{}{+"from": "foo bar",+"to": " baz ",+})+testResponseStatus(t, resp, 400)++resp = testHttpPost(t, token, addr+"/v1/sys/remount", map[string]interface{}{+"from": " foo bar ",+"to": "baz",+})+testResponseStatus(t, resp, 400)+}+func TestSysRemount(t *testing.T) {core, _, token := vault.TestCoreUnsealed(t)ln, addr := TestServer(t, core)
builtin/logical/pki/path_fetch_issuers.go+27 −2
@@ -75,11 +75,16 @@ their identifier and their name (if set).)func pathGetIssuer(b *backend) *framework.Path {-pattern := "issuer/" + framework.GenericNameRegex(issuerRefParam) + "(/der|/pem|/json)?"+pattern := "issuer/" + framework.GenericNameRegex(issuerRefParam) + "$"+return buildPathIssuer(b, pattern)+}++func pathGetUnauthedIssuer(b *backend) *framework.Path {+pattern := "issuer/" + framework.GenericNameRegex(issuerRefParam) + "/(json|der|pem)$"return buildPathGetIssuer(b, pattern)}-func buildPathGetIssuer(b *backend, pattern string) *framework.Path {+func buildPathIssuer(b *backend, pattern string) *framework.Path {fields := map[string]*framework.FieldSchema{}fields = addIssuerRefNameFields(fields)@@ -180,6 +185,26 @@ to be set on all PR secondary clusters.`,}}+func buildPathGetIssuer(b *backend, pattern string) *framework.Path {+fields := map[string]*framework.FieldSchema{}+fields = addIssuerRefField(fields)++return &framework.Path{+// Returns a JSON entry.+Pattern: pattern,+Fields: fields,++Operations: map[logical.Operation]framework.OperationHandler{+logical.ReadOperation: &framework.PathOperation{+Callback: b.pathGetIssuer,+},+},++HelpSynopsis: pathGetIssuerHelpSyn,+HelpDescription: pathGetIssuerHelpDesc,+}+}+func (b *backend) pathGetIssuer(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {// Handle raw issuers first.if strings.HasSuffix(req.Path, "/der") || strings.HasSuffix(req.Path, "/pem") || strings.HasSuffix(req.Path, "/json") {<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>85c3eab989de0c90d82b0cb39cabb79fb3911943 (#19716)changelog/19703.txt | 3 ++.../cluster/secrets/backend/metadata.hbs | 2 +-.../secrets/backend/kv/breadcrumbs-test.js | 29 +++++++++++++++++++3 files changed, 33 insertions(+), 1 deletion(-)create mode 100644 changelog/19703.txtcreate mode 100644 ui/tests/acceptance/secrets/backend/kv/breadcrumbs-test.js
website/content/docs/upgrading/upgrade-to-1.13.x.mdx+47 −0
@@ -29,6 +29,53 @@ The AliCloud auth plugin will now require the `role` parameter on login. Thishas always been documented as a required field but the requirement will now beenforced.+### Mounts associated with removed builtin plugins will result in core shutdown on upgrade++As of 1.13.0 Standalone (logical) DB Engines and the AppId Auth Method have been+marked with the `Removed` status. Any attempt to unseal Vault with+mounts backed by one of these builtin plugins will result in an immediate+shutdown of the Vault core.++-> **NOTE** In the event that an external plugin with the same name and type as+a deprecated builtin is deregistered, any subsequent unseal will continue to+unseal with an unusable auth backend, and a corresponding ERROR log.++```shell-session+$ vault plugin register -sha256=c805cf3b69f704dfcd5176ef1c7599f88adbfd7374e9c76da7f24a32a97abfe1 auth app-id+Success! Registered plugin: app-id+$ vault auth enable -plugin-name=app-id plugin+Success! Enabled app-id auth method at: app-id/+$ vault auth list -detailed | grep "app-id"+app-id/ app-id auth_app-id_3a8f2e24 system system default-service replicated false false map[] n/a 0018263c-0d64-7a70-fd5c-50e05c5f5dc3 n/a n/a c805cf3b69f704dfcd5176ef1c7599f88adbfd7374e9c76da7f24a32a97abfe1 n/a+$ vault plugin deregister auth app-id+Success! Deregistered plugin (if it was registered): app-id+$ vault plugin list -detailed | grep "app-id"+app-id auth v1.13.0+builtin.vault removed+$ curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST http://127.0.0.2:8200/v1/sys/seal+$ vault operator unseal <key1>+...+$ vault operator unseal <key2>+...+$ vault operator unseal <key3>+...+$ grep "app-id" /path/to/vault.log+[ERROR] core: skipping deprecated auth entry: name=app-id path=app-id/ error="mount entry associated with removed builtin"+[ERROR] core: skipping initialization for nil auth backend: path=app-id/ type=app-id version="v1.13.0+builtin.vault"+```++The remediation for affected mounts is to downgrade to the previously-used version of Vault+environment variable and replace any `Removed` feature with the+[preferred alternative+feature](/vault/docs/deprecation/faq#q-what-should-i-do-if-i-use-mount-filters-appid-or-any-of-the-standalone-db-engines).++For more information on the phases of deprecation, see the [Deprecation Notices+FAQ](/vault/docs/deprecation/faq#q-what-are-the-phases-of-deprecation).++#### Impacted Versions++Affects upgrading from any version of Vault to 1.13.x. All other upgrade paths+are unaffected.+## Known Issues@include 'tokenization-rotation-persistence.mdx'<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>b48e826d261e4f6166f4f5e0d112851b582a149f (#19590)changelog/19585.txt | 3 ++http/sys_mount_test.go | 66 ++++++++++++++++++++++++++++++++++++vault/logical_system.go | 8 ++---vault/logical_system_test.go | 16 +++++----4 files changed, 83 insertions(+), 10 deletions(-)create mode 100644 changelog/19585.txt
website/content/api-docs/secret/identity/entity-alias.mdx+3 −3
@@ -135,14 +135,14 @@ This endpoint is used to update an existing entity alias.- `id` `(string: <required>)` – Identifier of the entity alias.-- `name` `(string: <required>)` - Name of the alias. Name should be the identifier+- `name` `(string: "")` - Name of the alias. Name should be the identifierof the client in the authentication source. For example, if the alias belongsto userpass backend, the name should be a valid username within userpassbackend. If alias belongs to GitHub, it should be the GitHub username.-- `canonical_id` `(string: <required>)` - Entity ID to which this alias belongs to.+- `canonical_id` `(string: "")` - Entity ID to which this alias belongs to.-- `mount_accessor` `(string: <required>)` - Accessor of the mount to which the+- `mount_accessor` `(string: "")` - Accessor of the mount to which thealias should belong to.- `custom_metadata` `(map<string|string>: <optional>)` - A map of arbitrary string to string valued<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>3e4262f57167444a41ddb0e2325c9e0d5a4d3700 (#19455)website/content/docs/secrets/ldap.mdx | 2 ++1 file changed, 2 insertions(+)
vault/logical_system_test.go+10 −6
@@ -1026,34 +1026,38 @@ func TestSystemBackend_remount_nonPrintable(t *testing.T) {}}-func TestSystemBackend_remount_spacesInFromPath(t *testing.T) {+// TestSystemBackend_remount_trailingSpacesInFromPath ensures we error when+// there are trailing spaces in the 'from' path during a remount.+func TestSystemBackend_remount_trailingSpacesInFromPath(t *testing.T) {b := testSystemBackend(t)req := logical.TestRequest(t, logical.UpdateOperation, "remount")-req.Data["from"] = " foo / "+req.Data["from"] = " foo/ "req.Data["to"] = "bar"req.Data["config"] = structs.Map(MountConfig{})resp, err := b.HandleRequest(namespace.RootContext(nil), req)if err != logical.ErrInvalidRequest {t.Fatalf("err: %v", err)}-if resp.Data["error"] != `'from' path cannot contain whitespace` {+if resp.Data["error"] != `'from' path cannot contain trailing whitespace` {t.Fatalf("bad: %v", resp)}}-func TestSystemBackend_remount_spacesInToPath(t *testing.T) {+// TestSystemBackend_remount_trailingSpacesInToPath ensures we error when+// there are trailing spaces in the 'to' path during a remount.+func TestSystemBackend_remount_trailingSpacesInToPath(t *testing.T) {b := testSystemBackend(t)req := logical.TestRequest(t, logical.UpdateOperation, "remount")req.Data["from"] = "foo"-req.Data["to"] = " bar / "+req.Data["to"] = " bar/ "req.Data["config"] = structs.Map(MountConfig{})resp, err := b.HandleRequest(namespace.RootContext(nil), req)if err != logical.ErrInvalidRequest {t.Fatalf("err: %v", err)}-if resp.Data["error"] != `'to' path cannot contain whitespace` {+if resp.Data["error"] != `'to' path cannot contain trailing whitespace` {t.Fatalf("bad: %v", resp)}}<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>f15715f6d01f68a30431b9c09d3a6f52157f47fb (#19610)changelog/19591.txt | 3 +++physical/mssql/mssql.go | 30 ++++++++++++++++++++----physical/mssql/mssql_test.go | 44 ++++++++++++++++++++++++++++++++++--3 files changed, 70 insertions(+), 7 deletions(-)create mode 100644 changelog/19591.txt
builtin/logical/pki/backend.go+7 −0
@@ -92,6 +92,12 @@ func Backend(conf *logical.BackendConfig) *backend {"issuer/+/crl/delta/der","issuer/+/crl/delta/pem","issuer/+/crl/delta",+"issuer/+/unified-crl/der",+"issuer/+/unified-crl/pem",+"issuer/+/unified-crl",+"issuer/+/unified-crl/delta/der",+"issuer/+/unified-crl/delta/pem",+"issuer/+/unified-crl/delta","issuer/+/pem","issuer/+/der","issuer/+/json",@@ -162,6 +168,7 @@ func Backend(conf *logical.BackendConfig) *backend {// Issuer APIspathListIssuers(&b),pathGetIssuer(&b),+pathGetUnauthedIssuer(&b),pathGetIssuerCRL(&b),pathImportIssuer(&b),pathIssuerIssue(&b),
ui/tests/acceptance/settings/configure-secret-backends/configure-ssh-secret-test.js+40 −0
@@ -0,0 +1,40 @@+import { click, settled } from '@ember/test-helpers';+import { module, test } from 'qunit';+import { setupApplicationTest } from 'ember-qunit';+import page from 'vault/tests/pages/settings/configure-secret-backends/pki/index';+import authPage from 'vault/tests/pages/auth';+import enablePage from 'vault/tests/pages/settings/mount-secret-backend';+import { create } from 'ember-cli-page-object';+import fm from 'vault/tests/pages/components/flash-message';+const flashMessage = create(fm);+const SELECTORS = {+generateSigningKey: '[data-test-ssh-input="generate-signing-key-checkbox"]',+saveConfig: '[data-test-ssh-input="configure-submit"]',+publicKey: '[data-test-ssh-input="public-key"]',+};+module('Acceptance | settings/configure/secrets/ssh', function (hooks) {+setupApplicationTest(hooks);++hooks.beforeEach(function () {+return authPage.login();+});++test('it configures ssh ca', async function (assert) {+const path = `ssh-${new Date().getTime()}`;+await enablePage.enable('ssh', path);+await settled();+await page.visit({ backend: path });+await settled();+assert.dom(SELECTORS.generateSigningKey).isChecked('generate_signing_key defaults to true');+await click(SELECTORS.generateSigningKey);+await click(SELECTORS.saveConfig);+assert.strictEqual(+flashMessage.latestMessage,+'missing public_key',+'renders warning flash message for failed save'+);+await click(SELECTORS.generateSigningKey);+await click(SELECTORS.saveConfig);+assert.dom(SELECTORS.publicKey).exists('renders public key after saving config');+});+});<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>7071eb26f463be043a72dfdfcfdec59612fa4755 (#19478)website/content/api-docs/secret/identity/entity-alias.mdx | 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)
website/content/docs/secrets/gcp.mdx+4 −2
@@ -294,8 +294,10 @@ $ curl -H "Authorization: Bearer ya29.c.ElodBmNPwHUNY5gcBpnXcE4ywG4w1k..."### Service Account Keys-To generate service account keys, read from `gcp/.../key`. The roleset or static-account must have been created as type `service_account_key`:+To generate service account keys, read from `gcp/.../key`. Vault returns the service+account key data as a base64-encoded string in the `private_key_data` field. This can+be read by decoding it using `base64 --decode "ewogICJ0e..."` or another base64 tool of+your choice. The roleset or static account must have been created as type `service_account_key`:```shell-session$ vault read gcp/roleset/my-key-roleset/key<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>5d20d598c35eb632db4e99168400f16ccef97255 (#19506)website/content/docs/upgrading/upgrade-to-1.13.x.mdx | 3 ---website/data/docs-nav-data.json | 3 +--2 files changed, 1 insertion(+), 5 deletions(-)
ui/tests/acceptance/secrets/backend/kv/breadcrumbs-test.js+29 −0
@@ -0,0 +1,29 @@+import { create } from 'ember-cli-page-object';+import { module, test } from 'qunit';+import { setupApplicationTest } from 'ember-qunit';+import { click, currentURL, fillIn, visit } from '@ember/test-helpers';+import authPage from 'vault/tests/pages/auth';+import consoleClass from 'vault/tests/pages/components/console/ui-panel';++const consolePanel = create(consoleClass);++module('Acceptance | kv | breadcrumbs', function (hooks) {+setupApplicationTest(hooks);++test('it should route back to parent path from metadata tab', async function (assert) {+await authPage.login();+await consolePanel.runCommands(['delete sys/mounts/kv', 'write sys/mounts/kv type=kv-v2']);+await visit('/vault/secrets/kv/list');+await click('[data-test-secret-create]');+await fillIn('[data-test-secret-path]', 'foo/bar');+await click('[data-test-secret-save]');+await click('[data-test-secret-metadata-tab]');+await click('[data-test-secret-breadcrumb="foo"]');+assert.strictEqual(+currentURL(),+'/vault/secrets/kv/list/foo/',+'Routes back to list view on breadcrumb click'+);+await consolePanel.runCommands(['delete sys/mounts/kv']);+});+});
ui/tests/unit/routes/vault/cluster/oidc-callback-test.js+94 −68
@@ -1,4 +1,9 @@-import { module, test } from 'qunit';+/**+* Copyright (c) HashiCorp, Inc.+* SPDX-License-Identifier: MPL-2.0+*/++import { module, skip, test } from 'qunit';import { setupTest } from 'ember-qunit';import sinon from 'sinon';@@ -12,173 +17,194 @@ module('Unit | Route | vault/cluster/oidc-callback', function (hooks) {};this.route = this.owner.lookup('route:vault/cluster/oidc-callback');this.windowStub = sinon.stub(window.opener, 'postMessage');+this.state = 'st_yOarDguU848w5YZuotLs';this.path = 'oidc';this.code = 'lTazRXEwKfyGKBUCo5TyLJzdIt39YniBJOXPABiRMkL0T';-this.state = (ns) => {-return ns ? 'st_91ji6vR2sQ2zBiZSQkqJ' + `,ns=${ns}` : 'st_91ji6vR2sQ2zBiZSQkqJ';+this.route.paramsFor = (path) => {+if (path === 'vault.cluster') return { namespaceQueryParam: '' };+return {+auth_path: this.path,+code: this.code,+};+};+this.callbackUrlQueryParams = (stateParam) => {+switch (stateParam) {+case '':+window.history.pushState({}, '');+break;+case 'stateless':+window.history.pushState({}, '', '?' + `code=${this.code}`);+break;+default:+window.history.pushState({}, '', '?' + `code=${this.code}&state=${stateParam}`);+break;+}};});hooks.afterEach(function () {this.windowStub.restore();window.opener = this.originalOpener;+this.callbackUrlQueryParams('');});test('it calls route', function (assert) {assert.ok(this.route);});-test('it uses namespace param from state not namespaceQueryParam from cluster with default path', function (assert) {-this.routeName = 'vault.cluster.oidc-callback';-this.route.paramsFor = (path) => {-if (path === 'vault.cluster') return { namespaceQueryParam: 'admin' };-return {-auth_path: this.path,-state: this.state('admin/child-ns'),-code: this.code,-};-};-this.route.afterModel();--assert.ok(this.windowStub.calledOnce, 'it is called');-assert.propContains(-this.windowStub.lastCall.args[0],-{-code: 'lTazRXEwKfyGKBUCo5TyLJzdIt39YniBJOXPABiRMkL0T',-namespace: 'admin/child-ns',-path: 'oidc',-},-'namespace param is from state, ns=admin/child-ns'-);-});--test('it uses namespace param from state not namespaceQueryParam from cluster with custom path', function (assert) {+skip('it uses namespace param from state instead of cluster, with custom oidc path', function (assert) {this.routeName = 'vault.cluster.oidc-callback';+this.callbackUrlQueryParams(encodeURIComponent(`${this.state},ns=test-ns`));this.route.paramsFor = (path) => {if (path === 'vault.cluster') return { namespaceQueryParam: 'admin' };return {auth_path: 'oidc-dev',-state: this.state('admin/child-ns'),code: this.code,};};this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{+code: this.code,path: 'oidc-dev',-namespace: 'admin/child-ns',-state: this.state(),+namespace: 'test-ns',+state: this.state,+source: 'oidc-callback',},-'state ns takes precedence, state no longer has ns query'+'ns from state not cluster');});-test(`it uses namespace from namespaceQueryParam when state does not include: ',ns=some-namespace'`, function (assert) {+skip('it uses namespace from cluster when state does not include ns param', function (assert) {this.routeName = 'vault.cluster.oidc-callback';+this.callbackUrlQueryParams(encodeURIComponent(this.state));this.route.paramsFor = (path) => {if (path === 'vault.cluster') return { namespaceQueryParam: 'admin' };return {auth_path: this.path,-state: this.state(),code: this.code,};};this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{+code: this.code,path: this.path,namespace: 'admin',-state: this.state(),+state: this.state,+source: 'oidc-callback',},-'namespace is from cluster namespaceQueryParam'+`namespace is from cluster's namespaceQueryParam`);});-test('it uses ns param from state when no namespaceQueryParam from cluster', function (assert) {-this.routeName = 'vault.cluster.oidc-callback';-this.route.paramsFor = (path) => {-if (path === 'vault.cluster') return { namespaceQueryParam: '' };-return {-auth_path: this.path,-state: this.state('ns1'),-code: this.code,-};-};+skip('it correctly parses encoded, nested ns param from state', function (assert) {+this.callbackUrlQueryParams(encodeURIComponent(`${this.state},ns=parent-ns/child-ns`));this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{+code: this.code,path: this.path,-namespace: 'ns1',-state: this.state(),+namespace: 'parent-ns/child-ns',+state: this.state,+source: 'oidc-callback',},-'it strips ns from state and uses as namespace param'+'it has correct nested ns from state and sets as namespace param');});-test('the afterModel hook returns when both cluster and route params are empty strings', function (assert) {+skip('the afterModel hook returns when both cluster and route params are empty strings', function (assert) {this.routeName = 'vault.cluster.oidc-callback';+this.callbackUrlQueryParams('');this.route.paramsFor = (path) => {if (path === 'vault.cluster') return { namespaceQueryParam: '' };return {auth_path: '',-state: '',code: '',};};this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{path: '',state: '',code: '',+source: 'oidc-callback',},'model hook returns with empty params');});-test('the afterModel hook returns when state param does not exist', function (assert) {+skip('the afterModel hook returns when state param does not exist', function (assert) {this.routeName = 'vault.cluster.oidc-callback';-this.route.paramsFor = (path) => {-if (path === 'vault.cluster') return { namespaceQueryParam: '' };-return {-auth_path: this.path,-};-};+this.callbackUrlQueryParams('stateless');this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{-code: '',+code: this.code,path: 'oidc',state: '',+source: 'oidc-callback',},'model hook returns empty string when state param nonexistent');});-test('the afterModel hook returns when cluster namespaceQueryParam exists and all route params are empty strings', function (assert) {+skip('the afterModel hook returns when cluster ns exists and all route params are empty strings', function (assert) {this.routeName = 'vault.cluster.oidc-callback';+this.callbackUrlQueryParams('');this.route.paramsFor = (path) => {if (path === 'vault.cluster') return { namespaceQueryParam: 'ns1' };return {auth_path: '',-state: '',code: '',};};this.route.afterModel();-assert.propContains(+assert.propEqual(this.windowStub.lastCall.args[0],{+code: '',+namespace: 'ns1',path: '',+source: 'oidc-callback',state: '',-code: '',},'model hook returns with empty parameters');});++/*+If authenticating to a namespace, most SSO providers return a callback url+with a 'state' query param that includes a URI encoded namespace, example:+'?code=BZBDVPMz0By2JTqulEMWX5-6rflW3A20UAusJYHEeFygJ&state=sst_yOarDguU848w5YZuotLs%2Cns%3Dadmin'++Active Directory Federation Service (AD FS), instead, decodes the namespace portion:+'?code=BZBDVPMz0By2JTqulEMWX5-6rflW3A20UAusJYHEeFygJ&state=st_yOarDguU848w5YZuotLs,ns=admin'++'ns' isn't recognized as a separate param because there is no ampersand, so using this.paramsFor() returns+a namespace-less state and authentication fails+{ state: 'st_yOarDguU848w5YZuotLs,ns' }+*/+skip('it uses namespace when state param is not uri encoded', async function (assert) {+this.routeName = 'vault.cluster.oidc-callback';+this.callbackUrlQueryParams(`${this.state},ns=admin`);+this.route.afterModel();+assert.propEqual(+this.windowStub.lastCall.args[0],+{+code: this.code,+namespace: 'admin',+path: this.path,+source: 'oidc-callback',+state: this.state,+},+'namespace is parsed correctly'+);+});});<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>with VAULT_GRPC_MIN_CONNECT_TIMEOUT into release/1.13.x (#19680)changelog/19676.txt | 4 ++++vault/cluster.go | 3 ++-vault/cluster/cluster.go | 17 +++++++++++++++--vault/cluster/inmem_layer.go | 2 +-vault/core.go | 13 +++++++++++++vault/request_forwarding.go | 14 ++++++++++++--6 files changed, 47 insertions(+), 6 deletions(-)create mode 100644 changelog/19676.txt
website/content/partials/tokenization-rotation-persistence.mdx+14 −0
@@ -0,0 +1,14 @@+### Rotation configuration persistence issue could lose Transform Tokenization key versions++A rotation performed manually or via automatic time based rotation after+restarting or leader change of Vault, where configuration of rotation was+changed since the initial configuration of the tokenization transform can+result in the loss of intermediate key versions. Tokenized values from+these versions would not be decodeable. It is recommended that customers+who have enabled automatic rotation disable it, and other customers avoid+key rotation until the upcoming fix.++#### Affected Versions++This issue affects Vault Enterprise with ADP versions 1.10.x and higher. A+fix will be released in Vault 1.11.9, 1.12.5, and 1.13.1.<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>1fb765d61a9ac0081094d3ae92fda8e329cd0379 (#19559)changelog/19545.txt | 3 +++go.mod | 2 +-go.sum | 4 ++--3 files changed, 6 insertions(+), 3 deletions(-)create mode 100644 changelog/19545.txt
changelog/19585.txt+3 −0
@@ -0,0 +1,3 @@+```release-note:bug+core: Fixed issue with remounting mounts that have a non-trailing space in the 'to' or 'from' paths.+```
website/content/partials/ocsp-redirect.mdx+11 −0
@@ -0,0 +1,11 @@+### PKI OCSP GET requests can return HTTP redirect responses++If a base64 encoded OCSP request contains consecutive '/' characters, the GET request+will return a 301 permanent redirect response. If the redirection is followed, the+request will not decode as it will not be a properly base64 encoded request.++As a workaround, OCSP POST requests can be used which are unaffected.++#### Impacted Versions++Affects all current versions of 1.12.x and 1.13.x<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>77e80a80301a59f1d5ebfff951e460b2528cfcf7 (#19617)builtin/credential/github/path_config.go | 4 +-builtin/credential/github/path_config_test.go | 38 +++++++++++++++++++changelog/19244.txt | 4 ++website/content/api-docs/auth/github.mdx | 6 +++4 files changed, 51 insertions(+), 1 deletion(-)create mode 100644 changelog/19244.txt
website/content/docs/upgrading/upgrade-to-1.13.x.mdx+12 −0
@@ -81,3 +81,15 @@ are unaffected.@include 'tokenization-rotation-persistence.mdx'@include 'ocsp-redirect.mdx'++### PKI Revocation Request Forwarding++If a revocation request comes in to a standby or performance secondary node,+for a certificate that is present locally, the request will not be correctly+forwarded to the active node of this cluster.++As a workaround, submit revocation requests to the active node only.++#### Impacted Versions++Affects Vault 1.13.0 only.<82990506+hc-github-team-secure-vault-core@users.noreply.github.com>c5bc1764c85d099b6ba8da90ce6f2a3ccfbad94d (#19643)changelog/19640.txt | 3 +++go.mod | 2 +-go.sum | 4 ++--3 files changed, 6 insertions(+), 3 deletions(-)create mode 100644 changelog/19640.txt