Chapter 13. Using a vault to obtain secrets
To obtain a secret from a vault rather than entering it directly, enter the following specially crafted string into the appropriate field:
**${vault.**_key_**}**
where the key
is the name of the secret recognized by the vault.
To prevent secrets from leaking across realms, Red Hat Single Sign-On 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.
You can obtain the secret from the vault in the following fields:
- SMTP password
- In the realm SMTP settings
- LDAP bind credential
- In the LDAP settings of LDAP-based user federation.
- OIDC identity provider secret
- In the Client Secret inside identity provider OpenID Connect Config
To use a vault, register a vault provider in Red Hat Single Sign-On. You can use the providers described here or implement your provider. See the Server Developer Guide for more information.
Red Hat Single Sign-On permits a maximum of one active vault provider per Red Hat Single Sign-On instance at a time. Configure the vault provider in each instance within the cluster consistently.
13.1. Kubernetes / OpenShift files plain-text vault provider
Red Hat Single Sign-On supports vault implementation for Kubernetes secrets. You can mount Kubernetes secrets as data volumes, and they appear as a directory with a flat-file structure. Red Hat Single Sign-On represents each secret as a file with the file’s name as the secret name and the file’s contents as the secret value.
You must name the files within this directory as the secret name prefixed by the realm name and an underscore. Double all underscores within the secret name or the realm name in the file name. For example, for a field within a realm named sso_realm
, a reference to a secret with the name secret-name
would be written as ${vault.secret-name}
, and the file name looked up would be sso__realm_secret-name
. Note the underscore doubled in realm name.
To use this type of secret store, you must declare the files-plaintext
vault provider in the standalone.xml file and set its parameter for the directory containing the mounted volume. This example shows the files-plaintext
provider with the directory where vault files are searched set to standalone/configuration/vault
relative to the Red Hat Single Sign-On base directory:
<spi name="vault"> <default-provider>files-plaintext</default-provider> <provider name="files-plaintext" enabled="true"> <properties> <property name="dir" value="${jboss.home.dir}/standalone/configuration/vault/" /> </properties> </provider> </spi>
Here is the equivalent configuration using CLI commands:
/subsystem=keycloak-server/spi=vault/:add /subsystem=keycloak-server/spi=vault/provider=files-plaintext/:add(enabled=true,properties={dir => "${jboss.home.dir}/standalone/configuration/vault"}) /subsystem=keycloak-server/spi=vault:write-attribute(name=default-provider,value=files-plaintext)
13.2. Elytron credential store vault provider
Red Hat Single Sign-On also provides support for reading secrets stored in an Elytron credential store. The elytron-cs-keystore
vault provider can retrieve secrets from the credential store’s keystore based implementation, which is also the default implementation Elytron provides.
A keystore backs this credential store. JCEKS
is the default format, but you can use other formats such as PKCS12
. Users can create and manage the store contents using the elytron
subsystem in WildFly/JBoss EAP, or the elytron-tool.sh
script.
To use this provider, you must declare the elytron-cs-keystore
in the keycloak-server
subsystem and set the location and master secret of the keystore created by Elytron. An example of the minimal configuration for the provider follows:
<spi name="vault"> <default-provider>elytron-cs-keystore</default-provider> <provider name="elytron-cs-keystore" enabled="true"> <properties> <property name="location" value="${jboss.home.dir}/standalone/configuration/vault/credential-store.jceks" /> <property name="secret" value="secretpw1!"/> </properties> </provider> </spi>
If the underlying keystore has a format different from JCEKS
, you must specify this format by using the keyStoreType
:
<spi name="vault"> <default-provider>elytron-cs-keystore</default-provider> <provider name="elytron-cs-keystore" enabled="true"> <properties> <property name="location" value="${jboss.home.dir}/standalone/configuration/vault/credential-store.p12" /> <property name="secret" value="secretpw1!"/> <property name="keyStoreType" value="PKCS12"/> </properties> </provider> </spi>
For the secret, the elytron-cs-keystore
provider supports clear-text values and masked values by using the elytron-tool.sh
script:
<spi name="vault"> ... <property name="secret" value="MASK-3u2HNQaMogJJ8VP7J6gRIl;12345678;321"/> ... </spi>
For more information about creating and managing elytron credential stores and masking keystore secrets, see the Elytron documentation.
Red Hat Single Sign-On implements the elytron-cs-keystore
vault provider as a WildFly extension and is available if the Red Hat Single Sign-On server runs on WildFly/JBoss EAP only.
13.3. 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. Red Hat Single Sign-On 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:
<spi name="vault"> <default-provider>files-plaintext</default-provider> <provider name="files-plaintext" enabled="true"> <properties> <property name="dir" value="${jboss.home.dir}/standalone/configuration/vault/" /> <property name="keyResolvers" value="REALM_UNDERSCORE_KEY, KEY_ONLY"/> </properties> </provider> </spi>
The resolvers run in the same order you declare them in the configuration. For each resolver, Red Hat Single Sign-On uses the last entry name the resolver produces, which combines the realm with the vault key to search for the vault’s secret. If Red Hat Single Sign-On finds a secret, it returns the secret. If not, Red Hat Single Sign-On uses the next resolver. This search continues until Red Hat Single Sign-On finds a non-empty secret or runs out of resolvers. If Red Hat Single Sign-On finds no secret, Red Hat Single Sign-On returns an empty secret.
In the previous example, Red Hat Single Sign-On uses the REALM_UNDERSCORE_KEY
resolver first. If Red Hat Single Sign-On finds an entry in the vault that using that resolver, Red Hat Single Sign-On returns that entry. If not, Red Hat Single Sign-On searches again using the KEY_ONLY
resolver. If Red Hat Single Sign-On finds an entry by using the KEY_ONLY
resolver, Red Hat Single Sign-On returns that entry. If Red Hat Single Sign-On uses all resolvers, Red Hat Single Sign-On returns an empty secret.
A list of the currently available resolvers follows:
Name | Description |
---|---|
KEY_ONLY | Red Hat Single Sign-On ignores the realm name and uses the key from the vault expression. |
REALM_UNDERSCORE_KEY |
Red Hat Single Sign-On combines the realm and key by using an underscore character. Red Hat Single Sign-On escapes occurrences of underscores in the realm or key with another underscore character. For example, if the realm is called |
REALM_FILESEPARATOR_KEY | Red Hat Single Sign-On combines the realm and key by using the platform file separator character. |
If you have not configured a resolver for the built-in providers, Red Hat Single Sign-On selects the REALM_UNDERSCORE_KEY
.
13.4. Sample Configuration
The following is an example of configuring a vault and credential store. The procedure involves two parts:
- Creating the credential store and a vault, where the credential store and vault passwords are in plain text.
-
Updating the credential store and vault to have the password use a mask provided by
elytron-tool.sh
.
In this example, the test target used is an LDAP instance with BIND DN credential: secret12
. The target is mapped using user federation in the realm ldaptest
.
13.4.1. Configuring the credential store and vault without a mask
You create the credential store and a vault where the credential store and vault passwords are in plain text.
Prerequisites
-
A running LDAP instance has
BIND DN credential: secret12
. -
The alias uses the format <realm-name>_< key-value> when using the default key resolver. In this case, the instance is running in the realm
ldaptest
andldaptest_ldap_secret
is the alias that corresponds to the valueldap_secret
in that realm.
The resolver replaces underscore characters with double underscore characters in the realm and key names. For example, for the key ldaptest_ldap_secret
, the final key will be ldaptest_ldap__secret
.
Procedure
Create the Elytron credential store.
[standalone@localhost:9990 /] /subsystem=elytron/credential-store=test-store:add(create=true, location=/home/test/test-store.p12, credential-reference={clear-text=testpwd1!},implementation-properties={keyStoreType=PKCS12})
Add an alias to the credential store.
/subsystem=elytron/credential-store=test-store:add-alias(alias=ldaptest_ldap__secret,secret-value=secret12)
Notice how the resolver causes the key
ldaptest_ldap__secret
to use double underscores.List the aliases from the credential store to inspect the contents of the keystore that is produced by Elytron.
keytool -list -keystore /home/test/test-store.p12 -storetype PKCS12 -storepass testpwd1! Keystore type: PKCS12 Keystore provider: SUN Your keystore contains 1 entries ldaptest_ldap__secret/passwordcredential/clear/, Oct 12, 2020, SecretKeyEntry,
Configure the vault SPI in Red Hat Single Sign-On.
/subsystem=keycloak-server/spi=vault:add(default-provider=elytron-cs-keystore) /subsystem=keycloak-server/spi=vault/provider=elytron-cs-keystore:add(enabled=true, properties={location=>/home/test/test-store.p12, secret=>testpwd1!, keyStoreType=>PKCS12})
At this point, the vault and credentials store passwords are not masked.
<spi name="vault"> <default-provider>elytron-cs-keystore</default-provider> <provider name="elytron-cs-keystore" enabled="true"> <properties> <property name="location" value="/home/test/test-store.p12"/> <property name="secret" value="testpwd1!"/> <property name="keyStoreType" value="PKCS12"/> </properties> </provider> </spi> <credential-stores> <credential-store name="test-store" location="/home/test/test-store.p12" create="true"> <implementation-properties> <property name="keyStoreType" value="PKCS12"/> </implementation-properties> <credential-reference clear-text="testpwd1!"/> </credential-store> </credential-stores>
-
In the LDAP provider, replace
binDN credential
with${vault.ldap_secret}
. Test your LDAP connection.
LDAP Vault
13.4.2. Masking the password in the credential store and vault
You can now update the credential store and vault to have passwords that use a mask provided by elytron-tool.sh
.
Create a masked password using values for the
salt
and theiteration
parameters:$ EAP_HOME/bin/elytron-tool.sh mask --salt SALT --iteration ITERATION_COUNT --secret PASSWORD
For example:
elytron-tool.sh mask --salt 12345678 --iteration 123 --secret testpwd1! MASK-3BUbFEyWu0lRAu8.fCqyUk;12345678;123
Update the Elytron credential store configuration to use the masked password.
/subsystem=elytron/credential-store=cs-store:write-attribute(name=credential-reference.clear-text,value="MASK-3BUbFEyWu0lRAu8.fCqyUk;12345678;123")
Update the Red Hat Single Sign-On vault configuration to use the masked password.
/subsystem=keycloak-server/spi=vault/provider=elytron-cs-keystore:remove() /subsystem=keycloak-server/spi=vault/provider=elytron-cs-keystore:add(enabled=true, properties={location=>/home/test/test-store.p12, secret=>”MASK-3BUbFEyWu0lRAu8.fCqyUk;12345678;123”, keyStoreType=>PKCS12})
The vault and credential store are now masked:
<spi name="vault"> <default-provider>elytron-cs-keystore</default-provider> <provider name="elytron-cs-keystore" enabled="true"> <properties> <property name="location" value="/home/test/test-store.p12"/> <property name="secret" value="MASK-3BUbFEyWu0lRAu8.fCqyUk;12345678;123"/> <property name="keyStoreType" value="PKCS12"/> </properties> </provider> </spi> .... ..... <credential-stores> <credential-store name="test-store" location="/home/test/test-store.p12" create="true"> <implementation-properties> <property name="keyStoreType" value="PKCS12"/> </implementation-properties> <credential-reference clear-text="MASK-3BUbFEyWu0lRAu8.fCqyUk;12345678;123"/> </credential-store> </credential-stores>
-
You can now test the connection to the LDAP using
${vault.ldap_secret}
.
Additional resources
For more information about the Elytron tool, see Using Credential Stores with Elytron Client.