KEK providers

A KEK provider wraps and unwraps data-encryption keys. CertAutoPilot ships two: env (software, KEK bytes in environment variables) and pkcs11 (hardware, KEK lives in a PKCS#11 HSM). The choice is made at install time and is immutable thereafter.

01Comparison

env (software)pkcs11 (HSM)
Where the KEK livesProcess memory + secrets.env / K8s SecretInside the HSM; never leaves
Operational complexityLowModerate — HSM client install, PIN management, vendor-specific flags
Rotation storyEdit env vars, rolling restart, kek rotateGenerate a new HSM key, rolling restart, kek rotate
Compliance postureGood (AES-256-GCM, versioned)Stronger — FIPS 140-2 / 140-3 Level 2 / 3 depending on HSM
Failure modes if the KEK is lostData unrecoverableData unrecoverable (HSM backup policy is on you)
Typical useSelf-hosted single-tenant, dev, pre-prodRegulated enterprise, multi-tenant, SOC 2 / PCI-DSS shops

02env provider

The simplest provider. Raw 32-byte KEK material is supplied via CERTAUTOPILOT_ENCRYPTION_ENV_KEK_V{N} (one env var per version). The backend loads every present version at startup and reads the kek_versions collection to decide which one is active for new writes — rotation flips that pointer via certautopilot kek rotate, no per-host env var change is involved.

Storage:

  • Standalone/etc/certautopilot/secrets.env, mode 0600, loaded by systemd via EnvironmentFile=.
  • Kubernetes — a Secret consumed via envFrom.secretRef, rendered either inline by the Helm chart or from an external Secret (SealedSecrets, External Secrets, Vault injector).

Key material generation:

openssl rand -hex 32

Always 64 hex chars = 32 bytes. Shorter values are rejected on startup.

Memory exposure

The KEK bytes live in the backend process's address space while it runs. A memory-dump attack (a root on the host, a core dump, a debugger) exposes them. Disable core dumps on the unit (LimitCORE=0), enable memory-write-exec protections (MemoryDenyWriteExecute=true — already set by the standalone unit), and keep host access tight.

03pkcs11 provider

The HSM provider never lets the KEK enter the backend's address space. CertAutoPilot dlopens the vendor's PKCS#11 library, logs into the token with the operator PIN, and invokes CKM_AES_GCM on key handles. The wrapped DEK and the nonce come back to the backend; the KEK stays in the HSM.

The provider stores only keystore metadata in MongoDB — the HSM key label / handle + version, never raw material. A mismatch between the config-declared provider and the kek_install record aborts startup.

Tested HSMs: SoftHSM2 (dev/CI), AWS CloudHSM, Thales Luna Network HSM. Any FIPS-approved HSM supporting CKM_AES_GCM should work — we run a capability probe before committing.

04The install lock

At install time, the chosen provider is written into a singleton MongoDB document kek_install. Every subsequent startup reads this document and refuses to run if the config-declared provider disagrees. This prevents a misconfigured restart from silently switching storage backends — a mistake that would tag fresh envelopes with a provider tag that cannot unwrap the old ones.

Switching providers on an already-provisioned system requires a fresh install + data re-import. See Provider migration.

05How to choose

Pick env if any of these hold:

  • You do not have an HSM.
  • You are not in a regulated vertical that requires one.
  • You want the smallest operational surface area.

Pick pkcs11 if any of these hold:

  • SOC 2 / PCI-DSS / HIPAA auditors will ask where the KEK lives.
  • Your security model treats backend memory dumps as a realistic threat.
  • You have an HSM already (CloudHSM, Luna, Fortanix) and want to consolidate root-of-trust on it.

You can start with env and move to pkcs11 later — but because the switch requires a fresh install, decide early where possible.

06Rotation within the same provider

Both providers support seamless rotation via certautopilot kek rotate. The flow is identical:

  1. Add a new version (new env var, or kek pkcs11-init --version=N+1).
  2. Roll the fleet so every process loads both versions.
  3. kek verify --target=N+1 confirms readiness.
  4. kek rotate --from-version=N --to-version=N+1 re-wraps every envelope. --from-version defaults to the keystore's active row but passing it explicitly keeps the intended transition unambiguous on the audit record.
  5. (Optional) kek remove --version=N retires the old version.

See KEK rotation.