Skip to main content

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 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

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, 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.

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:

  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 this process's current version, which normally resolves from the keystore — but it silently follows encryption.current_version_override if this host is pinned, so pass it explicitly whenever you are not certain.
  5. (Optional) kek remove --version=N marks the old version removed — a different state from retired, and one that makes its key material ignored at startup even if it is still present (kek reinstate undoes 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.

See also