Encrypt Secrets with the Cipher Tool
The Integration Control Plane (ICP) ships with a cipher tool that lets you encrypt sensitive configuration values (such as passwords, JWT signing secrets, and SSO client secrets) before storing them in deployment.toml. At startup, ICP decrypts these values automatically using the private key in its keystore.
Prerequisites
- Java (JDK 11 or later) must be installed and the
JAVA_HOMEenvironment variable must be set. - ICP must be installed. The cipher tool is located in the
bin/directory of your ICP installation.
Encryptable configuration fields
Only the following configuration keys in deployment.toml support encryption (use of any other key has no effect). You will replace each plaintext value with a $secret{alias} reference in a later step.
Fields stored under [icp_server.secrets]:
| Configuration key | Description |
|---|---|
keystorePassword | ICP keystore password |
truststorePassword | ICP truststore password |
frontendJwtHMACSecret | JWT HMAC secret for frontend authentication |
userServiceJwtHMACSecret | JWT HMAC secret for user service authentication |
ssoClientId | SSO (OIDC) client ID |
ssoClientSecret | SSO (OIDC) client secret |
observabilityJwtHMACSecret | JWT HMAC secret for the observability adapter |
observabilityTruststorePassword | Truststore password for observability connections |
opensearchUsername | OpenSearch username |
opensearchPassword | OpenSearch password |
credentialsDbUser | Credentials database username |
credentialsDbPassword | Credentials database password |
ldapConnectionPassword | LDAP connection (bind) password |
ldapTrustStorePassword | Truststore password for LDAP TLS connections |
Fields stored under [icp_server.storage.secrets]:
| Configuration key | Description |
|---|---|
dbUser | Primary database username |
dbPassword | Primary database password |
Step 1: Generate a keystore
Generate a new PKCS12 keystore using the Java keytool command:
The keystore generated by this command uses a self-signed certificate. For a keystore used solely for local secret encryption and decryption, this is functionally sufficient in production. However, if your organization's security policy or compliance requirements mandate CA-issued certificates, use a CA-backed keystore instead. If you already have a suitable keystore, skip this step.
keytool -genkeypair -alias <alias-name> -keyalg RSA -keysize 2048 -validity 3650 -storetype PKCS12 -keystore <your-keystore-name>.p12 -storepass <your-keystore-pwd> -keypass <your-key-pwd> -dname "CN=localhost, OU=Security, O=MyOrg, L=City, ST=State, C=US"
Replace the placeholders before running the command:
| Placeholder | Description |
|---|---|
<alias-name> | Name to identify the key inside the keystore |
<your-keystore-name> | Output filename for the .p12 file |
<your-keystore-pwd> | Password to open/access the keystore |
<your-key-pwd> | Password for the private key itself |
Replace all placeholders with your own values before running the command.
Step 2: Configure the cipher tool
The cipher tool and ICP support both PKCS12 (.p12) and JKS keystore types, with PKCS12 being the recommended format. Adjust the type values in the steps below to match your keystore format.
- Copy your keystore file into the
conf/security/directory of your ICP installation. - Open
conf/cipher-standalone-config.propertiesand update the following properties to point to your keystore:
primary.key.location=conf/security/<your-keystore-file>
primary.key.type=<keystore-type>
primary.key.alias=<alias-name>
| Property | Description |
|---|---|
primary.key.location | Path to the keystore file relative to the ICP installation directory |
primary.key.type | Keystore format: PKCS12 for .p12 files, JKS for Java Keystore files |
primary.key.alias | Alias used to identify the key entry inside the keystore |
These settings tell the cipher tool which keystore to use when encrypting values.
Step 3: Encrypt a secret
Run the cipher tool from the ICP installation directory:
Linux/macOS:
./bin/ciphertool.sh
Windows:
bin\ciphertool.bat
The tool loads the keystore, prompts for the keystore password and the plaintext value, then prints the encrypted ciphertext:
Encrypting using Primary KeyStore.
{type: <keystore-type>, alias: <alias-name>, path: conf/security/<your-keystore-file>}
[Please Enter Primary KeyStore Password of Carbon Server : ]
Primary KeyStore of Carbon Server is initialized Successfully
[Enter Plain Text Value : ]
[Please Enter Value Again : ]
Encryption is done Successfully
Encrypted value is :
...
Copy the encrypted value, as you will need it in the next step. Repeat this for every secret you want to encrypt.
Step 4: Update deployment.toml with ciphertext references
For each secret you encrypted, make two changes to conf/deployment.toml:
- Replace the plaintext value with a
$secret{alias}reference, wherealiasis the name you will use to identify this secret in the secrets table. - Add an entry to the appropriate secrets table (see below), using that same alias as the key and the ciphertext as the value.
The alias can be any descriptive name, but using the configuration key name as the alias is the clearest convention.
# Ciphertext references for server configurables
keystorePassword = "$secret{keystorePassword}"
ssoClientSecret = "$secret{ssoClientSecret}"
ldapConnectionPassword = "$secret{ldapConnectionPassword}"
# Ciphertexts for server configurables
[icp_server.secrets]
keystorePassword = "RIbyQ0Te..."
ssoClientSecret = "duNHb..."
ldapConnectionPassword = "P8/7g6rkGB..."
# Ciphertext references for database configurables
[icp_server.storage]
dbUser = "$secret{dbUser}"
dbPassword = "$secret{dbPassword}"
# Ciphertexts for database configurables
[icp_server.storage.secrets]
dbUser = "a1B4y5Z6..."
dbPassword = "ZH84B2a1..."
Every value in a secrets table must be a ciphertext produced by the cipher tool. ICP will fail to start if a plaintext value is found there.
Step 5: Point ICP to your keystore
Add the following block to conf/deployment.toml so that ICP uses your keystore to decrypt secrets at startup:
[icp_server.utils]
cipherKeystorePath = "<full-path-to-your-keystore-file>"
cipherKeystoreAlias = "<alias-name>"
cipherKeystorePassword = "<your-keystore-pwd>"
cipherPrivateKeyPassword = "<your-key-pwd>"
| Property | Description |
|---|---|
cipherKeystorePath | Full path to the keystore file |
cipherKeystoreAlias | Alias of the key entry inside the keystore |
cipherKeystorePassword | Password to open the keystore |
cipherPrivateKeyPassword | Password for the private key entry |
Alternatively, the keystore passwords can be provided as environment variables, which take precedence over the deployment.toml values:
export ICP_CIPHER_KEYSTORE_PASSWORD="<your-keystore-pwd>"
export ICP_PRIVATE_KEY_PASSWORD="<your-key-pwd>"
For simplicity, this guide points ICP to the same keystore used by the cipher tool in Step 2. This is not required: ICP can use a different keystore file, path, or alias, as long as it contains the same key pair. Secrets are encrypted with the public key, so ICP needs the matching private key to decrypt them. If the key pairs differ, ICP will fail to decrypt the secrets at startup.
How ICP decrypts secrets at startup
For each configuration field that contains a $secret{alias} reference, ICP retrieves the corresponding ciphertext from the secrets table, decrypts it using the private key in the cipher keystore, and uses the resulting plaintext value for the rest of the server lifetime. Decryption happens once during server startup.