fix(tls): Management-Zertifikat des Standby lief ab und erneuerte sich nie
Auf utm-2 war das Zertifikat der Management-UI seit dem 28.08. abgelaufen (entdeckt am 11.09.) und haette sich aus eigener Kraft nie wieder erneuert. Zwei Ursachen trafen zusammen: 1) Das FQDN eines per Join dazugekommenen Nodes landet in KEINER tls_certs-Zeile — es wird beim Setup einmalig ausgestellt und danach von niemandem mehr angefasst. certrenewer arbeitet nur die Tabelle ab und sieht es deshalb nie. (utm-1 steht dort drin, weil sein FQDN beim Erst-Setup regulaer als Domain angelegt wurde — deshalb fiel es dort nicht auf.) 2) Der Scheduler blockt auf einem Nicht-VIP-Master jede ACME-Erneuerung (v1.3.20). Fuer geteilte Domains ist das richtig: die zeigen per DNS auf die VIP, nur der Master kann die Challenge bestehen. Fuer das eigene Management-FQDN stimmt es nicht — utm-2.netcell-it.de zeigt auf 89.163.205.8, die eigene IP des Nodes, und Port 80 antwortet dort. Neu: runManagementCertRenew laeuft auf JEDEM Node unabhaengig von der VIP, aber ausschliesslich fuer das eigene FQDN aus setup.json. Prueft die Restlaufzeit der Datei unter /etc/edgeguard/tls und erneuert ab 30 Tagen Rest (gleicher Schwellwert wie bei den Domain-Certs). Bewusst NICHT ueber tls_certs: das ist eine replizierte Shared-Table, und cluster-reconcile-replication TRUNCATEt solche Tabellen beim Refresh — eine lokal auf dem Subscriber eingefuegte Zeile waere beim naechsten Paket-Upgrade wieder weg. Das Management-Zertifikat ist node-lokale Infrastruktur und wird wie die cluster-tls-Certs als reine Datei behandelt. Existiert dagegen bereits eine tls_certs-Zeile fuer das eigene FQDN (Fall utm-1), bleibt alles beim Alten und certrenewer behaelt die Zustaendigkeit — sonst haetten zwei Mechanismen dieselbe Datei. Tests decken die Schwellwert-Entscheidung ab, inklusive des utm-2-Falls (bereits abgelaufen) und kaputter PEM-Dateien. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -167,8 +167,10 @@ func main() {
|
||||
st, _ := setupStore.Load()
|
||||
|
||||
var renewer *certrenewer.Service
|
||||
var acmeIssuer *acme.Service
|
||||
if st != nil && st.ACMEEmail != "" {
|
||||
issuer := acme.New(st.ACMEEmail)
|
||||
acmeIssuer = issuer
|
||||
renewer = certrenewer.New(tlsRepo, issuer, certDir, 30*24*time.Hour)
|
||||
slog.Info("scheduler: ACME renewer enabled",
|
||||
"email", st.ACMEEmail, "tick", renewTickInterval, "threshold", "30d")
|
||||
@@ -195,6 +197,11 @@ func main() {
|
||||
if renewer != nil && nodeHoldsVIP(ctx, pool) {
|
||||
runRenewer(ctx, renewer, alertSvc, alertDedupe)
|
||||
}
|
||||
// Das EIGENE Management-Zertifikat dagegen auf jedem Node — dessen FQDN
|
||||
// zeigt auf die eigene IP, nicht auf die VIP (siehe mgmtcert.go).
|
||||
if acmeIssuer != nil {
|
||||
runManagementCertRenew(ctx, setupStore, tlsRepo, acmeIssuer, alertSvc, alertDedupe)
|
||||
}
|
||||
runLicenseVerify(ctx, licClient, licKeyStore, licRepo, nodeID, alertSvc, alertDedupe)
|
||||
|
||||
// Lokale Node-ID für Heartbeat. EnsureNodeID liefert dieselbe ID
|
||||
@@ -268,6 +275,10 @@ func main() {
|
||||
if renewer != nil && nodeHoldsVIP(ctx, pool) {
|
||||
runRenewer(ctx, renewer, alertSvc, alertDedupe)
|
||||
}
|
||||
// Eigenes Management-Cert: unabhaengig von der VIP, siehe oben.
|
||||
if acmeIssuer != nil {
|
||||
runManagementCertRenew(ctx, setupStore, tlsRepo, acmeIssuer, alertSvc, alertDedupe)
|
||||
}
|
||||
runCertExpiryCheck(ctx, tlsRepo, alertSvc, alertDedupe)
|
||||
case <-licTick.C:
|
||||
runLicenseVerify(ctx, licClient, licKeyStore, licRepo, nodeID, alertSvc, alertDedupe)
|
||||
|
||||
Reference in New Issue
Block a user