IG 2023.6

Secrets object and secret stores

IG uses the ForgeRock Commons Secrets API to manage secrets, such as passwords and cryptographic keys.

For more information about how IG manages secrets, refer to Secrets.

Default secrets object (deprecated)

This object is deprecated; use SecretsProvider instead. For more information, refer to the Deprecated section of the Release Notes.

IG automatically creates a secrets object in each route in the configuration, and in config.json and admin.json.

When the secrets object is not used to declare a secrets store in the configuration, IG creates a default SystemAndEnvSecretStore in the local secrets service. When the secrets object is used to declare a secrets store, the default is not installed in the local secrets service.

Usage

{
  "secrets": {
    "stores": [ SecretStore reference, ... ]
  }
}

Properties

"stores": array of SecretStore references, required

One or more of the following secret stores:

Example

The following example configures two secret stores:

{
  "secrets": {
    "stores": [
       {
        "type": "FileSystemSecretStore",
        "config": {
          "directory": "/path/to/secrets",
          "format": "BASE64"
        }
      },
      {
        "type": "SystemAndEnvSecretStore",
        "config": {
          "format": "PLAIN"
        }
      }
    ]
  }
}

SecretsProvider

Uses the specified secret stores to resolve queried secrets, such as passwords and cryptographic keys. Attempts to resolve the secret with the secret stores in the order that they are declared in the array.

Usage

{
  "name": string,
  "type": "SecretsProvider",
  "config": {
    "stores": [ SecretStore reference, ... ]
  }
}

This object can alternatively be configured in a compact format, without the SecretsProvider declaration, as follows:

  • With an inline secret store:

    "secretsProvider": {
      "type": "secret store type1",
      "config": {...}
    }
  • With multiple inline secret stores:

    "secretsProvider": [
      {
        "type": "secret store type1",
        "config": {...}
      }
      {
        "type": "secret store type2",
        "config": {...}
      }
    ]
  • With a referenced secret store:

    "secretsProvider": "mySecretStore1"
  • With multiple referenced secret stores:

    "secretsProvider": [
      "mySecretStore1", "mySecretStore2"
    ]

See Example for more example configurations.

Properties

"stores": array of SecretStore references, required

One or more secret stores to provide access to stored secrets. Configure secret stores described in Secrets.

Example

The following SecretsProvider is used in Discover and dynamically register with OpenID connect providers.

"secretsProvider": {
  "type": "SecretsProvider",
  "config": {
    "stores": [
      {
        "type": "KeyStoreSecretStore",
        "config": {
          "file": "/path/to/keystore.p12",
          "mappings": [
            {
              "aliases": [ "myprivatekeyalias" ],
              "secretId": "private.key.jwt.signing.key"
            }
          ],
          "storePasswordSecretId": "keystore.secret.id",
          "storeType": "PKCS12",
          "secretsProvider": "SystemAndEnvSecretStore-1"
        }
      }
    ]
  }
}

The following example shows the equivalent SecretsProvider configuration with an inline compact format:

"secretsProvider": {
  "name": "KeyStoreSecretStore-1",
  "type": "KeyStoreSecretStore",
  "config": {
    "file": "/path/to/keystore.p12",
    "mappings": [
      {
        "aliases": [ "myprivatekeyalias" ],
        "secretId": "private.key.jwt.signing.key"
      }
    ],
    "storePasswordSecretId": "keystore.secret.id",
    "storeType": "PKCS12"
  }
}

The following example shows the equivalent SecretsProvider configuration with a compact format, referencing a KeyStoreSecretStore object in the heap:

"secretsProvider": "KeyStoreSecretStore-1"

Secret stores

Base64EncodedSecretStore

Manage a repository of generic secrets, such as passwords or simple shared secrets, whose values are base64-encoded, and hard-coded in the route.

This Secret store can only manage secrets of the GenericSecret type.

The secrets provider queries the Base64EncodedSecretStore for a named secret, identified by the secret-id in the "secret-id": "string" pair. The Base64EncodedSecretStore returns the matching secret.

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.

Secrets from Base64EncodedSecretStore never expire.

