Secret delivery option 5: Per-container JWT with encrypted secret claims (JWE) #133
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent epic: #129
Overview
Mint a short-lived JWE (JSON Web Encryption) token per container containing encrypted secret claims. Pass as a single env var
CAMELEER_BOOTSTRAP_JWT. Container decrypts on startup to extract secrets. Leverages our existing Nimbus JOSE library.Approach Design
Token Structure
Direct encryption with AES-256-GCM (
dir + A256GCM) — simplest symmetric JWE mode. Nimbus JOSE v9.47 (our current dep) has full support viaDirectEncrypter/DirectDecrypter.Token Size Capacity
execve()single arg~50-80 key-value pairs fit easily. Typical container has 5-15 secrets — not a constraint.
Security Analysis
Honest Comparison: JWE vs Plain Env Vars
docker inspectreveals secrets/proc)Verdict: More than obscurity (real protection against metadata leakage, log exposure) but less than a secrets manager. Does NOT protect against shell access to running container or key compromise.
The Fatal Chicken-and-Egg Problem
The container needs the decryption key to read the JWE. Options:
CAMELEER_AGENT_AUTH_TOKEN(already an env var — circular)CAMELEER_BOOTSTRAP_KEY(defeats the purpose)You still need at least one cleartext secret as env var. If an attacker reads
docker inspect, they get the bootstrap token, derive the AES key, and decrypt the JWE. Security improvement againstdocker inspectthreat is marginal — protecting N secrets by exposing 1 key that unlocks all N.Replay & Revocation
jti+ short expirysub: "deployment:<uuid>"Accidental Logging
JWE token in logs appears as opaque base64url — genuine improvement. But once agent decrypts and sets env vars from the JWT contents, those values are in process memory and potentially re-exposed.
Industry Assessment
Does Anyone Use JWTs for Secret Delivery?
No. After extensive research, no production systems use JWE tokens for secret delivery to containers. Closest patterns:
The absence of this pattern in production is itself a signal.
What Standards Say
While this guidance targets JWS (readable payloads), the spirit applies: JWTs are designed for authorization claims, not secret transport.
CVE Concerns
JWE implementations have demonstrated subtle vulnerabilities:
alg=nonetokens bypass signature verificationVault Response Wrapping Comparison
Platform Compatibility
withEnv()docker inspect(as ciphertext)If mounting as a file anyway (Swarm/K8s), the JWE encryption becomes redundant — platform-native encryption already protects it.
Implementation Complexity
Total: 2-3 days Java-only, 5-7 days with non-Java support.
Recommendation
Verdict: ⭐⭐ (2/5) — Do Not Implement
The per-container JWE approach is technically sound but strategically misguided for our scenario:
Chicken-and-egg is fatal — still need one cleartext secret to bootstrap decryption. If attacker reads
docker inspect, they get the key and decrypt everything. Marginal security improvement.Industry has not adopted this — no major platform, runtime, or security vendor uses JWE for secret delivery. Universal recommendation: platform-native secrets or external vault.
RFC 8725 and OWASP advise against it — putting sensitive data in JWT claims explicitly cautioned.
CVE surface area increases — JWE implementations have subtle vulnerabilities. Adds attack surface to critical startup path.
Cross-language tax is permanent — every non-Java container needs JWE bootstrap code forever.
What To Do Instead
The better version of this idea is the API-based secret fetch (Option 6, #TBD): mint a short-lived identity JWT (not containing secrets), container calls
GET /api/v1/bootstrap/{id}/secretswith it, receives secrets over TLS, server marks token consumed. This gives single-use guarantees, audit logging, and separation of identity from secrets — the Vault response-wrapping pattern without Vault.Sources