docs: PRODUCTION-PKI-REFUSE matrix 501 vs lab 201
Operator-facing refuse matrix for enroll/csr paths.
This commit is contained in:
parent
a973431935
commit
64da073787
2 changed files with 81 additions and 0 deletions
|
|
@ -145,6 +145,7 @@ If product later needs in-app production mint/renew, that is a **new** design (r
|
||||||
|
|
||||||
## Related docs
|
## Related docs
|
||||||
|
|
||||||
|
- [PRODUCTION-PKI-REFUSE.md](./PRODUCTION-PKI-REFUSE.md) — matrix: what stays **501** vs lab **201**; production refuse rules
|
||||||
- [TEST-CA-DESIGN.md](./TEST-CA-DESIGN.md) — lab script (offline) + **future** gated test CA design; no HTTP fake mint
|
- [TEST-CA-DESIGN.md](./TEST-CA-DESIGN.md) — lab script (offline) + **future** gated test CA design; no HTTP fake mint
|
||||||
- [CRL-OCSP-DESIGN.md](./CRL-OCSP-DESIGN.md) — future real-CA revocation (proxy CRL/OCSP); lab empty CRL only
|
- [CRL-OCSP-DESIGN.md](./CRL-OCSP-DESIGN.md) — future real-CA revocation (proxy CRL/OCSP); lab empty CRL only
|
||||||
- [`scripts/lab-test-ca.sh`](../scripts/lab-test-ca.sh) — OpenSSL lab CA init/sign/crl (NOT production; optional `LAB_CA_ENABLE=1` HTTP shell-out)
|
- [`scripts/lab-test-ca.sh`](../scripts/lab-test-ca.sh) — OpenSSL lab CA init/sign/crl (NOT production; optional `LAB_CA_ENABLE=1` HTTP shell-out)
|
||||||
|
|
|
||||||
80
docs/PRODUCTION-PKI-REFUSE.md
Normal file
80
docs/PRODUCTION-PKI-REFUSE.md
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# 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](../ENROLL.md) · backlog: [PKI-MINT-BACKLOG.md](./PKI-MINT-BACKLOG.md) · lab design: [TEST-CA-DESIGN.md](./TEST-CA-DESIGN.md) · revoke design: [CRL-OCSP-DESIGN.md](./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)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./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
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [PKI-MINT-BACKLOG.md](./PKI-MINT-BACKLOG.md) — shipped surface + live checklist
|
||||||
|
- [TEST-CA-DESIGN.md](./TEST-CA-DESIGN.md) — lab script + gated HTTP
|
||||||
|
- [CRL-OCSP-DESIGN.md](./CRL-OCSP-DESIGN.md) — future revocation
|
||||||
|
- [ENROLL.md](../ENROLL.md) — states, headers, nextSteps
|
||||||
Loading…
Reference in a new issue