verae-staff-iam/docs/CRL-OCSP-DESIGN.md
George Lambert 7e8fc7c1f9 docs: PKI READY packages — prod CA cutover, AuthZ enroll, CRL/OCSP deploy
Convert OPEN-ISSUES #4 external items to READY ops packages without
shipping production mint. LAB_CA_ENABLE stays default off; NODE_ENV=
production still refuses lab; default POST /enroll/csr remains 501.

- docs/PROD-CA-CUTOVER-RUNBOOK.md (mint/renew/revoke cutover)
- docs/AUTHZ-ENROLL-DESIGN.md (gates before dropping 501)
- docs/CRL-OCSP-DEPLOY-CHECKLIST.md (proxy/CA revoke deploy)
- Cross-links from README, ENROLL, PKI-MINT-BACKLOG, refuse/design docs

npm test: 19/19 PASS
2026-10-14 04:20:24 -04:00

8.4 KiB
Raw Blame History

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.sh crl)

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:

  1. How a lost/stolen workstation cert is invalidated before natural expiry.
  2. How reverse proxies and mTLS terminators learn about revocations.
  3. What staff-iam stores (metadata only) vs what the CA / edge owns.
  4. 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

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)

  • 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: false and 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)

  1. Confirm identity (staff user + device).
  2. Call CA revoke (CRL entry and/or OCSP revoked status) with reason (keyCompromise / cessationOfOperation).
  3. Set mtlsEnrolled: false (and any device record) in IAM.
  4. Optionally kill active sessions (orthogonal to cert crypto).
  5. Wait for proxy CRL/OCSP cache TTL or force cache flush.
  6. 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)

  1. Choose production CA model in PKI-MINT-BACKLOG.md (external ACME/EST/HSM/delegated).
  2. Decide Option A vs B for revocation enforcement (default A).
  3. Document proxy verify+CRL/OCSP settings in operator ENROLL runbook.
  4. Add Signer.revoke + IAM metadata fields when mint is real.
  5. Only then consider bulk offboard automation and status UI revoke state.
  6. Never enable lab empty-CRL or lab root as a production trust anchor.

Hard rules

  1. No fake revocation — do not return success on a revoke API that only flips a boolean without CA action.
  2. Proxy remains TLS source of truth for “cert valid on this request.”
  3. Lab CRL is empty + lab-signed only — experiments, not fleet security.
  4. Short lifetime remains the primary control; CRL/OCSP are complementary.
  5. Cross-link live-mint PRs: this doc + PKI-MINT-BACKLOG.md + ENROLL.md + TEST-CA-DESIGN.md.