mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-08 15:18:53 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55ce86b132 |
@@ -66,7 +66,6 @@ certctl-cli
|
|||||||
/mcp-server
|
/mcp-server
|
||||||
|
|
||||||
# Private strategy docs
|
# Private strategy docs
|
||||||
strategy.md
|
|
||||||
SECURITY_REMEDIATION.md
|
SECURITY_REMEDIATION.md
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
|
|||||||
@@ -65,14 +65,16 @@ services:
|
|||||||
echo "TLS cert already present at $$CERT — skipping generation"
|
echo "TLS cert already present at $$CERT — skipping generation"
|
||||||
else
|
else
|
||||||
mkdir -p /etc/certctl/tls
|
mkdir -p /etc/certctl/tls
|
||||||
openssl req -x509 -newkey ed25519 -nodes \
|
openssl req -x509 -newkey ec \
|
||||||
|
-pkeyopt ec_paramgen_curve:P-256 \
|
||||||
|
-nodes \
|
||||||
-keyout "$$KEY" \
|
-keyout "$$KEY" \
|
||||||
-out "$$CERT" \
|
-out "$$CERT" \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
-subj "/CN=certctl-server" \
|
-subj "/CN=certctl-server" \
|
||||||
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
||||||
cp "$$CERT" "$$CA"
|
cp "$$CERT" "$$CA"
|
||||||
echo "Generated self-signed TLS cert for certctl-test-server (ed25519, 3650d, CN=certctl-server)"
|
echo "Generated self-signed TLS cert for certctl-test-server (ECDSA-P256/SHA-256, 3650d, CN=certctl-server)"
|
||||||
fi
|
fi
|
||||||
# The test server container runs as root (see `user: "0:0"` below)
|
# The test server container runs as root (see `user: "0:0"` below)
|
||||||
# because setup-trust.sh needs to update the system trust store, so
|
# because setup-trust.sh needs to update the system trust store, so
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
services:
|
services:
|
||||||
# HTTPS-Everywhere Phase 3 — self-signed TLS bootstrap (init container).
|
# HTTPS-Everywhere Phase 3 — self-signed TLS bootstrap (init container).
|
||||||
# Generates a CN=certctl-server ed25519 cert with the SAN list locked by
|
# Generates a CN=certctl-server ECDSA-P256 (SHA-256 signature) cert with
|
||||||
# milestone §3.6 on first boot; subsequent boots see the cert already
|
# the SAN list locked by milestone §3.6 on first boot; subsequent boots
|
||||||
# present in the `certs` named volume and no-op out. Server + agent mount
|
# see the cert already present in the `certs` named volume and no-op out.
|
||||||
# the volume read-only. Destroy via `docker compose down -v` to force
|
# Server + agent mount the volume read-only. Destroy via `docker compose
|
||||||
# regeneration. This bootstrap is for docker-compose demos and local dev
|
# down -v` to force regeneration. This bootstrap is for docker-compose
|
||||||
# only; Helm operators supply a Secret / cert-manager Certificate per
|
# demos and local dev only; Helm operators supply a Secret / cert-manager
|
||||||
# docs/tls.md.
|
# Certificate per docs/tls.md.
|
||||||
|
#
|
||||||
|
# Rationale for ECDSA-P256 (was ed25519 pre-v2.0.48): Apple's TLS stack
|
||||||
|
# — Safari Network Framework and the macOS-bundled LibreSSL 3.3.6
|
||||||
|
# /usr/bin/curl — does not advertise ed25519 in the ClientHello
|
||||||
|
# signature_algorithms extension for server certs, yielding "tls: peer
|
||||||
|
# doesn't support any of the certificate's signature algorithms" at
|
||||||
|
# handshake. ECDSA-P256 with SHA-256 is universally supported. See
|
||||||
|
# docs/tls.md Pattern 1.
|
||||||
certctl-tls-init:
|
certctl-tls-init:
|
||||||
image: alpine/openssl:latest
|
image: alpine/openssl:latest
|
||||||
container_name: certctl-tls-init
|
container_name: certctl-tls-init
|
||||||
@@ -23,14 +31,16 @@ services:
|
|||||||
echo "TLS cert already present at $$CERT — skipping generation"
|
echo "TLS cert already present at $$CERT — skipping generation"
|
||||||
else
|
else
|
||||||
mkdir -p /etc/certctl/tls
|
mkdir -p /etc/certctl/tls
|
||||||
openssl req -x509 -newkey ed25519 -nodes \
|
openssl req -x509 -newkey ec \
|
||||||
|
-pkeyopt ec_paramgen_curve:P-256 \
|
||||||
|
-nodes \
|
||||||
-keyout "$$KEY" \
|
-keyout "$$KEY" \
|
||||||
-out "$$CERT" \
|
-out "$$CERT" \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
-subj "/CN=certctl-server" \
|
-subj "/CN=certctl-server" \
|
||||||
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
||||||
cp "$$CERT" "$$CA"
|
cp "$$CERT" "$$CA"
|
||||||
echo "Generated self-signed TLS cert for certctl-server (ed25519, 3650d, CN=certctl-server)"
|
echo "Generated self-signed TLS cert for certctl-server (ECDSA-P256/SHA-256, 3650d, CN=certctl-server)"
|
||||||
fi
|
fi
|
||||||
# certctl binary runs as UID 1000 inside the server container per
|
# certctl binary runs as UID 1000 inside the server container per
|
||||||
# Dockerfile:64-65; the cert + key must be readable by that UID.
|
# Dockerfile:64-65; the cert + key must be readable by that UID.
|
||||||
|
|||||||
+1
-1
@@ -161,7 +161,7 @@ certctl-test-stepca Up (healthy)
|
|||||||
|
|
||||||
### Get the CA bundle for curl
|
### Get the CA bundle for curl
|
||||||
|
|
||||||
The test harness runs HTTPS-only (the `certctl-tls-init` init container self-signs an ed25519 server cert into a bind-mounted directory before the server starts — see `docker-compose.test.yml` §`certctl-tls-init` for details). The CA cert that signed it is materialized on the host at `./test/certs/ca.crt` (relative to the `deploy/` directory). Every `curl` in the rest of this doc expects it in `$CA`:
|
The test harness runs HTTPS-only (the `certctl-tls-init` init container self-signs an ECDSA-P256 server cert with a SHA-256 signature into a bind-mounted directory before the server starts — see `docker-compose.test.yml` §`certctl-tls-init` for details). The CA cert that signed it is materialized on the host at `./test/certs/ca.crt` (relative to the `deploy/` directory). Every `curl` in the rest of this doc expects it in `$CA`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export CA=$PWD/test/certs/ca.crt
|
export CA=$PWD/test/certs/ca.crt
|
||||||
|
|||||||
+6
-2
@@ -19,10 +19,12 @@ Both paths are read during a fail-loud preflight in `cmd/server/main.go` (see `p
|
|||||||
|
|
||||||
This is the default for the `deploy/docker-compose.yml` stack. It exists so `docker compose up -d --build` just works on a laptop without the operator standing up a CA first. It is not appropriate for any non-demo environment.
|
This is the default for the `deploy/docker-compose.yml` stack. It exists so `docker compose up -d --build` just works on a laptop without the operator standing up a CA first. It is not appropriate for any non-demo environment.
|
||||||
|
|
||||||
An init container named `certctl-tls-init` runs once before the server starts. It uses the `alpine/openssl` image and generates an ed25519 self-signed cert:
|
An init container named `certctl-tls-init` runs once before the server starts. It uses the `alpine/openssl` image and generates an ECDSA-P256 self-signed cert (SHA-256 signature):
|
||||||
|
|
||||||
```
|
```
|
||||||
openssl req -x509 -newkey ed25519 -nodes \
|
openssl req -x509 -newkey ec \
|
||||||
|
-pkeyopt ec_paramgen_curve:P-256 \
|
||||||
|
-nodes \
|
||||||
-keyout /etc/certctl/tls/server.key \
|
-keyout /etc/certctl/tls/server.key \
|
||||||
-out /etc/certctl/tls/server.crt \
|
-out /etc/certctl/tls/server.crt \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
@@ -30,6 +32,8 @@ openssl req -x509 -newkey ed25519 -nodes \
|
|||||||
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
-addext "subjectAltName=DNS:certctl-server,DNS:localhost,IP:127.0.0.1,IP:::1"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Why ECDSA-P256 and not ed25519.** The pre-v2.0.48 demo bootstrap used ed25519 (small keys, fast signatures). Apple's TLS stack — Safari Network Framework and the macOS-bundled LibreSSL 3.3.6 `/usr/bin/curl` — does not advertise ed25519 in the ClientHello `signature_algorithms` extension for server certs, so an ed25519 server cert was rejected at handshake with `tls: peer doesn't support any of the certificate's signature algorithms` on the server side (and the generic TLS handshake error on the client side). Homebrew OpenSSL 3.x, Chrome, Firefox, and Linux curl all accepted ed25519 — Apple was the outlier. ECDSA-P256 with SHA-256 is universally supported, so the demo bootstrap uses it by default. To pick up the new algorithm on an existing demo install, tear the volume down and rebuild: `docker compose -f deploy/docker-compose.yml down -v && docker compose -f deploy/docker-compose.yml up -d --build`. **Helm and operator-supplied-Secret users (Patterns 2 and 3) are unaffected** — they bring their own cert, and `cmd/server/tls.go` is algorithm-agnostic (TLS 1.3 with curve preference `[X25519, P-256]` for key exchange — no constraint on the server cert's signature algorithm).
|
||||||
|
|
||||||
The cert, its matching key, and a copy of the cert published as `ca.crt` land in a named volume (`certs`) mounted at `/etc/certctl/tls/` in the server container (read-only) and the agent container (read-only). The bootstrap is idempotent — if `server.crt`, `server.key`, and `ca.crt` are already present on the volume, the init container logs `TLS cert already present at …` and exits cleanly.
|
The cert, its matching key, and a copy of the cert published as `ca.crt` land in a named volume (`certs`) mounted at `/etc/certctl/tls/` in the server container (read-only) and the agent container (read-only). The bootstrap is idempotent — if `server.crt`, `server.key`, and `ca.crt` are already present on the volume, the init container logs `TLS cert already present at …` and exits cleanly.
|
||||||
|
|
||||||
Single-cert design. CN is `certctl-server` to match the Docker-network hostname. The SAN list is `[certctl-server, localhost, 127.0.0.1, ::1]`, which covers both container-internal agent→server traffic and operator browser/curl access to `https://localhost:8443`. There is no separate intermediate/root chain — the server cert and the CA bundle are the same PEM. This is the whole point of a demo bootstrap.
|
Single-cert design. CN is `certctl-server` to match the Docker-network hostname. The SAN list is `[certctl-server, localhost, 127.0.0.1, ::1]`, which covers both container-internal agent→server traffic and operator browser/curl access to `https://localhost:8443`. There is no separate intermediate/root chain — the server cert and the CA bundle are the same PEM. This is the whole point of a demo bootstrap.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ There is no schema migration tied to this release; the only at-rest state that c
|
|||||||
|
|
||||||
## Procedure — docker-compose operators
|
## Procedure — docker-compose operators
|
||||||
|
|
||||||
The shipped `deploy/docker-compose.yml` includes a `certctl-tls-init` init container that self-signs an ed25519 cert on first boot and drops `server.crt`, `server.key`, and `ca.crt` into a named volume mounted read-only at `/etc/certctl/tls/` on the server and agent containers. No manual cert provisioning is required for the default stack.
|
The shipped `deploy/docker-compose.yml` includes a `certctl-tls-init` init container that self-signs an ECDSA-P256 (SHA-256 signature) cert on first boot and drops `server.crt`, `server.key`, and `ca.crt` into a named volume mounted read-only at `/etc/certctl/tls/` on the server and agent containers. No manual cert provisioning is required for the default stack. (Pre-v2.0.48 this was an ed25519 cert; see [`tls.md`](tls.md) Pattern 1 for the rationale and the `down -v && up --build` migration note.)
|
||||||
|
|
||||||
1. **Pull the HTTPS-everywhere release.** From the repo root:
|
1. **Pull the HTTPS-everywhere release.** From the repo root:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user