Skip to content

DynamoDB Key Source

The DynamoDB key source persists encrypted BLS validator private keys in a single DynamoDB table. Each key is encrypted with AES-256-GCM under a 256-bit master key; the master key itself never lives in plaintext on disk — it is reconstructed at unseal time from Shamir shares wrapped by AWS KMS.

This is one of three pluggable key sources: Filesystem, DynamoDB, and Memory.

  • AWS-native deployment with managed DynamoDB
  • Need durable key storage that survives signer restarts
  • Want multi-account custody — KMS keys across multiple AWS accounts, no single account holds the master key
  • Need runtime key generation (/api/v1/chamber/keys/generate) or import (/api/v1/chamber/keys)

For non-AWS deployments, prefer Filesystem with EIP-2335 keystores.

One DynamoDB table holds encrypted validator keys. Each row is keyed by validator public key and includes:

  • The encrypted BLS secret key.
  • An active or inactive status.
  • Timestamps.
  • An optional age-encrypted mnemonic backup for keys generated by the chamber.

The table also has a status-sharded index so startup and background refresh can load active keys in parallel.

key_sources:
dynamodb:
table: containment-keys
status_filter: [active]
refresh_interval_seconds: 1
max_concurrent_reads: 16
FieldDefaultDescription
tablerequiredDynamoDB table name for encrypted validator keys
status_filter["active"]Which key statuses to load into the signer
refresh_interval_seconds1Background reload interval. Set to 0 to disable refresh
max_concurrent_reads16Parallel read workers for startup and refresh loading

These knobs configure the storage only. The HTTP surface that reads from and writes to it (generate, import, list, patch, delete) has its own per-verb gating under chamber.keys.* — see Chamber Key Management.

Validator keys are encrypted under a single 256-bit master key. The master key itself is reconstructed during seal/unseal from KMS-wrapped Shamir shares and held only in memory.

The master-key metadata is not part of the key-source table. It lives in the state backend. The key-source table holds encrypted validator keys and optional mnemonic backups.

A working DynamoDB key source requires three independent subsystems, each with its own configuration root:

SubsystemConfig rootThis page covers?
Key source — encrypted validator keyskey_sources.dynamodbyes
State backend — master-key shares, ceremony, operator credentialssigner_state.*no, see State Backend
Anti-slashing — EIP-3076 slashing protection (any backend works)anti_slashing.*no, see Anti-Slashing

The three are independent. You can mix freely — DynamoDB key source + PostgreSQL anti-slashing + DynamoDB state backend is a perfectly valid configuration. The all-AWS pattern below picks DynamoDB for all three because it inherits managed durability for free.

When the DynamoDB key source is active, the chamber refuses to boot without a state backend configured (the master key has to live somewhere). A minimal valid config:

key_sources:
dynamodb:
table: containment-keys
signer_state:
backend: dynamodb
table: containment-state

Anti-slashing is independent — pick any backend (noop, sqlite, postgres, dynamodb) from the anti-slashing page. For an all-DynamoDB stack:

anti_slashing:
backend: dynamodb
table: containment-slashing

Three distinct tables — the chamber refuses to start if key_sources.dynamodb.table == signer_state.table or any pair collides.

The Shamir threshold can split across KMS keys in separate AWS accounts. A 2-of-3 setup means any two accounts can reconstruct the master key, but no single account holds enough material to do it alone — the strongest custody story the DynamoDB key source supports.

The KMS key ARNs and Shamir threshold are not in this config file. They are submitted once during the init ceremony via POST /api/v1/chamber/init and stored in the MASTER_KEY row of the state backend. See Seal & Unseal for the init flow.

For IAM setup, see AWS IAM Permissions. Ready-to-use Terraform examples live in terraform/examples/single-account/ and terraform/examples/multi-account/.

When chamber.keys.generate.backup.enabled = true, every key generated by POST /api/v1/chamber/keys/generate has its BIP-39 mnemonic encrypted with the configured age public keys and stored in the same DynamoDB row as the encrypted secret key. This is your last-resort recovery path that doesn’t depend on AWS:

chamber:
keys:
generate:
enabled: true
backup:
enabled: true
recipients:
- "age1..."

To recover a key when KMS is lost:

  1. Read encrypted_mnemonic from the DynamoDB row
  2. Decrypt with your age private key (stored offline)
  3. Re-derive the BLS keypair via EIP-2333
  4. Import into any compatible signer

The chamber.keys.generate.backup.recipients list MUST be non-empty when enabled = true, or the chamber refuses to start (validated by ChamberConfig::validate).

If fewer than the configured Shamir threshold of KMS keys are accessible, the signer cannot reconstruct the master key and will refuse to unseal. It logs a clear error indicating which KMS keys failed. If you cannot restore access to enough KMS keys, use the age backup to recover the mnemonics and re-import the keys.

Error: KMS Decrypt failed: AccessDeniedException

The signer’s IAM role lacks kms:Decrypt on one or more KMS keys. Check:

  1. The IAM role attached to the instance or pod has the correct policy
  2. The KMS key resource policy grants access to the role
  3. For cross-account: both the role’s policy AND the target KMS key’s resource policy grant access
Terminal window
aws kms describe-key --key-id arn:aws:kms:...

See AWS IAM Permissions for the full policy reference.

Error: Shamir reconstruction failed: insufficient shares

The signer needs at least the threshold’s worth of KMS keys. Check:

  1. Network connectivity to the KMS endpoints in each region (especially for cross-region multi-account setups)
  2. IAM access to every KMS key in the set, not just one

If you can’t restore access to enough KMS keys, use the age backup to recover the mnemonics and re-import the keys.

Error: ProvisionedThroughputExceededException

The DynamoDB table is throttled. Options:

  • Switch to PAY_PER_REQUEST billing mode (recommended for variable workloads)
  • Lower key_sources.dynamodb.max_concurrent_reads to reduce burst read load
  • Increase provisioned RCUs/WCUs if you must stay on provisioned billing
Error: Master key HMAC verification failed

The reconstructed master key did not match the stored hash. This means either:

  1. The KMS keys accessible to the signer differ from those used during init — for example, you rotated KMS keys without re-encrypting the Shamir shares
  2. The MASTER_KEY row was tampered with

Don’t proceed if the HMAC fails. Restore the original KMS keys, or use the age backup to recover and re-import keys against a fresh master key.

  • Chamber Key Management — generate, import, list, patch, delete endpoints
  • State Backend — where the master key, ceremony state, operator credentials, and auth policies live
  • Anti-Slashing — EIP-3076 slashing protection, independent of this key source
  • Seal & Unseal — init ceremony, KMS share rotation, operator quorum