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.
Comparison
env (software) | pkcs11 (HSM) | |
|---|---|---|
| Where the KEK lives | Process memory + secrets.env / K8s Secret | Inside the HSM; never leaves |
| Operational complexity | Low | Moderate — HSM client install, PIN management, vendor-specific flags |
| Rotation story | Edit env vars, rolling restart, kek rotate | Generate a new HSM key, rolling restart, kek rotate |
| Compliance posture | Good (AES-256-GCM, versioned) | Stronger — FIPS 140-2 / 140-3 Level 2 / 3 depending on HSM |
| Failure modes if the KEK is lost | Data unrecoverable | Data unrecoverable (HSM backup policy is on you) |
| Typical use | Self-hosted single-tenant, dev, pre-prod | Regulated enterprise, multi-tenant, SOC 2 / PCI-DSS shops |
env 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, mode0600, loaded by systemd viaEnvironmentFile=. - 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.
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.
pkcs11 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 — version, status and provider name, never raw material and not the key label either. The label is derived at load time as key_label_prefix + the version number, which is why the prefix must stay fixed for the life of the install: changing it makes CertAutoPilot look for keys that do not exist. A mismatch between the config-declared provider and the kek_install record aborts startup.
Validated HSMs: SoftHSM2 (CI) and Fortanix DSM. Others are expected to work but have not been exercised by us, and AWS CloudHSM is currently blocked — see supported HSMs. Any HSM exposing CKM_AES_GCM with host-supplied IVs should work; run certautopilot kek pkcs11-init --probe-only to confirm before committing data to it.
The 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.
How 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.
Rotation within the same provider
Both providers support seamless rotation via certautopilot kek rotate. The flow is identical:
- Add a new version (new env var, or
kek pkcs11-init --version=N+1). - Roll the fleet so every process loads both versions.
kek verify --target=N+1confirms readiness.kek rotate --from-version=N --to-version=N+1re-wraps every envelope.--from-versiondefaults to this process's current version, which normally resolves from the keystore — but it silently followsencryption.current_version_overrideif this host is pinned, so pass it explicitly whenever you are not certain.- (Optional)
kek remove --version=Nmarks the old version removed — a different state fromretired, and one that makes its key material ignored at startup even if it is still present (kek reinstateundoes it). It refuses if any record still references the version, if any encrypted data is invisible to the reference count, or if any live node still reports that version as its current one.
See KEK rotation.