Use Base64EncodedSecretStore for testing or evaluation only, to store passwords locally. In production, use an alternative secret store.

For a description of how secrets are managed, refer to Secrets.

Usage

{
  "name": string,
  "type": "Base64EncodedSecretStore",
  "config": {
    "secrets": map or configuration expression<map>
  }
}

Properties

"secrets": map or configuration expression<map>, required

Map of one or more data pairs with the format Map<String, String>, where:

  • The key is the ID of a secret used in a route

  • The value is the base64-encoded value of a secret, or a configuration expression that evaluates to the base64-encoded value of a secret

The following formats are allowed:

{
  "secrets": {
    "secret-id": "configuration expression<string>",
    ...
  }
}
{
  "secrets": "configuration expression<map>"
}

In the following example, the property is a map whose values are provided by strings:

{
  "type": "Base64EncodedSecretStore",
  "config": {
    "secrets": {
      "agent.password": "d2VsY29tZQ==",
      "crypto.header.key": "Y2hhbmdlaXQ="
    }
  }
}

In the following example, the property is a map whose values are provided by a configuration token and a configuration expression. The values are substituted when the route is loaded:

{
  "type": "Base64EncodedSecretStore",
  "config": {
    "secrets": {
      "agent.password": "&{secret.value|aGVsbG8=}",
      "crypto.header.key": "${readProperties('file.property')['b64.key.value']}"
    }
  }
}

Log level

To facilitate debugging secrets for the Base64EncodedSecretStore, in logback.xml add a logger defined by the fully qualified package name of the Base64EncodedSecretStore. The following line in logback.xml sets the log level to ALL:

<logger name="org.forgerock.openig.secrets.Base64EncodedSecretStore" level="ALL">

Example

For an example that uses Base64EncodedSecretStore, refer to client-credentials.json in Using OAuth 2.0 client credentials.

FileSystemSecretStore

Manage a store of secrets held in files, specified as follows:

  • Each file must contain only one secret.

  • The file must be in the directory specified by the property directory.

  • The filename must match the mappings property secretId.

  • The file content must match the mappings property format. For example, if the mapping specifies BASE64, the file content must be base64-encoded.

This Secret store can manage secrets of both GenericSecret and CryptoKey types when used with dedicated formats.

Secrets are read lazily from the filesystem.

The secrets provider queries the FileSystemSecretStore for a named secret, identified by the name of a file in the specified directory, without the prefix/suffix defined in the store configuration. The FileSystemSecretStore returns the secret that exactly matches the name.

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 Secrets.

Usage

{
  "name": string,
  "type": "FileSystemSecretStore",
  "config": {
    "directory": configuration expression<string>,
    "format": SecretPropertyFormat reference,
    "suffix": configuration expression<string>,
    "mappings": [ object, ... ],
    "leaseExpiry": configuration expression<duration>,
    "autoRefresh": object
  }
}

Properties

"directory": configuration expression<string>, required

File path to a directory containing secret files. This object checks the specified directory, but not its subdirectories.

format: SecretPropertyFormat reference, optional

Format in which the secret is stored. Use one of the following values, or define a format:

  • BASE64: Base64-encoded

  • PLAIN: Plain text

Default: BASE64

"suffix": configuration expression<string>, optional

File suffix.

When set, the FileSystemSecretStore will append that suffix to the secret ID and try to find a file with the mapped name.

Default: None

"mappings": array of objects, optional

One or more mappings to define a secret:

secretId: configuration expression<secret-id>, required

The ID of the secret used in your configuration.

format: SecretPropertyFormat reference, required

The format and algorithm of the secret. Use SecretKeyPropertyFormat or PemPropertyFormat.

"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 or unlimited, IG issues a warning, and uses the default value.

Default: 5 minutes

"autoRefresh": object, optional

Automatically reload the FileSystemSecretStore when a file is edited or deleted on the filesystem in the configured directory.

{
  "enabled": configuration expression<boolean>,
  "executor": ScheduledExecutorService reference
}
enabled: configuration expression<boolean>, optional

Flag to enable or disable automatic reload:

  • true: Enable

  • false: Disable

Default: true

"executor": ScheduledExecutorService reference, optional

