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:
@@ -278,7 +278,10 @@ func serialHex(cert *x509.Certificate) string {
|
||||
// keepalive) with the hub registered. Split from the listen/serve so tests can
|
||||
// drive it on an ephemeral listener.
|
||||
func agentServer(cfg config, hub *agentHub) (*grpc.Server, error) {
|
||||
cert, err := tls.LoadX509KeyPair(cfg.agentCert, cfg.agentKey)
|
||||
// GetCertificate (not a fixed Certificates slice) so the agent-cert-renewer
|
||||
// sidecar can rotate server.crt/key on disk and the manager picks it up on the
|
||||
// next handshake without a restart. See certreload.go.
|
||||
reloader, err := newCertReloader(cfg.agentCert, cfg.agentKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("agent server cert: %w", err)
|
||||
}
|
||||
@@ -291,10 +294,10 @@ func agentServer(cfg config, hub *agentHub) (*grpc.Server, error) {
|
||||
return nil, fmt.Errorf("no certificates parsed from FLEET_MGR_AGENT_CLIENT_CA")
|
||||
}
|
||||
creds := credentials.NewTLS(&tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: pool,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
GetCertificate: reloader.GetCertificate,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: pool,
|
||||
})
|
||||
gs := grpc.NewServer(
|
||||
grpc.Creds(creds),
|
||||
|
||||
Reference in New Issue
Block a user