Pre-flight checklist
Problem / motivation
Multi-replica and Kubernetes deployments must share the same Fernet encryption key material so tokens and cookies decrypt consistently. Today the only supported source is CODEX_LB_ENCRYPTION_KEY_FILE (auto-created under the data dir or mounted as a volume). That forces shared filesystem state even when the operator already holds the key as a secret string (env, K8s Secret env injection, platform secrets managers). Empty or misconfigured setups also risk generating a different on-disk key per replica.
Proposed change
Add optional CODEX_LB_ENCRYPTION_KEY for raw Fernet key material.
Precedence (highest first):
Explicit Python key argument
-
CODEX_LB_ENCRYPTION_KEY
-
CODEX_LB_ENCRYPTION_KEY_FILE / default data-dir key file
-
Default remains unset → current key-file behavior (auto-generate, 0600) is unchanged.
-
When the env key is set and valid, encrypt/decrypt uses it and must not read, create, or chmod a key file.
-
Empty, whitespace-only, or invalid Fernet values fail fast at settings load (no silent file fallback).
-
Document in .env.example, configuration docs, and the generated settings reference; multi-replica docs allow env key or shared file.
Alternatives considered
- Keep file-only, require Secret volume mounts — works, but not stateless-friendly and heavier for pure env-based secret injection.
- Read the key only in crypto code without a Settings field — bypasses central config validation and settings reference / docs generation.
- Overload CODEX_LB_ENCRYPTION_KEY_FILE for either path or inline key — ambiguous type, harder validation, worse DX.
Area
Helm / Docker / packaging, OpenSpec / docs, Other
Additional context
- Fernet generation example:
python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'
-
Cross-replica fingerprint check (CODEX_LB_ENCRYPTION_KEY_FINGERPRINT_MODE) must still see the same effective key material whether supplied by env or file.
-
Migrating from file → a different env key in enforce mode trips the fingerprint sentinel until intentional rotation cleanup (delete encryption_key_fingerprint in runtime_sentinels).
-
OpenSpec change (if opened from existing work): openspec/changes/support-encryption-key-env-priority/
Pre-flight checklist
Problem / motivation
Multi-replica and Kubernetes deployments must share the same Fernet encryption key material so tokens and cookies decrypt consistently. Today the only supported source is CODEX_LB_ENCRYPTION_KEY_FILE (auto-created under the data dir or mounted as a volume). That forces shared filesystem state even when the operator already holds the key as a secret string (env, K8s Secret env injection, platform secrets managers). Empty or misconfigured setups also risk generating a different on-disk key per replica.
Proposed change
Add optional CODEX_LB_ENCRYPTION_KEY for raw Fernet key material.
Precedence (highest first):
Explicit Python key argument
CODEX_LB_ENCRYPTION_KEY
CODEX_LB_ENCRYPTION_KEY_FILE / default data-dir key file
Default remains unset → current key-file behavior (auto-generate, 0600) is unchanged.
When the env key is set and valid, encrypt/decrypt uses it and must not read, create, or chmod a key file.
Empty, whitespace-only, or invalid Fernet values fail fast at settings load (no silent file fallback).
Document in .env.example, configuration docs, and the generated settings reference; multi-replica docs allow env key or shared file.
Alternatives considered
Area
Helm / Docker / packaging, OpenSpec / docs, Other
Additional context
python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'Cross-replica fingerprint check (CODEX_LB_ENCRYPTION_KEY_FINGERPRINT_MODE) must still see the same effective key material whether supplied by env or file.
Migrating from file → a different env key in enforce mode trips the fingerprint sentinel until intentional rotation cleanup (delete encryption_key_fingerprint in runtime_sentinels).
OpenSpec change (if opened from existing work):
openspec/changes/support-encryption-key-env-priority/