A ScheduledExecutorService to monitor the filesystem.

Default: The default ScheduledExecutorService in the heap

Log level

To facilitate debugging secrets for the FileSystemSecretStore, in logback.xml add a logger defined by the fully qualified package name of the property resolver. The following line in logback.xml sets the log level to ALL:

<logger name="org.forgerock.secrets.propertyresolver" level="ALL">

Example

For an example that uses FileSystemSecretStore, refer to Pass runtime data in a JWT signed with a PEM.

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 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 prefix SunPKCS11-. For example, declare the following for the name FooAccelerator:

"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 Secrets.

"secretsProvider": SecretsProvider reference, optional

The SecretsProvider object to query for the storePassword.

Default: The route’s default secret service. For more information, refer to Default secrets object.

"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 if aliasesMatching is not used

One or more key aliases. Named aliases are mapped to the secret ID.

Use aliases or aliasesMatching but not both.

"aliasesMatching": array of <strings>, required if aliases 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 or aliasesMatching 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": [".*"]
  }
]
secretId: configuration expression<secret-id>, required

The ID of the secret used in your configuration.

aliases: array of configuration expression<strings>, required

One or more aliases for the secret ID. :leveloffset: +2

"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 or unlimited, 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 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:

  1. Set up and test the example in JwtBuilderFilter, and then replace the KeyStoreSecretStore in that example with an HsmSecretStore.

  2. 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.

  3. Create a provider config file, as specified in the PKCS#11 Reference guide.

  4. 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>
  5. 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"
    }
  }
}

JwkSetSecretStore

A secret store of JSON Web Keys (JWK) from a local or remote JWK Set.

This Secret store can only manage secrets of the CryptoKey type.

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 Secrets.

For information about JWKs and JWK Sets, refer to JSON Web Key (JWK).

Usage

{
  "name": string,
  "type": "JwkSetSecretStore",
  "config": {
    "jwkUrl": configuration expression<url>,
    "handler": Handler reference,
    "cacheTimeout": configuration expression<duration>,
    "cacheMissCacheTime": configuration expression<duration>,
    "leaseExpiry": configuration expression<duration>
  }
}

Properties

"jwkUrl": configuration expression<url>, required

A URL that contains the client’s public keys in JWK format.

"handler": Handler reference, optional

An HTTP client handler to communicate with the jwkUrl.

Usually set this property to the name of a ClientHandler configured in the heap, or a chain that ends in a ClientHandler.

Default: ClientHandler

"cacheTimeout": configuration expression<duration>, optional

Delay before the cache is reloaded. The cache contains the jwkUrl.

The cache cannot be deactivated. If a value lower than 10 seconds is configured, a warning is logged and the default value is used instead.

Default: 2 minutes

"cacheMissCacheTime": configuration expression<duration>, optional

If the jwkUrl is looked up in the cache and is not found, this is the delay before the cache is reloaded.

Default: 2 minutes

"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 or unlimited, IG issues a warning, and uses the default value.

Default: 5 minutes

Log level

To facilitate debugging secrets for the JwkSetSecretStore, in logback.xml add a logger defined by the fully qualified package name of the JwkSetSecretStore. The following line in logback.xml sets the log level to ALL:

<logger name="org.forgerock.secrets.jwkset" level="ALL">

Example

For an example of how to set up and use JwkSetSecretStore to validate signed access tokens, refer to Validate signed access_tokens with the StatelessAccessTokenResolver and JwkSetSecretStore.

In the following example, a StatelessAccessTokenResolver validates a signed access token by using a JwkSetSecretStore:

"accessTokenResolver": {
  "type": "StatelessAccessTokenResolver",
  "config": {
    "secretsProvider": {
      "type": "JwkSetSecretStore",
      "config": {
        "jwkUrl": "http://am.example.com:8088/openam/oauth2/connect/jwk_uri"
      },
      "issuer": "http://am.example.com:8088/openam/oauth2",
      "verificationSecretId": "verification.secret.id"
    }
  }
}

