HsmSecretStore
Manage a store of secrets with a hardware security module (HSM) device or a software emulation of an HSM device, such as SoftHSM.
This Secret store can only manage secrets of the CryptoKey type.
The secrets provider queries the HsmSecretStore for a named secret,
identified by a secret ID and a stable ID, corresponding to the
secret-id
/aliases
mapping. The HsmSecretStore returns a list of matching
secrets.
The secrets provider builds the secret, checking that the secret’s constraints are met, and returns a unique secret. If the secret’s constraints are not met, the secrets provider cannot build the secret and the secret query fails.
For a description of how secrets are managed, refer to About secrets
Usage
{
"name": string,
"type": "HsmSecretStore",
"config": {
"providerName": configuration expression<string>,
"storePasswordSecretId": configuration expression<secret-id>,
"secretsProvider": SecretsProvider reference,
"mappings": [ object, ... ],
"leaseExpiry": configuration expression<duration>,
"storePassword": configuration expression<secret-id> //deprecated
}
}
Properties
"providerName"
: configuration expression<string>, required-
The name of the pre-installed Java Security Provider supporting an HSM. Use a physical HSM device, or a software emulation of an HSM device, such as SoftHSM.
For the SunPKCS11 provider, concatenate
"providerName"
with the prefixSunPKCS11-
. For example, declare the following for the nameFooAccelerator
:"providerName": "SunPKCS11-FooAccelerator"
"storePasswordSecretId"
: configuration expression<secret-id>, optional-
The secret ID of the password to access the HsmSecretStore.
This secret ID must point to a GenericSecret.
For information about how IG manages secrets, refer to About secrets.
"secretsProvider"
: SecretsProvider reference, required-
The SecretsProvider to query for the
storePassword
.
"mappings"
: array of objects, required-
One or more mappings of one secret ID to one or more aliases.
"mappings" : { "secretId": configuration expression<secret-id>, "aliases": array of configuration expression<string>, //use aliases or "aliasesMatching": [ string, ... ] //aliasesMatching but not both }
"secretId"
: configuration expression<secret-id>, required-
The secret ID of the key.
"aliases"
: array of configuration expression<strings>, required ifaliasesMatching
is not used-
One or more key aliases. Named aliases are mapped to the secret ID.
Use
aliases
oraliasesMatching
but not both. "aliasesMatching"
: array of <strings>, required ifaliases
is not used-
One or more regular expressions to match key aliases. Aliases that match the expressions are mapped to the secret ID.
Use
aliases
oraliasesMatching
but not both.Some KeyStores, such as a global Java TrustStore, can contain hundreds of valid certificates. Use this property to map multiple aliases to a secret ID without listing them all in the mapping.
The secret store uses the mappings as follows:
-
When the secret is used to create signatures or encrypt values, the secret store uses the active secret, the first alias in the list.
-
When the secret is used to verify signatures or decrypt data, the secret store tries all of the mapped aliases in the list, starting with the first, and stopping when it finds a secret that can successfully verify signature or decrypt the data.
The following example maps the named aliases to the named secret IDs:
"mappings": [ { "secretId": "id.key.for.signing.jwt", "aliases": [ "signingkeyalias", "anothersigningkeyalias" ] }, { "secretId": "id.key.for.encrypting.jwt", "aliases": ["encryptionkeyalias"] } ]
The following example maps aliases that match the regular expression
.*
to the named secret ID:"mappings": [ { "secretId": "id.key.for.signing.jwt", "aliasesMatching": [".*"] } ]
"leaseExpiry"
: configuration expression<duration>, optional-
The amount of time that secrets produced by this store can be cached before they must be refreshed.
If the duration is
zero
orunlimited
, IG issues a warning, and uses the default value.Default: 5 minutes
"storePassword"
: configuration expression<secret-id>, required if storePasswordSecretId not set-
The use of this property is deprecated. If the KeyStore is password-protected, use storePasswordSecretId
. For more information, refer to the Deprecated section of the Release Notes.The secret ID of the password to access the HsmSecretStore.
+ For information about how IG manages secrets, refer to About secrets.
Log level
To facilitate debugging secrets for the HsmSecretStore, in
logback.xml
add a logger defined by the fully qualified package name
of the HsmSecretStore. The following line in logback.xml
sets the
log level to ALL
:
<logger name="org.forgerock.secrets.keystore" level="ALL">
Example
To set up this example:
-
Set up and test the example in JwtBuilderFilter, and then replace the KeyStoreSecretStore in that example with an HsmSecretStore.
-
Set an environment variable for the HsmSecretStore password,
storePassword
, and then restart IG.For example, if the HsmSecretStore password is
password
, set the following environment variable:export HSM_PIN='cGFzc3dvcmQ='
The password is retrieved by the SystemAndEnvSecretStore, and must be base64-encoded.
-
Create a provider config file, as specified in the PKCS#11 Reference guide.
-
Depending on your version of Java, create a
java.security.ext
file for the IG instance, with the following content:security.provider.<number>=<provider-name> <path-to-provider-cfg-file>
or
security.provider.<number>=<class-name> <path-to-provider-cfg-file>
-
Start the IG JVM with the following system property that points to the provider config file:
-Djava.security.properties=file://path-to-security-extension-file
The following example route is based on the examples in JwtBuilderFilter, replacing the KeyStoreSecretStore with an HsmSecretStore:
{
"name": "hsm-jwt-signature",
"condition": "${find(request.uri.path, '/hsm-jwt-signature$')}",
"baseURI": "http://app.example.com:8081",
"heap": [
{
"name": "SystemAndEnvSecretStore-1",
"type": "SystemAndEnvSecretStore"
},
{
"name": "AmService-1",
"type": "AmService",
"config": {
"agent": {
"username": "ig_agent",
"passwordSecretId": "agent.secret.id"
},
"secretsProvider": "SystemAndEnvSecretStore-1",
"url": "http://am.example.com:8088/openam"
}
},
{
"name": "HsmSecretStore-1",
"type": "HsmSecretStore",
"config": {
"providerName": "SunPKCS11-SoftHSM",
"storePasswordSecretId": "hsm.pin",
"secretsProvider": "SystemAndEnvSecretStore-1",
"mappings": [{
"secretId": "id.key.for.signing.jwt",
"aliases": [ "signature-key" ]
}]
}
}
],
"handler": {
"type": "Chain",
"config": {
"filters": [{
"name": "SingleSignOnFilter-1",
"type": "SingleSignOnFilter",
"config": {
"amService": "AmService-1"
}
}, {
"name": "UserProfileFilter-1",
"type": "UserProfileFilter",
"config": {
"username": "${contexts.ssoToken.info.uid}",
"userProfileService": {
"type": "UserProfileService",
"config": {
"amService": "AmService-1"
}
}
}
}, {
"name": "JwtBuilderFilter-1",
"type": "JwtBuilderFilter",
"config": {
"template": {
"name": "${contexts.userProfile.commonName}",
"email": "${contexts.userProfile.rawInfo.mail[0]}"
},
"secretsProvider": "HsmSecretStore-1",
"signature": {
"secretId": "id.key.for.signing.jwt"
}
}
}, {
"name": "HeaderFilter-1",
"type": "HeaderFilter",
"config": {
"messageType": "REQUEST",
"add": {
"x-openig-user": ["${contexts.jwtBuilder.value}"]
}
}
}],
"handler": "ReverseProxyHandler"
}
}
}