Skip to content

Credential Encryption

Accurids encrypts sensitive credential fields (endpoint passwords, API keys) at rest using AES-256-GCM. This protects stored secrets even if an attacker gains read access to the database.

Overview

When a master key is configured, all credential fields are encrypted before being written to the database. The ciphertext is stored as a prefixed string (v1:<keyId>:<iv>:<ct>) in the same varchar column — no schema changes are required beyond the initial migration.

When no master key is configured, credential fields are stored with a plain: prefix (unencrypted). A startup warning is emitted in this case.

Configuration

Variable Default Description
accurids.security.encryption.master-key (none) Primary encryption key. Any non-blank string (see Generating a key).
accurids.security.encryption.old-keys (empty) List of previous master keys retained for decryption during key rotation.
accurids.security.encryption.migrate-on-startup true Whether to automatically re-encrypt credentials with the current key on startup.
accurids.security.encryption.allow-downgrade false Whether startup migration may convert encrypted values to plaintext when no master key is set.

Generating a key

The master key can be any non-blank string — UUID, passphrase, hex, or base64. Internally, the key is run through HKDF-SHA256 (RFC 5869) to derive the actual 256-bit AES key, so no specific format or length is required.

For production use, generate a high-entropy value (at least 128 bits), e.g. by:

# Option 1: base64-encoded random bytes
openssl rand -base64 32

# Option 2: UUID
uuidgen

Important: Use the same master key on every node of a cluster. A mismatch will cause decryption failures.

Key rotation

To rotate the encryption key:

  1. Add the current key to old-keys — this ensures existing ciphertexts remain readable during the transition.
  2. Set the new key as master-key — new writes will use the new key immediately.
  3. Deploy to all nodes — the automatic startup migration re-encrypts all credentials with the new key (only one node in the cluster performs the migration).
  4. Remove the old key — once all nodes are running with the new key and the migration has completed, the old key can be removed from old-keys.

Example: rotating from key A to key B

Before rotation:

accurids.security.encryption.master-key: "key-A"

After rotation:

accurids.security.encryption.master-key: "key-B"
accurids.security.encryption.old-keys[0]: "key-A"

After migration completes (check logs for "Encryption key migration complete"):

accurids.security.encryption.master-key: "key-B"

Multiple old keys can be specified using indexed notation:

accurids.security.encryption.old-keys[0]: "key-A"
accurids.security.encryption.old-keys[1]: "key-Z"

Automatic startup migration

When migrate-on-startup is true (the default) and a master key is configured, Accurids checks all credential columns at application start. Any value not yet encrypted with the current key (including plain:-prefixed values and values encrypted with an old key) is decrypted and re-encrypted with the current key.

The migration:

  • Runs only once per cluster (coordinated via a cluster lock) — safe for multi-node deployments.
  • Is idempotent — rows already on the current key are skipped.
  • Handles individual row failures gracefully — a corrupt value is logged at WARN level but does not abort the migration of other rows.

Disabling migration

Set migrate-on-startup to false if you want to control when migration happens (e.g. in a maintenance window):

accurids.security.encryption.migrate-on-startup: false

Deploying encryption for the first time

If you are upgrading from a version of Accurids that did not have credential encryption, or if encryption was not enabled before, Accurids migrates all unencrypted credentials to ciphertext on the next boot.

No manual data migration is required.

Troubleshooting

Symptom Cause Resolution
Startup warning: "No master key configured" master-key is not set or blank Set the environment variable / config property
EncryptionException: key ID not recognised The credential was encrypted with a key that is not in master-key or old-keys Add the missing key to old-keys
EncryptionException: no handler recognises the prefix A bare string without plain: or v1: prefix Re-run the Flyway migration or manually prefix with plain:
Migration log shows failures Individual row has corrupt data Inspect the logged row ID and fix or re-set the credential manually