The JWT signature is validated as follows:

  • If the JWT contains a kid with a matching secret in the JWK set:

    • The secrets provider queries the JwkSetSecretStore for a named secret.

    • The JwkSetSecretStore returns the matching secret, identified by a stable ID.

    • The StatelessAccessTokenResolver tries to validate the signature with that named secret. If it fails, the token is considered as invalid.

    In the route, note that the property verificationSecretId must be configured but is not used in named secret resolution.

  • If the JWT contains a kid without a matching secret in the JWK set:

    • The secrets provider queries the JwkSetSecretStore for a named secret.

    • Because the referenced JWK set doesn’t contain a matching secret, named secret resolution fails. IG tries valid secret resolution in the same way as when the JWT doesn’t contain a kid.

  • If the JWT doesn’t contain a kid:

    • The secrets provider queries the JwkSetSecretStore for list of valid secrets, whose secret ID is verification.secret.id.

    • The JwkSetSecretStore returns all secrets in the JWK set whose purpose is signature verification. For example, signature verification keys can have the following JWK parameters:

      {
        "use": "sig"
      }
      {
        "key_opts": [ "verify" ]
      }

      Secrets are returned in the order that they are listed in the JWK set.

    • The StatelessAccessTokenResolver tries to validate the signature with each secret sequentially, starting with the first, and stopping when it succeeds.

    • If none of the valid secrets can verify the signature, the token is considered as invalid.

KeyStoreSecretStore

Manages a secret store for cryptographic keys and certificates, based on a standard Java keystore.

Legacy keystore types such as JKS and JCEKS are supported but are not secure. Consider using the PKCS#12 keystore type.

This Secret store can only manage secrets of the CryptoKey type.

The secrets provider queries the KeyStoreSecretStore for a named secret, identified by a secret ID and a stable ID, corresponding to the secret-id/aliases mapping. The KeyStoreSecretStore returns a secret that exactly matches the name, and whose purpose matches the secret ID and any purpose constraints.

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 Secrets.

Usage

{
  "name": string,
  "type": "KeyStoreSecretStore",
  "config": {
    "file": configuration expression<string>,
    "storeType": configuration expression<string>,
    "storePasswordSecretId": configuration expression<string>,
    "entryPasswordSecretId": configuration expression<string>,
    "secretsProvider": SecretsProvider reference,
    "mappings": [ object, ... ],
    "leaseExpiry": configuration expression<duration>,
    "autoRefresh": object,
    "storePassword": configuration expression<string>, //deprecated
    "keyEntryPassword": configuration expression<string> //deprecated
   }
}

Properties

"file": configuration expression<string>, required

The path to the KeyStore file.

"storeType": configuration expression<string>, optional

The secret store type.

Default: PKCS12

"storePasswordSecretId": configuration expression<secret-id>, optional

The secret ID of the password to access the KeyStore.

This secret ID must point to a GenericSecret.

IG searches for the value of the password until it finds it, first locally, then in parent routes, then in config.json.

To create a store password, add a file containing the password. The filename must corresponds to the secret ID, and the file content must contain only the password, with no trailing spaces or carriage returns.

Default: None; the KeyStore is not password-protected

"entryPasswordSecretId": configuration expression<secret-id>, optional

The secret ID of the password to access entries in the KeyStore.

This secret ID must point to a GenericSecret.

To create an entry password, add a file containing the password. The filename must correspond to the secret ID, and the file content must contain only the password, with no trailing spaces or carriage returns.

When this property is used, the password must be the same for all entries in the KeyStore. If the KeyStore uses different passwords for entries, entryPasswordSecretId doesn’t work.

Default: The value of storePasswordSecretId

"secretsProvider": SecretsProvider reference, optional

The SecretsProvider object to query for the keystore password and key entry password. For more information, see SecretsProvider.

Default: The route’s default secret service. For more information, see Default secrets object.

"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 if aliasesMatching is not used

One or more key aliases. Named aliases are mapped to the secret ID.

Use aliases or aliasesMatching but not both.

"aliasesMatching": array of <strings>, required if aliases 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 or aliasesMatching 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": [".*"]
  }
]
secretId: configuration expression<secret-id>, required

The ID of the secret used in your configuration.

aliases: array of configuration expression<strings>, required

