---
title: Secret stores
description: Secret stores are repositories for cryptographic keys and credentials. IDM supports the following secret store types:
component: pingidm
version: 8.1
page_id: pingidm:security-guide:secret-stores
canonical_url: https://docs.pingidentity.com/pingidm/8.1/security-guide/secret-stores.html
keywords: ["Security", "Secret Stores", "Keystores", "Truststores", "Encryption", "Keys", "Hardware Security Modules (HSM)", "Mappings"]
page_aliases: ["configure-secrets.adoc"]
section_ids:
  configure_secret_stores: Configure secret stores
  secret-mappings: Mapping secretIDs to key aliases
  secret-rotation-email: Configure email service secret rotation
  store_password_as_secret: Store password as secret
  store-user-pass-as-secret: Store username and password as a secret
  secret-rotation-connectors: Configure secret rotation for connectors
  store_the_credentials_as_a_secret: Store the credentials as a secret
  store_the_principal_and_credentials_as_a_secret: Store the principal and credentials as a secret
  secret-rotation-rsfilter: Store rsFilter client secret as a secret
  secret-rotation-hikari: Rotate Hikari credentials
  configure_whole_account_rotation: Configure whole account rotation
  configure_password_rotation: Configure password rotation
  secret-rotation-prometheus: Store Prometheus credentials as a secret
  rotate_prometheus_credentials: Rotate Prometheus credentials
  proxy-secret-rotation: Configure proxy secret rotation
  default_proxy_credentials: Default proxy credentials
  external_service_proxy_credentials: External service proxy credentials
  rotate_proxy_credentials: Rotate proxy credentials
---

# Secret stores

Secret stores are repositories for cryptographic keys and credentials. IDM supports the following secret store types:

* *File* secret stores, which have one file that stores many secrets

* *Filesystem* secret stores, which have many files that each store one secret

* *Property* secret stores, which store secrets in properties

* *Hardware Security Module* (HSM) secret stores, which involve security devices (for example, a YubiKey)

## Configure secret stores

You can configure secret stores in your project's `conf/secrets.json` file, which has the following default configuration:

```json
{
    "stores" : [
        {
            "name" : "mainKeyStore",
            "class" : "org.forgerock.openidm.secrets.config.KeyStoreSecretStore",
            "config" : {
                "file" : "&{idm.data.dir}/security/keystore.jceks",
                "storetype" : "JCEKS",
                "providerName" : "SunJCE",
                "storePassword" : "changeit",
                "mappings" : [
                    {
                        "secretId" : "decrypt",
                        "aliases" : [
                            "openidm-sym-default"
                        ],
                        "types" : [
                            "ENCRYPT",
                            "DECRYPT"
                        ]
                    }
                ]
            }
        },
        {
            "name" : "mainTrustStore",
            "class" : "org.forgerock.openidm.secrets.config.KeyStoreSecretStore",
            "config" : {
                "file" : "&{idm.data.dir}/security/truststore",
                "storetype" : "JKS",
                "providerName" : "SUN",
                "storePassword" : "changeit",
                "mappings" : [
                    {
                        "secretId" : "sign",
                        "aliases" : [
                            "server-cert"
                        ],
                        "types" : [
                            "SIGN"
                        ]
                    }
                ]
            }
        }
    ],
    "populateDefaults" : true
}
```

The `mainKeyStore` and `mainTrustStore` properties configure the default secret stores. IDM requires these properties in order to start up. Do not change the property names because they are also provided to third-party products that need a single keystore and a single truststore.

* `mainKeyStore`

  The main keystore references a Java Cryptography Extension Keystore (JCEKS) located at `/path/to/openidm/security/keystore.jceks`.

* `mainTrustStore`

  The main truststore references a file-based truststore located at `/path/to/openidm/security/truststore`.

You can manage these keystores and truststores using the `keytool` command, included in your Java installation. Learn more about the [`keytool` command](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html).

Each configured store has a `name` and `class`, and the following configuration properties:

* `file`

  For file-based secret stores, this property references the path to the store file, for example, `&{idm.install.dir}/security/keystore.jceks}`. Hardware security modules do not have a `file` property.

* `storetype`

  The type of secret store. IDM supports a number of store types, including JCEKS, JKS, PKCS #11, and PKCS #12.

* `providerName`

  Sets the name of the cryptographic service provider; for example, `SunPKCS11` or `softHSM`. If no provider is specified, the JRE default is used.

