From b84da5541fada8a44f9d22bf329433d07d6b64a2 Mon Sep 17 00:00:00 2001 From: Alessandro Digilio Date: Sat, 31 Oct 2026 00:47:05 +0100 Subject: [PATCH 1/2] =?UTF-8?q?docs(security):=20=F0=9F=93=9D=20explain=20?= =?UTF-8?q?certificate=20lifecycle=20and=20trust=20boundaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 04c55ef..8a919ed 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,42 @@ unless you explicitly enable `INCLUDE_RAW_KEY_IN_ZIP=true`. Treat both the ZIP and its password as sensitive. ```mermaid -flowchart LR - A[Local Smallstep CA] -->|issue| B[Client identity] - B --> C[PEM certificate and key] - B --> D[PKCS#12 bundle] - D --> E[Optional ZIP for transfer] +flowchart TD + subgraph Local[Private operator machine] + CA["Smallstep CA: private state in ./step"] + PEM["Public PEM certificate + secret client private key"] + CSV["issued_passwords.csv: plaintext passwords, mode 0600"] + P12["Password-protected PKCS#12: certificate + private key"] + ZIP["ZIP: protected PKCS#12 + public CA/client certificates"] + CA -->|issue or renew| PEM + PEM -->|package| P12 + CSV -->|password for packaging| P12 + P12 --> ZIP + end + ZIP -->|optional serve-certs.sh| HTTP["Temporary HTTP download: trusted LAN only"] + HTTP --> CLIENT["Client imports PKCS#12 using its password"] + ZIP -->|operator-managed secure transfer| CLIENT + CLIENT -->|presents client certificate over TLS| SERVICE["Service validates certificate against trusted CA"] + CA -.->|revoke prevents future renewal| REVOKED["Revoked certificate"] + REVOKED -.->|early rejection requires service-side CRL/OCSP checks| SERVICE ``` -This diagram shows the local packaging workflow. The default Compose deployment +In text: the local CA issues a public certificate and private client key. +`cert-manager.sh renew CLIENT_NAME` renews the certificate in place and rebuilds +the PKCS#12 and ZIP using the latest password in the local plaintext log. +The ZIP is not itself encrypted: its PKCS#12 is password-protected. Deliver the +bundle and password through trusted channels chosen by the operator; the scripts +do not arrange a separate secure password-delivery channel. Importing the bundle +does not configure a server: the relying service must trust the CA and enforce +client-certificate validation. + +The optional HTTP download is temporary but not authenticated or encrypted. +It exposes the selected ZIP to anyone who can reach the listener while it runs. +Do not expose it to the Internet or use it to serve CA state, PEM private keys, +or the password log. See the [security model](#security-model) and the +[Nginx Proxy Manager integration guide](docs/nginx-proxy-manager.md). + +Revocation is not an automatic disconnect mechanism. The default Compose deployment does not configure active revocation checking or a CRL endpoint, and open-source step-ca does not provide OCSP. Do not assume that revoking a certificate makes an already issued certificate unusable at relying services before expiry. From 008d16d934be28c14d0b47866a0140ee6760d892 Mon Sep 17 00:00:00 2001 From: Alessandro Digilio Date: Sat, 31 Oct 2026 00:49:16 +0100 Subject: [PATCH 2/2] =?UTF-8?q?docs(security):=20=F0=9F=93=9D=20distinguis?= =?UTF-8?q?h=20local=20key=20generation=20from=20CA=20signing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8a919ed..df986ce 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,14 @@ and its password as sensitive. flowchart TD subgraph Local[Private operator machine] CA["Smallstep CA: private state in ./step"] - PEM["Public PEM certificate + secret client private key"] + CERT["Public PEM client certificate"] + KEY["Secret client private key: generated locally by step CLI"] CSV["issued_passwords.csv: plaintext passwords, mode 0600"] P12["Password-protected PKCS#12: certificate + private key"] ZIP["ZIP: protected PKCS#12 + public CA/client certificates"] - CA -->|issue or renew| PEM - PEM -->|package| P12 + CA -->|sign or renew certificate| CERT + CERT -->|package| P12 + KEY -->|package locally| P12 CSV -->|password for packaging| P12 P12 --> ZIP end @@ -55,7 +57,9 @@ flowchart TD REVOKED -.->|early rejection requires service-side CRL/OCSP checks| SERVICE ``` -In text: the local CA issues a public certificate and private client key. +In text: the `step` CLI generates the client private key on the operator's +machine and requests a signed public certificate from the CA. The CA does not +receive or generate the client private key. `cert-manager.sh renew CLIENT_NAME` renews the certificate in place and rebuilds the PKCS#12 and ZIP using the latest password in the local plaintext log. The ZIP is not itself encrypted: its PKCS#12 is password-protected. Deliver the