One or more aliases for the secret ID. :leveloffset: +2

"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 or unlimited, IG issues a warning, and uses the default value.

Default: 5 minutes

"autoRefresh": object, optional

Automatically reload the KeystoreSecretStore when the keystore is edited or deleted.

{
  "enabled": configuration expression<boolean>,
  "executor": ScheduledExecutorService reference
}
enabled: configuration expression<boolean>, optional

Flag to enable or disable automatic reload:

  • true: Enable

  • false: Disable

Default: true

"executor": ScheduledExecutorService reference, optional

A ScheduledExecutorService to monitor the keystore.

Default: The default ScheduledExecutorService in the heap

"storePassword": configuration expression<secret-id>, required
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 KeyStore.

This secret ID must point to a GenericSecret.

IG searches for the value of the password until it finds it, first locally, then in parent routes, then in config.json.

To create a store password, add a file containing the password. The filename must corresponds to the secret ID, and the file content must contain only the password, with no trailing spaces or carriage returns.

"keyEntryPassword": configuration expression<secret-id>, optional
This property is deprecated; use the entryPasswordSecretId instead. For more information, refer to the Deprecated section of the Release Notes.

The secret ID of the password to access entries in the KeyStore.

This secret ID must point to a GenericSecret.

To create an entry password, add a file containing the password. The filename must correspond to the secret ID, and the file content must contain only the password, with no trailing spaces or carriage returns.

When this property is used, the password must be the same for all entries in the keystore. If the keystore uses different passwords for entries, keyEntryPassword doesn’t work.

Default: The value of storePassword

Log level

To facilitate debugging secrets for the KeyStoreSecretStore, in logback.xml add a logger defined by the fully qualified package name of the KeyStoreSecretStore. The following line in logback.xml sets the log level to ALL:

<logger name="org.forgerock.secrets.keystore" level="ALL">

Example

For examples of routes that use KeyStoreSecretStore, see the examples in JwtBuilderFilter.

In the following example, a StatelessAccessTokenResolver validates a signed access token by using a KeyStoreSecretStore:

"accessTokenResolver": {
  "type": "StatelessAccessTokenResolver",
  "config": {
    "secretsProvider": {
      "type": "KeyStoreSecretStore",
      "config": {
        "file": "IG_keystore.p12",
        "storeType": "PKCS12",
        "storePasswordSecretId": "keystore.secret.id",
        "entryPasswordSecretId": "keystore.secret.id",
        "mappings": [{
          "secretId": "verification.secret.id",
          "aliases": [ "verification.key.1", "verification.key.2" ]
        }]
      },
      "issuer": "http://am.example.com:8088/openam/oauth2",
      "verificationSecretId": "verification.secret.id"
    }
  }
}

The JWT signature is validated as follows:

  • If the JWT contains a kid with a mapped value, for example verification.key.1:

    • The secrets provider queries the KeyStoreSecretStore for a named secret with the secret ID verification.secret.id and the stable ID verification.key.1.

    • Because the KeyStoreSecretStore contains that mapping, the KeyStoreSecretStore returns a named secret.

    • The StatelessAccessTokenResolver tries to validate the JWT signature with the named secret. If it fails, the token is considered as invalid.

  • If the JWT contains a kid with an unmapped value, for example, verification.key.3:

    • The secrets provider queries the KeyStoreSecretStore for a named secret with the secret ID verification.secret.id and the stable ID verification.key.3.

    • Because the KeyStoreSecretStore doesn’t contain that mapping, named secret resolution fails. IG tries valid secret resolution in the same way as when the JWT doesn’t contain a kid.

  • If the JWT doesn’t contain a kid:

    • The secrets provider queries the KeyStoreSecretStore for all valid secrets, whose alias is mapped to the secret ID verification.secret.id. There are two valid secrets, with aliases verification.key.1 and verification.key.2.

    • The StatelessAccessTokenResolver first tries to verify the signature with verification.key.1. If that fails, it tries verification.key.2.

    • If neither of the valid secrets can verify the signature, the token is considered as invalid.

SystemAndEnvSecretStore

Manage a store of secrets from system properties and environment variables.

