
[[_vault-administration]]

== Using a vault to obtain secrets

{project_name} currently provides two out-of-the-box implementations of the Vault SPI: a plain-text file-based vault and Java KeyStore-based vault.

To obtain a secret from a vault rather than entering it directly, enter the following specially crafted string into the appropriate field:

[source]
----
${vault.key}
----
where the `key` is the name of the secret recognized by the vault.

To prevent secrets from leaking across realms, {project_name} combines the realm name with the `key` obtained from the vault expression. This method means that the `key` does not directly map to an entry in the vault but creates the final entry name according to the algorithm used to combine the `key` with the realm name. In case of the file-based vault, such combination reflects to a specific filename, for the Java KeyStore-based vault it's a specific alias name.

You can obtain the secret from the vault in the following fields:

SMTP password::
In the realm <<_email,SMTP settings>>

LDAP bind credential::
In the <<_ldap,LDAP settings>> of LDAP-based user federation.

OIDC identity provider secret::
In the _Client Secret_ inside identity provider <<_identity_broker_oidc,OpenID Connect Config>>

[[_vault-key-resolvers]]
=== Key resolvers

All built-in providers support the configuration of key resolvers. A key resolver implements the algorithm or strategy for combining the realm name with the key, obtained from the `${vault.key}` expression, into the final entry name used to retrieve the secret from the vault. {project_name} uses the `keyResolvers` property to configure the resolvers that the provider uses. The value is a comma-separated list of resolver names. An example of the configuration for the `files-plaintext` provider follows:

[source,bash]
----
kc.[sh|bat] start --spi-vault-file-key-resolvers=REALM_UNDERSCORE_KEY,KEY_ONLY
----

The resolvers run in the same order you declare them in the configuration. For each resolver, {project_name} uses the last entry name the resolver produces, which combines the realm with the vault key to search for the vault's secret. If {project_name} finds a secret, it returns the secret. If not, {project_name} uses the next resolver. This search continues until {project_name} finds a non-empty secret or runs out of resolvers. If {project_name} finds no secret, {project_name} returns an empty secret.

In the previous example, {project_name} uses the `REALM_UNDERSCORE_KEY` resolver first. If {project_name} finds an entry in the vault that using that resolver, {project_name} returns that entry. If not, {project_name} searches again using the `KEY_ONLY` resolver. If {project_name} finds an entry by using the `KEY_ONLY` resolver, {project_name} returns that entry. If {project_name} uses all resolvers, {project_name} returns an empty secret.

A list of the currently available resolvers follows:

|===
|Name |Description

| KEY_ONLY
| {project_name} ignores the realm name and uses the key from the vault expression. {project_name} escapes occurrences of underscores in the key with another underscore character. For example, if the key is called `my_secret`, {project_name} searches for an entry in the vault named `my++__++secret`. This is to prevent conflicts with the default `REALM_UNDERSCORE_KEY` resolver.

| REALM_UNDERSCORE_KEY
| {project_name} combines the realm and key by using an underscore character. {project_name} escapes occurrences of underscores in the realm or key with another underscore character. For example, if the realm is called `master_realm` and the key is `smtp_key`, the combined key is `master+++__+++realm_smtp+++__+++key`.

| REALM_FILESEPARATOR_KEY
| {project_name} combines the realm and key by using the platform file separator character. The vault expression prohibits the use of characters that could cause path traversal, thus preventing access to secrets outside the corresponding realm.

ifeval::[{project_community}==true]
| FACTORY_PROVIDED
| {project_name} combines the realm and key by using the vault provider factory's `VaultKeyResolver`, allowing the creation of a custom key resolver by extending an existing factory and implementing the `getFactoryResolver` method.
endif::[]

|===

If you have not configured a resolver for the built-in providers, {project_name} selects the `REALM_UNDERSCORE_KEY`.
