verae-staff-iam/docs/CRL-OCSP-DEPLOY-CHECKLIST.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 KiB

CRL / OCSP production deploy checklist (READY package)

Status: READY package — operator checklist to deploy production revocation (CRL and/or OCSP) for staff device certificates.
Not implemented in staff-iam. No CRL/OCSP HTTP routes ship from this service. Lab lab-test-ca.sh crl emits an empty lab-signed CRL for local experiments only — never production.

Design background: CRL-OCSP-DESIGN.md.
Cutover context: PROD-CA-CUTOVER-RUNBOOK.md.
AuthZ revoke path: AUTHZ-ENROLL-DESIGN.md.


Hard rules

  1. Primary control = short leaf lifetime; CRL/OCSP are complementary.
  2. Proxy / edge performs chain verify and revocation check — not the IAM Node process.
  3. staff-iam does not serve GET /crl or OCSP — prefer AIA/CRLDP URLs on the issuing CA hostnames.
  4. Lab empty CRL is not a revoke authority; lab root must not be in production trust stores.
  5. No fake revoke — flipping mtlsEnrolled: false without CA revoke is policy only, not crypto revoke.
  6. LAB_CA_ENABLE stays default off; production refuses lab mint.

Choose enforcement option

Option Where revoke is checked staff-iam role
A. Proxy-side only (recommended first) nginx/Caddy/Envoy/WAF loads CRL or OCSP against client cert Headers only; metadata later
B. CA-adjacent PKI service Signer publishes CRL/OCSP; proxy still enforces TLS IAM calls Signer.revoke
C. In-process IAM OCSP/CRL Discouraged Do not start here

Default deploy path: A.


Pre-flight (CA)

  • R-01 Issuing intermediate (or leaf profile) embeds CRL Distribution Points and/or AIA OCSP URL
  • R-02 CRL/OCSP endpoints are HTTPS (or org-approved distribution), highly available, independent of staff-iam uptime
  • R-03 CRL sign key / OCSP responder key custody documented (HSM preferred); not the IAM app key
  • R-04 CRL validity / nextUpdate cadence agreed (e.g. ≤ 24h) and OCSP cache skew understood
  • R-05 Reason codes mapped: keyCompromise, cessationOfOperation, affiliationChanged (offboard)
  • R-06 Short-lived leaf policy documented if org skips CRL for leaves shorter than cache TTL
  • R-07 Lab root / lab-pki absent from production trust + CRL fetch config

Proxy deploy (Option A)

  • R-10 Production trust store = corporate root/intermediate only
  • R-11 Client cert verify on for staff doors (fail closed on FAILED / absent when enforce intended)
  • R-12 Revocation mode enabled:
    • CRL file/URL periodic fetch, or
    • OCSP (stapling where applicable; client-cert OCSP leaf check per proxy docs)
  • R-13 Soft-fail vs hard-fail policy explicit:
    • Hard-fail recommended for staff mTLS when OCSP/CRL unreachable (document availability needs)
    • Soft-fail only with compensating short lifetime + monitoring
  • R-14 Forward verify/DN headers to staff-iam per ENROLL.md
  • R-15 Header spoofing blocked (proxy strips inbound client-supplied verify headers)
  • R-16 Document cache TTL and how to force flush after emergency revoke

nginx sketch (names only — adapt to platform)

# illustrative — not a copy-paste production profile
ssl_client_certificate /etc/ssl/staff-ca-chain.pem;
ssl_verify_client on;
# ssl_crl /etc/ssl/staff-ca.crl;   # if CRL file mode
# OCSP: per nginx/OpenSSL build capabilities — configure in org template
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Client-DN     $ssl_client_s_dn;

Exact header names must match what staff-iam already reads (see ENROLL.md). Do not invent production hostnames here.

Caddy / Envoy

  • Use org-standard mTLS + revoke modules.
  • Same requirements: verify + revoke + forward identity headers + strip spoofed inbound.

CA-adjacent Signer (Option B add-on)

  • R-20 Signer.revoke({ serial, reason }) API live and audited
  • R-21 Revoke publishes to CRL and/or OCSP within agreed SLA (e.g. ≤ 5 minutes)
  • R-22 staff-iam (when live mint ships) dual-writes: Signer.revoke + metadata revokedAt + mtlsEnrolled: false
  • R-23 Bulk offboard job: all serials for principal → revoke → clear IAM flags
  • R-24 Monitoring: revoke latency, CRL publish failures, OCSP error rate

staff-iam deploy attestation

  • R-30 No CRL/OCSP listen sockets on staff-iam service
  • R-31 NODE_ENV=production, LAB_CA_ENABLE unset
  • R-32 GET /enroll/status still reflects proxy verify — IAM does not claim crypto revoke itself
  • R-33 When metadata exists (future): status may show serial / revokedAt from store, still subordinate to proxy check
  • R-34 Admin UI never offers “Revoke” that only flips a boolean without CA action (if button ships, it must call Signer)

Offboard / emergency revoke runbook

  1. Identify user + device + cert serial (from CA inventory or future IAM metadata).
  2. Revoke at CA (Option A portal/CLI or Option B Signer.revoke) with reason.
  3. IAM: set mtlsEnrolled: false; optionally invalidate sessions.
  4. Flush or wait proxy CRL/OCSP cache (R-16).
  5. Verify:
    • Present revoked cert → proxy verify fail / revoke fail
    • GET /enroll/status without good cert → not verifyOk
    • STAFF_MTLS_ENFORCE=1 login path denies enrolled user without valid cert
  6. Ticket serial, time, reason, actor (no PEM bodies in tickets if avoidable).

Bulk tenant offboard: revoke all serials, then clear flags; do not rely on flag clear alone.


Lab vs production (do not confuse)

Item Lab Production
CRL helper ./scripts/lab-test-ca.sh crl → empty lab CRL Real CA CRL with serials
Trust dev proxy + lab-root only on lab machines Corporate chain only
OCSP none in staff-iam CA/responder hosts
Mint optional LAB_CA_ENABLE=1 external PKI or Signer; lab refused
Empty CRL smoke config only Insufficient as revoke proof
# LAB ONLY — never production trust
./scripts/lab-test-ca.sh init --dir ./lab-pki
./scripts/lab-test-ca.sh crl --dir ./lab-pki --out ./lab-pki/lab-empty.crl.pem
# point a *local* dev proxy at lab-root + empty CRL for config syntax checks only

Acceptance tests (ops)

  • T-01 Valid unrevoked client cert → proxy OK → IAM status shows proxy present
  • T-02 Unknown/untrusted cert → proxy fail → no spoofed verify header reaches IAM
  • T-03 Revoked serial after cache TTL → proxy fail
  • T-04 Emergency flush path works within agreed RTO
  • T-05 staff-iam production still returns 501 on POST /enroll/csr until live Signer cutover
  • T-06 LAB_CA_ENABLE=1 on production binary still does not mint (server refuse)
  • T-07 Monitoring alerts on CRL fetch fail / OCSP unhealthy

Do not

  • Do not serve CRL/OCSP from staff-iam origin by default
  • Do not load lab empty CRL in production
  • Do not soft-fail revoke checks without short-lived certs + explicit risk acceptance
  • Do not treat IAM enrollment flag as cryptographic revocation
  • Do not enable lab CA to “work around” missing production CRL

Still left (ops / product)

  • Live CA CRL/OCSP hostnames and certs (out-of-band)
  • Proxy config in org IaC
  • Signer.revoke when model B/C mint ships
  • Optional IAM metadata + status UI revoke state after live mint