This secret store can manage secrets of both GenericSecret and CryptoKey types when used with dedicated formats.

A secret ID must conform to the convention described in secret-id. The reference is then transformed to match the environment variable name, as follows:

  • Periods (.) are converted to underscores.

  • Characters are transformed to uppercase.

For example, my.secret.id is transformed to MY_SECRET_ID.

The secrets provider queries the SystemAndEnvSecretStore for a named secret, identified by the name of a system property or environment variable. The SystemAndEnvSecretStore returns a secret that exactly matches the name.

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 Secrets.

Usage

{
  "name": string,
  "type": "SystemAndEnvSecretStore",
  "config": {
    "format": SecretPropertyFormat reference,
    "mappings": [ object, ... ],
    "leaseExpiry": configuration expression<duration>
    }
}

Properties

format: SecretPropertyFormat reference, optional

Format in which the secret is stored. Use one of the following values, or define a format:

  • BASE64: Base64-encoded

  • PLAIN: Plain text

Default: BASE64

"mappings": array of objects, optional

One or more mappings to define a secret:

secretId: configuration expression<secret-id>, required

The ID of the secret used in your configuration.

format: SecretPropertyFormat reference, required

The format and algorithm of the secret. Use SecretKeyPropertyFormat or PemPropertyFormat.

"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 or unlimited, IG issues a warning, and uses the default value.

Default: 5 minutes

Log level

To facilitate debugging secrets for the SystemAndEnvSecretStore, in logback.xml add a logger defined by the fully qualified package name of the property resolver. The following line in logback.xml sets the log level to ALL:

<logger name="org.forgerock.secrets.propertyresolver" level="ALL">

Example

For an example of how to uses a SystemAndEnvSecretStore to manage a password, see the example in Authenticate with SSO through the default authentication service

Secret property formats

PemPropertyFormat

The format of a secret used with a mappings configuration in FileSystemSecretStore and SystemAndEnvSecretStore. Privacy-Enhanced Mail (PEM) is a file format for storing and sending cryptographic keys, certificates, and other data, based on standards in Textual Encodings of PKIX, PKCS, and CMS Structures. By default, OpenSSL generates keys using the PEM format.

Encryption methods and ciphers used for PEM encryption must be supported by the Java Cryptography Extension.

PEM keys have the following format, where the PEM label is associated to the type of stored cryptographic material:

-----BEGIN {PEM label}-----
Base64-encoded cryptographic material
-----END {PEM label}-----
PEM Label Stored Cryptographic Material

CERTIFICATE

X.509 Certificate

PUBLIC KEY

X.509 SubjectPublicKeyInfo

PRIVATE KEY

PKCS#8 Private Key

ENCRYPTED PRIVATE KEY

Encrypted PKCS#8 Private Key

EC PRIVATE KEY

EC Private Key

RSA PRIVATE KEY

PKCS#1 RSA Private Key

RSA PUBLIC KEY

PKCS#1 RSA Public Keys

DSA PRIVATE KEY

PKCS#1-style DSA Private Key

HMAC SECRET KEY

HMAC Secret Keys

AES SECRET KEY

AES Secret Keys

GENERIC SECRET

Generic Secrets (passwords, API keys, etc)

Note the following points about the key formats:

  • PKCS#1 is the standard that defines RSA. For more information, refer to RFC 8017: RSA Public Key Syntax.

  • PKCS#1-style DSA and EC keys are not defined in any standard, but are adapted from the RSA format.

  • HMAC SECRET KEY, AES SECRET KEY, and GENERIC SECRET are a ForgeRock extension, and not currently supported by any other tools.

    The following example is non-standard PEM encoding of an HMAC symmetric secret key. The payload is base64-encoded random bytes that are the key material, with no extra encoding.

    -----BEGIN HMAC SECRET KEY-----
    Pj/Vel...thB0U=
    -----END HMAC SECRET KEY-----

    Run the following example command to create the key:

    cat <<EOF
    -----BEGIN HMAC SECRET KEY-----
    $(head -c32 /dev/urandom | base64)
    -----END HMAC SECRET KEY-----
    EOF

Usage

