8.1 KiB
CRL / OCSP design (future real CA)
Status: design only — not implemented in staff-iam.
- No CRL distribution endpoint
- No OCSP responder
- No revocation API on enroll/mint paths
- Lab helper may emit an empty CRL file for local proxy experiments only (
scripts/lab-test-ca.shcrl)
Production device-cert mint is still out of scope (PKI-MINT-BACKLOG.md). Lab mint (LAB_CA_ENABLE=1) is never a production CA and must not be treated as a revocation authority.
Canonical enroll contract: ENROLL.md. Lab CA: TEST-CA-DESIGN.md. Platform revocation baseline: short lifetimes first; CRL/OCSP for intermediates and offboard bulk revoke (security-reference §6.4).
Purpose
When (and only when) product ships a real production Signer for staff device certificates, operators need a documented revocation story:
- How a lost/stolen workstation cert is invalidated before natural expiry.
- How reverse proxies and mTLS terminators learn about revocations.
- What staff-iam stores (metadata only) vs what the CA / edge owns.
- What stays out of the IAM Node process (no in-process OCSP, no fake “revoked” demo PEMs).
This document is that story. It does not authorize implementing CRL/OCSP inside staff-iam today.
Non-goals (now)
| Non-goal | Why |
|---|---|
| Ship CRL or OCSP HTTP from staff-iam | IAM is not a CA; default mint stays 501 |
| Soften mTLS with a stub “revoked” flag that is not backed by CA state | Violates “no fake crypto” |
| Require CRL checks for lab-only leaves | Lab leaves are short-lived (≤30d script cap; default 7d); throwaway trust |
| Put private CA keys or OCSP signing keys in the IAM user store | Keys stay in HSM / external PKI / LAB_PKI_DIR (lab only) |
Browser “Revoke cert” that only flips mtlsEnrolled |
Admin flag is enrollment policy, not cryptographic revocation |
Recommended production model
Align with Verae security-reference provisioning:
| Control | Role |
|---|---|
| Short leaf lifetime | Primary control (hours–days for staff device certs; renew via real mint path) |
| CRL and/or OCSP on issuing intermediate | Secondary control for early revoke and offboard |
| Proxy / edge termination | Performs chain verify and revocation check; forwards verify/DN headers to IAM |
| staff-iam | Stores enrollment flag + optional cert metadata (serial, fingerprint, notAfter); never signs CRL/OCSP itself unless product later splits a dedicated PKI service |
Corporate / HSM CA (or EST/SCEP/ACME delegate)
│ signs leaves
│ publishes CRL URI and/or OCSP URL in AIA/CRLDP
▼
Reverse proxy (mTLS terminate)
│ verify + CRL/OCSP (or short-lived-only policy)
│ forward ssl-client-verify / DN / optional PEM presence
▼
staff-iam GET /enroll/status · STAFF_MTLS_ENFORCE
│ mtlsEnrolled flag + future serial metadata
▼
Login / My security UI
Preferred default for staff workstations: short-lived client certs + automated renew, with OCSP stapling or CRL fetch at the proxy, not inside the IAM app.
Options (choose at live-mint design time)
A — Proxy-side only (recommended first)
- Issuing CA publishes CRL Distribution Points and/or OCSP in leaf/intermediate extensions.
- nginx / Caddy / Envoy / corporate WAF enables client-cert verify + revocation.
- staff-iam continues to trust
proxy.verifyOk/ DN headers only. - Offboard: admin sets
mtlsEnrolled: falseand CA revokes serial (runbook both).
Pros: no new IAM crypto surface; matches today’s header contract.
Cons: revoke latency depends on CRL TTL / OCSP cache; operators must wire proxy correctly.
B — CA-adjacent PKI service (not in IAM process)
- Dedicated signer service owns issue + revoke + CRL/OCSP endpoints.
- staff-iam calls
Signer.issue/Signer.revoke(serial)over mTLS; never holds CA key. - Status UI may show “revoked at CA” from metadata poll, not by serving CRL bytes.
Pros: clean AuthZ boundary; scalable OCSP.
Cons: new service + ops; still need proxy to enforce at TLS.
C — In-process staff-iam OCSP/CRL (discouraged)
- Only if product explicitly requires IAM to be the issuing CA (unlikely).
- Would need HSM, AIA URLs, cache, audit, rate limits, and production hardening.
- Do not start here; backlog assumes external/HSM/EST signer first.
Data staff-iam may hold later (metadata only)
When live mint ships, persist at most:
| Field | Use |
|---|---|
serial (hex) |
Correlate revoke + support |
fingerprint (SHA-256 of DER) |
Display / audit |
notAfter |
Renew warnings |
revokedAt / revokeReason |
UI + audit after CA confirms |
deviceId (optional) |
Bind to workstation record |
Never store leaf private keys, PKCS#12 passwords, or full cert PEM in the user JSON unless a separate encrypted secret store is designed. Audit events may log serial/fingerprint flags only (same rule as today’s csr_attempt — no PEM bodies).
Revoke / offboard runbook (future)
- Confirm identity (staff user + device).
- Call CA revoke (CRL entry and/or OCSP revoked status) with reason (
keyCompromise/cessationOfOperation). - Set
mtlsEnrolled: false(and any device record) in IAM. - Optionally kill active sessions (orthogonal to cert crypto).
- Wait for proxy CRL/OCSP cache TTL or force cache flush.
- Verify: client cert no longer yields
proxy.verifyOk; login enforce path denies.
Bulk tenant/staff offboard: revoke all serials bound to that principal at the CA, then clear IAM flags.
Lab only — empty CRL helper
scripts/lab-test-ca.sh optional subcommand:
./scripts/lab-test-ca.sh crl [--dir DIR] [--out PATH]
- Requires an initialized lab CA (
init). - Writes a valid, empty CRL (no revoked serials) signed by the lab root, default
DIR/lab-empty.crl.pem. - Purpose: let a local dev proxy load a CRL file path so verify+CRL config can be smoke-tested without implying production revocation.
- NOT FOR PRODUCTION. Empty CRL does not revoke anything; lab root must not be in real trust stores.
- Does not add HTTP CRL/OCSP routes to staff-iam.
HTTP surfaces (not shipped)
| Surface | Today | Future (product decision) |
|---|---|---|
POST /enroll/csr |
501 default; lab 201 only | Real sign; still no CRL body |
POST /enroll/revoke (name TBD) |
absent | Optional: AuthZ’d request that calls external Signer.revoke |
GET /crl/... or OCSP |
absent | Prefer CA/proxy hostnames in cert AIA/CRLDP — not staff-iam origin |
GET /enroll/status |
proxy headers + flags | May add serial / notAfter / revokedAt metadata |
Implementation order (blocked on product)
- Choose production CA model in PKI-MINT-BACKLOG.md (external ACME/EST/HSM/delegated).
- Decide Option A vs B for revocation enforcement (default A).
- Document proxy verify+CRL/OCSP settings in operator ENROLL runbook.
- Add
Signer.revoke+ IAM metadata fields when mint is real. - Only then consider bulk offboard automation and status UI revoke state.
- Never enable lab empty-CRL or lab root as a production trust anchor.
Hard rules
- No fake revocation — do not return success on a revoke API that only flips a boolean without CA action.
- Proxy remains TLS source of truth for “cert valid on this request.”
- Lab CRL is empty + lab-signed only — experiments, not fleet security.
- Short lifetime remains the primary control; CRL/OCSP are complementary.
- Cross-link live-mint PRs: this doc + PKI-MINT-BACKLOG.md + ENROLL.md + TEST-CA-DESIGN.md.
Related docs
- PKI-MINT-BACKLOG.md — live mint checklist; CRL/OCSP item
- TEST-CA-DESIGN.md — lab CA init/sign; never production
- ENROLL.md — mTLS states, proxy headers, CSR scaffold
- README.md — service overview and security gates