fleet-manager: auto-renew the agent-plane server cert (step-ca sidecar + hot-reload)

The agent-plane server cert was issued by hand (server-pki.sh / docker exec
step ca certificate), which needs the step CLI on the host, re-specifies SANs
each time, and silently expires at the CA's 90-day cap — the exact failure that
just broke agent TLS (cert minted with a stale SAN, missing manager.fleet.lab).

Automate it:
- agent-cert-renewer sidecar (smallstep step-cli image, compose profile
  cert-auto): issues the cert once from the co-located fleet step-ca, then
  'step ca renew --daemon' rotates it before the cap. Renewal preserves the
  subject + SANs, so SAN drift cannot recur. Chowns to the manager's nonroot
  uid so the distroless manager reads the key. Opt-in + only valid where the CA
  is co-located; server-pki.sh stays as the manual/remote-CA path.
- manager hot-reloads via GetCertificate (certreload.go): a rotated cert on
  disk is picked up on the next handshake with no restart and no dropped agent
  streams; a half-written pair keeps the last good cert serving. Unit-tested.
- defaults.env documents the cert-auto knobs; DEPLOY.md §2a recommends the
  renewer and flags the mandatory manager.fleet.lab SAN.
This commit is contained in:
Audiobuzz
2026-07-10 07:42:18 +00:00
parent 1c68c37824
commit 1db3977238
8 changed files with 360 additions and 12 deletions
+39
View File
@@ -118,6 +118,45 @@ services:
# cert. (UI TLS is Traefik's — no admin cert here.) See DEPLOY.md/server-pki.sh.
- ./pki:/pki:ro
# --- agent-plane server-cert auto-renewer (optional; step-ca co-located) -----
# Issues the manager's agent-plane server cert ONCE from the fleet step-ca, then
# runs `step ca renew --daemon` to rotate it well before the CA's ~90-day cap —
# replacing the manual server-pki.sh + `docker exec … step ca certificate` dance
# and the periodic re-mint. Renewal PRESERVES the subject + SANs of the first
# issuance, so agent-TLS SAN drift can't recur. The manager hot-reloads the
# rotated cert via GetCertificate (certreload.go) — no restart, no dropped hub.
#
# OPT-IN via `--profile cert-auto`, and ONLY valid where the fleet step-ca
# (serving/dot1x-bench) runs on THIS host: it mounts the CA root + intermediate +
# 'enrol' provisioner password read-only and reaches the CA over host-loopback.
# Where the CA is remote, leave this off and issue via server-pki.sh (or ACME).
#
# docker compose --profile cert-auto up -d agent-cert-renewer fleet-manager
agent-cert-renewer:
image: harbor.bitasylum.org/dockerhub/smallstep/step-cli:latest
profiles: ["cert-auto"]
restart: unless-stopped
network_mode: host # reach the co-located CA on ${AGENT_CA_URL}
user: "0:0" # writes into /pki/agent, then chowns to the manager uid
environment:
STEPPATH: /tmp/step
HOME: /tmp
AGENT_SANS: "${AGENT_CERT_SANS:-manager.fleet.lab,diskless-server.bitasylum.org}"
CA_URL: "${AGENT_CA_URL:-https://localhost:8443}"
PROVISIONER: "${FLEET_CA_PROVISIONER:-enrol}"
RENEW_EXPIRES_IN: "${AGENT_CERT_RENEW_EXPIRES_IN:-720h}"
CERT_NOT_AFTER: "${AGENT_CERT_NOT_AFTER:-2160h}"
OWNER: "65532:65532"
entrypoint: ["/bin/sh", "/renew/agent-cert-renewer.sh"]
volumes:
- ./pki/agent:/pki/agent # shared with the manager (rw here)
- ./agent-cert-renewer.sh:/renew/agent-cert-renewer.sh:ro
# fleet CA material (read-only), from the co-located step-ca stack. Override
# the host paths in .env if your bench lays them out differently.
- ${FLEET_CA_ROOT:-../dot1x-bench/pki/root_ca.crt}:/ca/root_ca.crt:ro
- ${FLEET_CA_INTERMEDIATE:-../dot1x-bench/pki/intermediate_ca.crt}:/ca/intermediate_ca.crt:ro
- ${FLEET_CA_PROVISIONER_PW:-../dot1x-bench/pki/stepca/secrets/password}:/ca/password:ro
# --- management-plane ingress (Traefik) — admin UI on :443 ------------------
# Terminates the Let's Encrypt cert (Route 53 DNS-01) on :443 and forwards
# plaintext to the manager (behind-proxy mode, loopback :9500). Host networking