{
  "name": string,
  "type": "PemPropertyFormat",
  "config": {
   "decryptionSecretId": configuration expression<secret-id>,
   "secretsProvider": SecretsProvider reference
  }
}

Properties

"decryptionSecretId": configuration expression<secret-id>, optional

The secret ID for the secret to decrypt a PKCS#8 private key.

This secret ID must point to a GenericSecret.

"secretsProvider": SecretsProvider reference, required when decryptionSecretId is used

The SecretsProvider object to query for the decryption secret. For more information, see SecretsProvider.

SecretKeyPropertyFormat

The format of a secret used with a secret store.

Usage

{
  "name": string,
  "type": "SecretKeyPropertyFormat",
  "config": {
    "format": SecretPropertyFormat reference,
    "algorithm": configuration expression<string>
  }
}

Properties

format: SecretPropertyFormat reference, optional

Format in which the secret is stored. Use one of the following values, or define a format:

  • BASE64: Base64-encoded

  • PLAIN: Plain text

Default: BASE64

"algorithm": configuration expression<string>, required

The algorithm name used for encryption and decryption. Use algorithm names given in Java Security Standard Algorithm Names.

Example

{
  "type": "SecretKeyPropertyFormat",
  "config": {
    "format": "PLAIN",
    "algorithm": "AES"
  }
}

TLS specific elements

SecretsKeyManager

Uses the Commons Secrets API to manage keys that authenticate a TLS connection to a peer. The configuration references the keystore that holds the keys.

Usage

{
   "name": string,
   "type": "SecretsKeyManager",
   "config": {
     "signingSecretId": configuration expression<secret-id>,
     "secretsProvider": SecretsProvider reference
 }
}

Properties

"signingSecretId": configuration expression<secret-id>, required

The secret ID used to retrieve private signing keys.

This secret ID must point to a CryptoKey.

"secretsProvider": SecretsProvider reference, required

The SecretsProvider to query for secrets to resolve the private signing key. For more information, see SecretsProvider.

Example

The following example uses a private key found from a keystore for TLS handshake.

{
  "type": "SecretsKeyManager",
  "config": {
    "signingSecretId": "key.manager.secret.id",
    "secretsProvider": {
      "type": "KeyStoreSecretStore",
      "config": {
        "file": "path/to/certs/ig.example.com.p12",
        "storePasswordSecretId": "keystore.pass",
        "secretsProvider": "SecretsPasswords",
        "mappings": [{
          "secretId": "key.manager.secret.id",
          "aliases": [ "ig.example.com" ]
        }]
      }
    }
  }
}

SecretsTrustManager

Uses the Commons Secrets API to manage trust material that verifies the credentials presented by a peer. Trust material is usually public key certificates. The configuration references the secrets store that holds the trust material.

Usage

{
  "name": string,
  "type": "SecretsTrustManager",
  "config": {
    "verificationSecretId": configuration expression<secret-id>,
    "secretsProvider": SecretsProvider reference,
    "checkRevocation": configuration expression<boolean>
  }
}

Properties

"verificationSecretId": configuration expression<secret-id>, required

The secret ID to retrieve trusted certificates.

This secret ID must point to a CryptoKey.

"secretsProvider": SecretsProvider reference, required

The SecretsProvider to query for secrets to resolve trusted certificates. For more information, refer to SecretsProvider.

"checkRevocation": configuration expression<boolean>, optional

Specifies whether to check for certificate revocation.

Default: true

Example

The following example trusts a list of certificates found in a given keystore:

{
  "name": "SecretsTrustManager-1",
  "type": "SecretsTrustManager",
  "config": {
    "verificationSecretId": "trust.manager.secret.id",
    "secretsProvider": {
      "type": "KeyStoreSecretStore",
      "config": {
        "file": "path/to/certs/truststore.p12",
        "storePasswordSecretId": "keystore.pass",
        "secretsProvider": "SecretsPasswords",
        "mappings": [{
          "secretId": "trust.manager.secret.id",
          "aliases": [ "alias-of-trusted-cert-1", "alias-of-trusted-cert-2" ]
        }]
      }
    }
  }
}
Copyright © 2010-2023 ForgeRock, all rights reserved.