Architecture Overview
Containment Chamber is an Ethereum remote signer designed to protect validator keys while remaining compatible with existing Web3Signer clients. It can run as a standard Linux process or inside an AWS Nitro Enclave, where decrypted validator keys and reconstructed master-key material stay inside enclave memory. Every signing request is checked against authorization rules, network boundaries, and EIP-3076 slashing protection before a BLS signature is produced.
It has two deployment modes:
- Standard mode — runs as a normal Linux process or container. This is the direct Web3Signer replacement path for bare metal, Docker, Kubernetes, and conventional TLS deployments.
- Nitro Enclave mode — runs the signer inside an AWS Nitro Enclave. The parent EC2/Kubernetes pod only forwards bytes over vsock; decrypted validator keys and the reconstructed master key stay inside enclave memory. aTLS lets clients verify the enclave measurements before sending signing or operator traffic.
The signing pipeline is intentionally the same in both modes: backpressure, auth policy evaluation, network guard, anti-slashing, BLS signing, and key lookup. Nitro changes the trust boundary around that pipeline.
Standard Mode
Section titled “Standard Mode”
Standard mode exposes the Web3Signer-compatible API directly over HTTP or file-based TLS. Validator clients send signing requests to Containment Chamber, which routes them through:
- Backpressure — load shedding, concurrency limits, and timeouts protect the runtime under overload.
- Auth policy evaluation — HMAC-hashed tokens are checked against route scope, validator key, and signing operation.
- EthereumSigner — the network guard rejects wrong-genesis requests, anti-slashing runs before every signature, and BLS signing only proceeds after the key lookup succeeds.
- Key sources — filesystem and DynamoDB load keys at boot; DynamoDB can refresh keys; Key Manager API imports are memory-only runtime key imports.
- Anti-slashing backends — PostgreSQL, SQLite, or DynamoDB provide
check_and_update()before signing.
This is the lowest-friction path when the host is already trusted enough to hold decrypted validator keys in process memory.
Nitro Enclave Mode
Section titled “Nitro Enclave Mode”
Nitro mode wraps the same signer pipeline in a stricter trust boundary:
- The EC2 parent instance / Kubernetes pod is untrusted. It runs
nitro-cli, ingressenclave-proxy, egressvsock-proxyprocesses, config bootstrap, credentials bridge, and log forwarding. - The Nitro Enclave is trusted. It runs
containment-chamber --features nitro, owns the NSM handle, serves aTLS over vsock, reconstructs the master key, decrypts validator keys, and performs signing. - aTLS is mandatory when
tee.platform: nitrois enabled. The enclave generates an ephemeral TLS key, binds its SPKI hash into an NSM attestation document, and embeds that document in the X.509 certificate. - KMS decrypts are attested.
AttestedKmsClientsends an NSM attestation document as KMSRecipientInfo; KMS returns a CMS envelope encrypted to an enclave-generated RSA key, and plaintext is recovered only inside the enclave. - Outbound AWS/database access is explicit. DynamoDB, KMS, STS/Pod Identity, and optional PostgreSQL/RDS traffic goes through configured vsock egress endpoints while preserving end-to-end TLS.
Nitro mode is the differentiated deployment path versus Web3Signer: a compromised parent host can observe traffic timing and move bytes, but cannot read enclave memory, plaintext validator keys, the reconstructed master key, or KMS plaintext shares. See Nitro Enclave Overview for the full deployment model.
Signing Path
Section titled “Signing Path”The signing path is the same in Standard and Nitro Enclave mode:
- The validator client sends a Web3Signer-compatible signing request.
- Backpressure and timeouts reject overload before work is accepted.
- Auth policies decide whether the caller may use the route, key, and signing operation.
- The network guard rejects requests for the wrong genesis validators root.
- Anti-slashing checks run before every signature.
- BLS signing happens only after the key is found and all checks pass.
Nitro changes where this path runs, not what the path does. In Nitro mode, the parent instance forwards traffic over vsock while the signing path executes inside the enclave.
Key Sources
Section titled “Key Sources”Every validator BLS keypair in memory is tagged with one of three sources: Filesystem, DynamoDB, or Memory. The taxonomy distinguishes how the key got there, not where it is now.
Boot-time backends
Section titled “Boot-time backends”Two configured backends load keys when the signer starts:
-
Filesystem (
KeySource::Filesystem) — Web3Signer-compatible EIP-2335 keystores with local password files, or raw hex files, read from one or more directories. Read-only. No background refresh. -
DynamoDB + KMS (
KeySource::Dynamodb) — Keys stored in DynamoDB, encrypted with AES-256-GCM under a master key protected by Shamir secret sharing across multiple AWS KMS keys (M-of-N threshold). Loaded at boot, then refreshed by a supervised background task on a configurable interval. Also writable at runtime through the Chamber Key Management API below.
Runtime key import
Section titled “Runtime key import”Keys can also be added after startup through HTTP APIs. Runtime imports can either stay memory-only or be persisted to DynamoDB:
-
Key Manager API (
POST /eth/v1/keystores) — Web3Signer-compatible import for EIP-2335 keystores. These keys are memory-only and vanish on restart. Validator-client-facing. Gated byhttp.key_manager_api.enabled. -
Chamber Key API (
POST /api/v1/chamber/keys) — operator-facing import for raw keys or keystores. Withstorage.persist=false, keys are memory-only and produceKeySource::Memory. Withstorage.persist=true, keys are encrypted, written to DynamoDB, and produceKeySource::Dynamodb.
Chamber Key Management API
Section titled “Chamber Key Management API”A separate operator-facing surface tied to the DynamoDB key source:
POST /api/v1/chamber/keys/generate— derive new validator keys (BIP-39 mnemonic → EIP-2333 → BLS), optionally back up the mnemonic age-encrypted to one or more public keys.POST /api/v1/chamber/keys— import existing keystores or raw hex keys (persistent or memory-only).GET /api/v1/chamber/keys— list with status filter (always mounted when DynamoDB is configured).PATCH /api/v1/chamber/keys— activate or deactivate keys in-place.DELETE /api/v1/chamber/keys— delete from DynamoDB and the in-memory cache.
Each verb is gated by its own flag: chamber.keys.{generate, import, lifecycle}.enabled. List is always mounted. See DynamoDB + KMS for the full surface and request shapes.
Collision precedence
Section titled “Collision precedence”When the same pubkey arrives from more than one source, first loaded wins. Boot-time backends load in registration order (filesystem before dynamodb), so a filesystem-supplied key shadows a same-pubkey DynamoDB key. Runtime imports against an already-loaded pubkey are reported back to the caller as Duplicate (HTTP 200 with per-key status) and the original entry is preserved untouched.
Seal/Unseal State Machine
Section titled “Seal/Unseal State Machine”When the DynamoDB key source is configured, the signer operates a 6-state seal machine that controls whether signing is permitted. The master key only exists in memory during the Unsealed and AwaitingRotation states — all other states reject signing requests.
The six states are: Uninitialized, AwaitingRegistration, Sealed, KmsUnsealed, Unsealed, and AwaitingRotation. Transitions are driven by operator actions (init ceremony, unseal share submissions, seal commands) and by the signer itself (KMS auto-unseal, threshold reached, rotation complete).
Filesystem-only deployments bypass the seal machine entirely. The state machine only activates when key_sources.dynamodb is configured.
For the full state diagram, transition rules, and operational procedures, see Seal & Unseal.
TLS and Attestation TLS
Section titled “TLS and Attestation TLS”When TLS is configured, the signer runs a second listener on port 9443 (HTTPS) alongside the main HTTP listener on port 9000. Both listeners serve all API routes. The HTTP listener stays up for health probes and Prometheus scraping — those don’t need TLS.
File mode reads a PEM certificate and private key from disk and reloads them on a configurable poll interval. It works with any PKI: self-signed certs, Let’s Encrypt, cert-manager, or Vault PKI. Cert rotation happens without a restart.
aTLS mode (attestation TLS) generates an ephemeral X.509 certificate and binds its public key hash (SPKI) into an NSM attestation document embedded in the cert’s X.509 extension. This gives connecting clients cryptographic proof that:
- The server is running in a genuine AWS Nitro Enclave
- The enclave contains the expected binary, verified by PCR measurements
- The TLS session goes to that specific attested enclave — not an interceptor
Certs rotate automatically every rotation_interval_seconds. Active sessions complete on the old cert; new connections receive the fresh one. No restart needed.
The TOFU model (Trust On First Use): the first connection records the enclave’s PCR measurements. Future connections reject certificates from enclaves with different PCR values, even if those certs carry valid attestations from a different binary.
For setup instructions and the dual-listener port layout, see Attested TLS.