Files
DDI/docs/adr/0021-agent-strecke-m3.md
T
beug.k@beugsiud.deandClaude Opus 5.5 e843502cbf feat: M3 contracts for agents, revisions and bundles
Shared Apache-2.0 packages for the signed bundle format and the agent
certificate conventions, the agent role interface, REST API spec for
agents, enrollment tokens, revisions, deployments and leases, and ADR
0021. Generator settings now hold the target paths on the managed hosts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:54:30 +02:00

6.9 KiB
Raw Blame History

0021 – Agent-Strecke: Revisionen, PKI, Ablauf im Agent (M3)

  • Status: Akzeptiert
  • Datum: 2026-10-13

Kontext

ADR 0007–0011 legen Protokoll, CA, Signatur, Binaries und Agent-Zustand fest. Für M3 (erste durchgängige Strecke) fehlen die konkreten Regeln, auf die sich Server, Agent-Kern und Rollen verlassen. Gemeinsame Typen liegen in internal/bundle (Manifest, Signatur), internal/agentpki (Agent-ID im Zertifikat, CA-Fingerprint, TLS) und agent/core/role.go (Rollen-Schnittstelle); die REST-API steht in server/api/openapi.yaml.

Entscheidung

Revisionen

  • Eine globale, fortlaufende Revisionsnummer (1 … 2³²−1, weil sie zugleich SOA-Seriennummer ist). Eine Revision enthält die DNS- und die DHCP-Artefakte, Warnungen, Kommentar, Ersteller und Zeitpunkt und ist unveränderlich.
  • Erzeugt wird sie ausdrücklich mit POST /api/v1/revisions (Recht deploy, im Lesemodus gesperrt). Der Server erzeugt die Konfiguration zuerst mit der Nummer der letzten Revision; ist sie byte-gleich, entsteht keine neue Revision (Antwort 200). Sonst wird mit der nächsten Nummer erzeugt und gespeichert (201). Kann ein Teil nicht erzeugt werden (z. B. fehlende DNS-Einstellungen), wird nichts gespeichert (422).
  • Soll-Revision jedes Agents ist in M3 die neueste Revision. Betriebsmodi pro Agent, Push aus dem UI und Entwürfe folgen in M4; das Feld mode existiert bereits (Standard auto_pull).
  • Bundles werden beim Abruf (FetchBundle) für den Agent signiert: Agent-ID und Rolle aus dem Zertifikat, Artefakte der Rolle, created_at = Zeitpunkt der Revision. Gleiche Eingabe ergibt gleiche Bytes.

PKI und Agent-API

  • Beim ersten Start erzeugt der Server die Agent-CA (ECDSA P-256, 10 Jahre) und den Bundle-Signaturschlüssel (Ed25519). Beide privaten Schlüssel liegen mit dem Master-Key verschlüsselt in der Datenbank (ADR 0015).
  • Das Serverzertifikat des Agent-Ports wird bei jedem Start im Speicher aus der CA ausgestellt (1 Jahr); es muss nirgends gespeichert oder erneuert werden. SANs aus agent_api.server_names. Der Server sendet Zertifikat und CA (Kette), damit der Agent beim Enrollment den Fingerprint prüfen kann.
  • Konfiguration: agent_api.listen (Standard :8444), agent_api.public_address (host:port für den angezeigten Enrollment-Befehl; Standard: Host aus http.public_url und Port aus listen), agent_api.server_names (Standard: Host aus public_address).
  • Client-Zertifikate: 14 Tage, CN = Agent-ID, URI-SAN urn:<produkt>:agent:<uuid>, nur ClientAuth, zufällige 128-Bit-Seriennummer. Der Server speichert pro Agent nur die Seriennummer des aktuellen Zertifikats. Eine Verbindung wird nur akzeptiert, wenn Kette, Gültigkeit, Agent-ID, Seriennummer und Sperrstatus stimmen. Nach einer Erneuerung ist das alte Zertifikat damit sofort wertlos; eine Sperrliste ist nicht nötig.
  • Der Listener fordert Client-Zertifikate an, prüft sie aber selbst (Interceptor), weil Enroll ohne Zertifikat und RenewCertificate mit einem bis zu 30 Tage abgelaufenen Zertifikat erlaubt sein müssen.
  • Enrollment-Token <id>.<secret>: ID 16 Hex-Zeichen, Secret 32 Zufallsbytes (base64url). In der Datenbank liegt SHA-256 des Secrets (hohe Entropie, kein Passwort-Hash nötig). Einmalig, an die Rolle gebunden, Standard 24 h gültig. Fehlversuche werden pro Quell-IP begrenzt.
  • Der Agent erneuert sein Zertifikat, sobald weniger als die Hälfte der Laufzeit übrig ist, mit neuem Schlüssel.
  • Connect: Agent sendet Hello, Server antwortet mit Welcome (Modus, Pull-Intervall Standard 60 s, Heartbeat Standard 30 s, Soll-Revision). Neue Revisionen werden verbundenen Agents im Modus auto_pull sofort als ApplyRevisionCommand gesendet; ohne Stream holt der Agent sie im Pull-Intervall über GetDesiredState. Ein gesperrter Agent wird sofort getrennt.