* `storePassword`

  The password to the secret store. For the default IDM keystore and truststore, the password is `changeit`. You should change this password in a production deployment, as described in [Changing the default keystore password](stores-certs-keys.html#security-keystore-password).

* `mappings`

  This object lets you map keys and certificates in the secret stores to functionality in IDM. A secrets mapping object has the following structure:

  ```json
  {
      "secretId" : "idm.config.encryption",
      "types": [ "ENCRYPT", "DECRYPT" ],
      "aliases": [ "&{openidm.config.crypto.alias|openidm-sym-default}" ]
  }
  ```

  * `secretId` is the name of the secret. The `secretId` should indicate the purpose that the secret should be used for. For example, `idm.config.encryption` indicates that the mapping is used to encrypt and decrypt sensitive configuration properties, while `idm.password.encryption` indicates that the mapping is used to encrypt and decrypt passwords.

  * `types` indicates what the keys are used for. The supported types are:

    | Type      | Definition                              |
    | --------- | --------------------------------------- |
    | `GENERIC` | Used for credentials, such as passwords |
    | `ENCRYPT` | Used to encrypt data                    |
    | `DECRYPT` | Used to decrypt data                    |
    | `SIGN`    | Used to sign data                       |
    | `VERIFY`  | Used to verify data                     |

  * `aliases` are the key aliases in the secret store that are used for this purpose. You can add as many aliases as necessary. The first alias in the list determines which alias is the active one. Active secrets are used for signature generation and encryption.

    The aliases in the default keystore are described in [The IDM keystore](default-keystore.html).

  The default secret IDs and the aliases they are mapped to are listed in [Mapping secretIDs to key aliases](#secret-mappings).

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | All these properties have a resolvable property value by default; for example `&{openidm.keystore.location}`, that allows you to use *property value substitution*. If no *configuration expression* has been set for a specific property, the value following the vertical bar (`\|`) is used. In the following property, the password is `changeit` unless you have set a configuration expression in one of the property resolver locations:```properties
"storePassword": "&{openidm.keystore.password|changeit}"
```For more information, refer to [Property value substitution](../setup-guide/using-property-substitution.html). |

## Mapping secretIDs to key aliases

The following table describes the default secrets and their alias mappings:

| `secretId`                                                         | `alias`                                                                                                                                               | Description                                                                                                | Supported `types`    |
| ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------- |
| `idm.default`                                                      | `openidm-sym-default`                                                                                                                                 | Encryption keystore for legacy JSON objects that do not contain a `purpose` value in their `$crypto` block | `ENCRYPT`, `DECRYPT` |
| `idm.config.encryption`                                            | `openidm-sym-default`                                                                                                                                 | Encrypts configuration information                                                                         | `ENCRYPT`, `DECRYPT` |
| `idm.password.encryption`                                          | `openidm-sym-default`                                                                                                                                 | Encrypts managed user passwords                                                                            | `ENCRYPT`, `DECRYPT` |
| `idm.jwt.session.module.encryption`                                | `openidm-localhost`                                                                                                                                   | Encrypts JWT session tokens                                                                                | `ENCRYPT`, `DECRYPT` |
| `idm.jwt.session.module.signing`                                   | `openidm-jwtsessionhmac-key`                                                                                                                          | Signs JWT session tokens using HMAC                                                                        | `SIGN`, `VERIFY`     |
| `idm.assignment.attribute.encryption`                              | `openidm-sym-default`                                                                                                                                 | Encrypts confidential assignment attributes                                                                | `ENCRYPT`, `DECRYPT` |
| `idm.rs.filter.client.secret`                                      | `rsFilter/clientSecret` field in `authentication.json`	You can use a secret to contain this value. Refer to Store rsFilter client secret as a secret. | The `rsFilter` `client_secret`                                                                             | `GENERIC`            |
| `idm.prometheus.password`[\*](#deprecated-prometheus-footnote)     | `openidm.prometheus.password`[\*](#deprecated-prometheus-footnote) property in `boot.properties`                                                      | The password for Prometheus                                                                                | `GENERIC`            |
| `idm.workflow.email.password`                                      | `mail/password` property in `workflow.json`                                                                                                           | The password for Workflow emails                                                                           | `GENERIC`            |
| `idm.http.client.proxy.password`[\*\*](#deprecated-proxy-footnote) | `openidm.http.client.proxy.password`[\*\*](#deprecated-proxy-footnote) property in `boot.properties`                                                  | The password for the default HTTP client proxy                                                             | `GENERIC`            |

\* []()The `idm.prometheus.password` purpose and `openidm.prometheus.password` property are [deprecated](../release-notes/deprecated-functionality.html#deprecation-prometheus-properties-purpose).

\*\* []()The `idm.http.client.proxy.password` purpose and `openidm.http.client.proxy.password` property are [deprecated](../release-notes/deprecated-functionality.html#deprecation-proxy-properties-purpose).

## Configure email service secret rotation

You can store the basic auth credentials for the email service using purposes. You can store both the username and password or just the password.

### Store password as secret

To store the email service password credential as a secret:

1. Configure a purpose called `idm.basic.auth.email` in your `conf/secrets.json` file. The purpose must resolve to the password for the basic auth connection to the email service. For example:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "idm.basic.auth.email",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

2. In the `auth` settings of your email configuration *(tooltip: You can edit the email service over REST at the config/external.email endpoint, or in the external.email.json file in your project's conf directory.)*, update the `password` value to use the purpose:

   ```json
   {
     ...
     "auth" : {
           "enable" : true,
           "username" : "example",
           "password": {
             "$purpose" : {
               "name" : "idm.basic.auth.email"
             }
           }
     },
     ...
   }
   ```

### Store username and password as a secret

To store the username and password as a secret:

1. Configure a purpose called `idm.basic.auth.email` in your `conf/secrets.json` file:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "idm.basic.auth.email",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

   The purpose must resolve to a JSON object with two fields, `username` and `password`:

   ```json
   {
     "username" : "exampleUsername",
     "password" : "changeit"
   }
   ```

2. In the `auth` settings of your email configuration *(tooltip: You can edit the email service over REST at the config/external.email endpoint, or in the external.email.json file in your project's conf directory.)*, update the `username` and `password` values to use the purpose. You must supply a `jsonPointer` value that indicates the property name in the secret's JSON structure. For example:

   ```json
   {
     ...
     "auth" : {
       "enable" : true,
       "username" : {
         "$purpose" : {
           "name" : "idm.basic.auth.email",
           "jsonPointer" : "/username"
           }
         },
         "password" : {
           "$purpose" : {
           "name" : "idm.basic.auth.email",
           "jsonPointer" : "/password"
           }
         }
     },
     ...
   }
   ```

## Configure secret rotation for connectors

Connectors that support encrypted credentials support storing them in a secret. You can store the `principal` and `credentials`, or just the `credentials`.

### Store the credentials as a secret

1. Configure a purpose called `icf.ldap.credentials` in your `conf/secrets.json` file. The purpose must resolve to the connector's `credentials` value:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "icf.ldap.credentials",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

2. In the `configurationProperties` property of the connector's provisioner file, update the `credentials` value to use the new secret:

   ```json
   {
   ...
     "credentials" : {
       "$purpose": {
         "name": "icf.ldap.credentials"
       }
     },
   ...
   }
   ```

### Store the principal and credentials as a secret

The following procedure demonstrates how to store the LDAP connector's `principal` and `credentials` in a file system based secret store:

1. Configure a purpose called `icf.ldap.credentials` in your `conf/secrets.json` file:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "icf.ldap.credentials",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

   The purpose must resolve to a JSON object with two fields, `principal` and `secret`:

   ```json
   {
     "principal" : "uid=admin",
     "secret" : "changeit"
   }
   ```

2. In the `configurationProperties` property of the connector's provisioner file, update the `principal` and `credentials` values to use the new purpose. You must supply a `jsonPointer` value that indicates the property name in the secret's JSON structure. For example:

   ```json
   {
     ...
     "configurationProperties" : {
       "principal" :  {
         "$purpose": {
           "name": "icf.ldap.credentials",
           "jsonPointer": "/principal"
           }
         },
       "credentials" : {
         "$purpose": {
           "name": "icf.ldap.credentials",
           "jsonPointer": "/secret"
         }
       }
     }
     ...
   }
   ```

If you change the value of the secret after the initial configuration, you must call the `reloadSecrets` connector action on the connector to complete the update:

```
curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Accept-API-Version: resource=1.0" \
--request POST \
--header "content-type: application/json" \
--data '' \
"http://localhost:8080/openidm/system/ldap?_action=reloadSecrets"
{
    "status": "ok"
}
```

## Store rsFilter client secret as a secret

You can use a secret to store the rsFilter's client secret:

1. Remove the `rsFilter/clientSecret` field from `conf/authentication.json`.

2. In `conf/secrets.json`, define a purpose called `idm.rs.filter.client.secret`. This example shows how to do this using a filesystem secret store:

   ```json
   {
     "name":"secretVolume",
     "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
     "config": {
       "format": "PLAIN",
       "directory": "&{idm.install.dir}/secrets",
       "mappings": [{
           "secretId": "idm.rs.filter.client.secret",
           "types": [
             "GENERIC"
           ]
         }
       ]
     }
   }
   ```

3. Ensure that secret's value resolves to the client secret of the OAuth2 client in PingAM.

## Rotate Hikari credentials

You can store the credentials for the Hikari connection pooling datasource using purposes. This lets you enable whole account or password rotation, depending on your needs.

Credentials are rotated when the existing threads in Hikari expire and new ones are spawned. You can set the time-to-live in your configuration by adding a `maxLifetime` property to the `connectionPool` object. The value of `maxLifetime` should be an integer with a minimum value of `30000`. If `maxLifetime` is set to `0`, credentials will never rotate.

|   |                                                                                                                               |
| - | ----------------------------------------------------------------------------------------------------------------------------- |
|   | If an account lockout mechanism is configured, ensure that the lockout threshold is greater than the number of IDM instances. |

### Configure whole account rotation

To enable whole account rotation, update `conf/datasource.jdbc-default.json` to read `username` and `password` from a purpose. The following procedure demonstrates how to do this using a file system based secret store:

1. Configure a purpose called, for example, `jdbc.hikari.credentials` in your `conf/secrets.json` file:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "jdbc.hikari.credentials",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

   The purpose must resolve to a JSON object with two fields, here called `username` and `password`:

   ```json
   {
     "username": "example-admin",
     "password": "changeit"
   }
   ```

2. In `conf/datasource.jdbc-default.json`, update the `username` and `password` definitions to resolve to the value provided by your purpose. You must supply a `jsonPointer` value that indicates the property name in the secret's JSON structure. For example:

   ```json
   {
       "driverClass" : "org.postgresql.Driver",
       "jdbcUrl" : "jdbc:postgresql://&{openidm.repo.host}:&{openidm.repo.port}/openidm",
       "databaseName" : "openidm",
       "username" : {
           "$purpose" : {
               "name" : "jdbc.hikari.credentials",
               "jsonPointer" : "/username"
           }
       },
       "password" : {
           "$purpose" : {
               "name" : "jdbc.hikari.credentials",
               "jsonPointer" : "/password"
           }
       },
       "connectionTimeout" : 30000,
       "connectionPool" : {
           "type" : "hikari",
           "minimumIdle" : 20,
           "maximumPoolSize" : 50
       }
   }
   ```

### Configure password rotation

To enable password rotation, update `conf/datasource.jdbc-default.json` to read `password` from a purpose. The following procedure demonstrates how to do this using a file system based secret store:

1. Configure a purpose called, for example, `jdbc.hikari.password` in your `conf/secrets.json` file:

   ```json
   {
       "name":"secretVolume",
       "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
       "config": {
           "format": "PLAIN",
           "directory": "&{idm.install.dir}/secrets",
           "mappings": [
             {
               "secretId": "jdbc.hikari.password",
               "types": [
                 "GENERIC"
               ]
             }
           ]
       }
   }
   ```

2. In `conf/datasource.jdbc-default.json`, update the `password` definition to resolve to the value provided by your purpose. For example:

   ```json
   {
       "driverClass" : "org.postgresql.Driver",
       "jdbcUrl" : "jdbc:postgresql://&{openidm.repo.host}:&{openidm.repo.port}/openidm",
       "databaseName" : "openidm",
       "username" : "openidm",
       "password" : {
           "$purpose" : {
               "name" : "jdbc.hikari.password"
           }
       },
       "connectionTimeout" : 30000,
       "connectionPool" : {
           "type" : "hikari",
           "minimumIdle" : 20,
           "maximumPoolSize" : 50
       }
   }
   ```

## Store Prometheus credentials as a secret

You can use the `idm.prometheus.credentials` well-defined purpose to store your Prometheus credentials:

1. Remove `openidm.prometheus.password` and `openidm.prometheus.username` from `resolver/boot.properties`.

2. In `conf/secrets.json`, define a versioned file system secret store for the `idm.prometheus.credentials` purpose. For example:

   ```json
   {
     "name": "fileSystemStore",
     "class": "org.forgerock.openidm.secrets.config.FileSystemStore",
     "config": {
       "versionSuffix": ".v",
       "directory":"&{idm.install.dir}/secrets",
       "format":"PLAIN",
       "mappings":[
         {
           "secretId":"idm.prometheus.credentials",
           "types":["GENERIC"]
         }
       ]
     }
   }
   ```

3. In the `/secrets` directory, create the `idm.prometheus.credentials.v1` file storing the initial Prometheus username and password:

   ```json
   {
     "username": "prometheus",
     "password":"prometheus1"
   }
   ```

### Rotate Prometheus credentials

1. In `conf/metrics.json`, configure metrics collection by setting `enabled: true`. For more information on configuring Prometheus metrics, refer to [Enable metrics](../monitoring-guide/monitoring.html#enable-metrics).

2. Start IDM.

3. Verify that the Prometheus endpoint is up and can be accessed with the initial password. For more information on verifying the Prometheus endpoint, refer to [Enable metrics](../monitoring-guide/monitoring.html#enable-metrics).

4. In the `/secrets` directory, create the `idm.prometheus.credentials.v2` file storing a new password:

   ```json
   {
     "username": "prometheus",
     "password":"prometheus2"
   }
   ```

5. Verify that the Prometheus endpoint can be accessed with both the initial and new password. The new password may require a few seconds before activating. For more information on verifying the Prometheus endpoint, refer to [Enable metrics](../monitoring-guide/monitoring.html#enable-metrics).

6. Delete `secrets/idm.prometheus.credentials.v1`.

7. Verify that the Prometheus endpoint can be accessed only with the `v2` password. The old password could require a few seconds before deactivating. Learn more about verifying the Prometheus endpoint in [Enable metrics](../monitoring-guide/monitoring.html#enable-metrics).

## Configure proxy secret rotation

You can configure proxies in IDM in two ways:

* The default proxy settings use a combination of system properties and specific secret purposes.

* External services, such as email, REST connectors, and connections between IDM instances, allow direct proxy configuration within their JSON files. These settings override the default proxy configuration when specified.

### Default proxy credentials

IDM provides two ways to handle credentials for the default proxy configuration:

* `idm.http.client.proxy.credentials`: The recommended purpose for managing default proxy credentials. It resolves to a JSON object containing both the username and password.

* `idm.http.client.proxy.password`: A [deprecated](../release-notes/deprecated-functionality.html#deprecation-proxy-properties-purpose) purpose that resolves only to the proxy password. You should migrate away from using this purpose.

The secret referenced by the `idm.http.client.proxy.credentials` purpose should contain a JSON object like this:

```json
{
  "username": "<proxy_username>",
  "password": "<proxy_password>"
}
```

Replace `<proxy_username>` and `<proxy_password>` with the actual credentials for your proxy server.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | To use the `idm.http.client.proxy.credentials` purpose:- Ensure the corresponding system property `openidm.http.client.proxy.password` is **not** set in your `boot.properties` file.

- Ensure no secret value is defined for the deprecated `idm.http.client.proxy.password` purpose in your `secrets.json` file.Using `idm.http.client.proxy.credentials` allows you to manage the username and password together as a single secret. |

### External service proxy credentials

You can configure proxy credentials for specific external services that offer a `proxy` configuration block in their JSON files, for example, `external.rest.json`.

Set the `proxy.userName` and `proxy.password` fields to reference a secret containing a credential pair:

```json
"proxy": {
    "proxyUri": "http://your-proxy.example.com:8888",
    "userName": {
        "$purpose": {
            "name": "idm.external.proxy.credentials",
            "jsonPointer": "/username"
        }
    },
    "password": {
        "$purpose": {
            "name": "idm.external.proxy.credentials",
            "jsonPointer": "/password"
        }
    }
}
```

The `name` must match the `secretId` you defined in your `conf/secrets.json` file for these external proxy credentials.

The `jsonPointer` values (`/username` and `/password` in this example) must correspond to the keys used within the JSON secret object stored for the `idm.external.proxy.credentials` purpose.

### Rotate proxy credentials

To rotate the credentials IDM uses to authenticate with a proxy:

* If using a non-versioned secret store, such as a plain file system store, update the content of the secret file or value.

* If using a versioned secret store, such as a versioned file system store, add a new version of the secret (for example, add a `.v2` file).

|   |                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------- |
|   | For zero-downtime rotation, your proxy must support multiple user accounts simultaneously during the transition. |

The general steps for zero-downtime rotation are:

1. Add the new user account credentials to your proxy configuration, keeping the old ones active for now.

2. Update the secret value in IDM to use the new account details, either by modifying the existing secret file, value, or adding a new version. IDM will start using the new credentials as connections are refreshed or new versions are picked up.

3. After confirming IDM is using the new credentials, you can safely remove the old user account from the proxy configuration.
