verae-staff-iam/docs/PRODUCTION-PKI-REFUSE.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

4.9 KiB
Raw Permalink Blame History

Production PKI refuse matrix (501 vs lab 201)

Purpose: single place for what stays honest 501 in production vs what may return lab-only 201. Live production mint is not shipped. Lab path is never production.

Canonical detail: ENROLL.md · backlog: PKI-MINT-BACKLOG.md · lab design: TEST-CA-DESIGN.md · revoke design: CRL-OCSP-DESIGN.md.

Gate summary

Gate Production / default Lab opt-in
LAB_CA_ENABLE unset / off =1
NODE_ENV=production refuses lab even if flag set must not be production
Lab PKI dir (LAB_PKI_DIR or ./lab-pki) ignored must exist + init’d (ca.crt + key)
Signer none scripts/lab-test-ca.sh sign (openssl)
Response markers no cert body X-Lab-CA: 1, X-Lab-CA-Warning: NOT-FOR-PRODUCTION, body lab: true

Fail closed: missing flag, missing lab-pki, missing script, production env, or sign failure → no silent success.

HTTP matrix — stays 501 vs lab 201

Surface Condition HTTP Body / headers Production?
GET /enroll/csr/schema always 200 fields only; mint: false OK (no crypto)
GET /enroll/status default 200 csrPostStatus: **501**; labCa.enabled: false OK
GET /enroll/status lab ready 200 csrPostStatus: **201** (probe only); labCa.enabled/ready Lab probe only — not a mint
POST /enroll/csr missing / empty csr 501 error: not_implemented + nextSteps Stays 501
POST /enroll/csr invalid PEM shape 400 error: invalid_csr_pem Shape gate (no mint)
POST /enroll/csr valid-looking PEM, lab off 501 not_implemented Stays 501
POST /enroll/csr valid PEM, lab on, pki missing / not ready 501 not_implemented Stays 501
POST /enroll/csr valid PEM, lab on, NODE_ENV=production 501 lab gated off → scaffold Stays 501 (refuse)
POST /enroll/csr valid PEM, lab on + pki ready + non-prod 201 certificate (+ optional chain); X-Lab-CA: 1 LAB ONLY
POST /enroll/csr lab path, openssl sign fails 502 lab_ca_sign_failed + X-Lab-CA: 1 Lab failure (not production mint)
Login / My security UI any — status chips / checklist only No download-cert / mint button
PUT /users/:username { mtlsEnrolled } admin 200 flag only OK (no cert issue)
Proxy mTLS headers edge — presence flags on status External PKI SoT

What always stays refused in production (no 201)

These must never return success cert material under production defaults:

Capability Status
Production CA / HSM / EST / ACME / SCEP mint Not shipped → default POST 501
Silent or default-on lab mint Forbidden (LAB_CA_ENABLE default off; production env refuses)
Demo / stub / self-signed “real” staff cert from IAM Forbidden
PKCS#12 / private key return Never
Production CRL or OCSP from staff-iam Not shipped (design only; lab empty crl offline)
Dropping default 501 without real Signer Forbidden until live PKI checklist done

Operator path (production)

  1. Issue workstation client certs in external reverse-proxy / internal PKI — not this app.
  2. Do not call POST /enroll/csr expecting a production cert — it returns 501.
  3. Terminate mTLS at the proxy; forward verify/DN headers.
  4. Confirm GET /enroll/status → proxyHeadersSeen / mtlsPresent.
  5. Admin mtlsEnrolled: true → optional STAFF_MTLS_ENFORCE=1.

Lab path (explicit only)

./scripts/lab-test-ca.sh init --dir ./lab-pki
LAB_CA_ENABLE=1 npm start   # never with NODE_ENV=production
# POST /enroll/csr { "csr": "-----BEGIN CERTIFICATE REQUEST-----..." }
# → 201 + X-Lab-CA: 1  OR  502 on sign failure  OR  501 if pki not ready

Still left (live production PKI)

  • Choose real CA model (external ACME/EST/HSM/delegated signer)
  • AuthZ + full CSR ASN.1 / PoP / CN-SAN policy
  • Bind cert → IAM user; metadata persist; renew/revoke
  • Production CRL/OCSP (not lab empty CRL)
  • Remove default 501 only after real Signer; keep no-fake-crypto tests