Agent

  • Konfigurationsdatei /etc/ddi-suite/agent-<rolle>.yaml (--config): state_dir, log, Zeitlimits und der Abschnitt der Rolle (dns: bzw. dhcp:). Serveradresse, Servername, Agent-ID, Schlüssel und Zertifikate schreibt enroll nach state_dir/identity/ (ADR 0011).
  • Befehle: enroll --server <host:port> --token <token> --ca-hash sha256:<hex> [--server-name <name>], run, status, version.
  • Ablauf (siehe agent/core/role.go): Bundle prüfen (bundle.Verify, Revision > angewendete) → unter revisions/<n>/ ablegen → Validate → Activate → Health (bis zu 30 s wiederholt) → bei Fehler Activate(letzte funktionierende). Ergebnis succeeded, rejected, rolled_back oder failed geht per ReportDeployment an den Server; ist er nicht erreichbar, wird der Bericht gespeichert und später gesendet.
  • Eine abgelehnte oder zurückgerollte Revision wird nicht automatisch erneut versucht (sonst Endlosschleife bei jedem Poll). Erst eine neuere Revision oder ein ausdrücklicher Push derselben Nummer startet einen neuen Versuch.
  • Ohne Server läuft der Dienst mit der zuletzt aktiven Konfiguration weiter.
  • Leases: Implementiert die Rolle LeaseSource, fragt der Kern sie alle 30 s ab und meldet Änderungen; beim Start, nach jeder neuen Verbindung und stündlich einen vollständigen Stand (full_sync). Die Sequenznummer ist persistent.

DNS-Rolle (BIND)

  • conf_dir (Standard /etc/bind/ddi-suite) erhält ddi-suite.conf und ddi-suite-options.conf, zone_dir (Standard /var/lib/bind/ddi-suite, muss der Generator-Einstellung entsprechen) erhält den Inhalt von zones/. zone_dir liegt unter /var/lib/bind, weil BIND dort schreiben darf (Journale dynamischer Zonen; AppArmor auf Ubuntu).
  • Validate: named-checkconf auf einer temporären named.conf, die die neuen Include-Dateien einbindet, und named-checkzone für jede Zonendatei (Zonenname aus db.<zone>).
  • Activate: bisherige Dateien sichern, neue atomar schreiben, veraltete entfernen, named-checkconf -z auf die echte named.conf; schlägt das fehl, Sicherung zurück und Fehler. Danach rndc reconfig und rndc reload.
  • Health: rndc status und SOA-Abfrage jeder verwalteten Zone an dns_address (Standard 127.0.0.1:53); die Seriennummer muss der Revision entsprechen.

DHCP-Rolle (Kea)

  • config_file (Standard /etc/kea/kea-dhcp4.conf), control_socket (muss der Generator-Einstellung entsprechen).
  • Validate: kea-dhcp4 -t auf die neue Datei. Activate: Sicherung, atomar schreiben, config-reload über den Control-Socket, bei Fehler Sicherung zurück. Health: status-get. Leases: lease4-get-page.

Konsequenzen

  • Server, Agent-Kern und Rollen lassen sich unabhängig entwickeln und testen; der Kern kennt weder BIND noch Kea.
  • Zielpfade stehen zweimal (Generator-Einstellung und Agent-Konfiguration). Der Installer (M6) setzt beide gleich; die Rollen prüfen beim Validate, dass die erzeugte Konfiguration ihr zone_dir bzw. ihren control_socket verwendet, und lehnen sonst mit klarer Meldung ab.
  • Schlüsselrotation des Bundle-Signaturschlüssels (ADR 0009) und CA-Rotation sind vorbereitet, aber nicht umgesetzt.