Clusters (DDI_CLUSTER), Kea HA pairs (DDI_KEA_HA), dynamic zones (DDI_DYNAMIC_ZONES) and SSO (DDI_SSO) now need the matching Keygen entitlement; the trial grants all of them. Only taking a feature into use is blocked (403 license_feature): existing clusters, HA pairs, dynamic zones and enabled SSO keep working and stay editable. maxAgents is checked when creating an enrollment token and, under an advisory lock, at enrollment; revoked agents do not count. GET /license reports available_features and the agent usage. The UI shows the features on the license page and disables locked controls, and keygen-setup.sh creates the entitlements and assigns them to licenses (ADR 0027). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.3 KiB
REST-API
Die vollständige, verbindliche Beschreibung ist die OpenAPI-Spezifikation server/api/openapi.yaml (ADR 0012, ADR 0019). Dieses Dokument erklärt nur die übergreifenden Regeln.
Grundlagen
- Basis-URL:
https://<server>/api/v1 - Format: JSON (
application/json), Felder insnake_case - CSV-Export und -Import:
text/csv, Audit-Export zusätzlich als JSON Lines
Anmeldung und Sitzung
POST /auth/loginmit{"username", "password"}setzt das Sitzungs-Cookieddi_session(HttpOnly,SameSite=Lax,Securebei HTTPS) und liefert das CSRF-Token.- Ist für das Konto TOTP aktiv, ist die Sitzung zunächst
mfa_required: true. ErstPOST /auth/totp/verifymit{"code"}schließt die Anmeldung ab. - Muss das Passwort geändert werden (
must_change_password), ist bis zuPOST /auth/passwordnur die Passwortänderung erlaubt. - Single Sign-On: Der Browser ruft
GET /auth/oidc/startauf und landet nach dem Identitätsanbieter überGET /auth/oidc/callbackwieder in der Anwendung.
Jede zustandsändernde Anfrage (POST, PUT, DELETE) braucht den Header X-CSRF-Token: <csrf_token aus der Sitzung>. Anfragen von fremden Seiten (Origin/Sec-Fetch-Site) werden abgelehnt.
Sitzungen enden nach 12 Stunden oder nach 1 Stunde Inaktivität (konfigurierbar), bei Abmeldung, Passwortänderung (andere Sitzungen) und Deaktivierung des Kontos.
Rollen
| Recht | Viewer | Operator | Admin |
|---|---|---|---|
| Netze, Adressen, Zonen, Records, Cluster, TSIG-Schlüssel (ohne Geheimnis), Lizenzstatus ansehen, exportieren, eigene Filter | ✓ | ✓ | ✓ |
| Netze, Adressen, Zonen und Records ändern, Import | ✓ | ✓ | |
| Revisionen erzeugen, ausrollen, zurückrollen | ✓ | ✓ | |
| Cluster und TSIG-Schlüssel verwalten, Geheimnis eines Schlüssels anzeigen, Agents, Generator-Einstellungen | ✓ | ||
| Benutzer, SSO, Lizenz verwalten, Audit-Log | ✓ |
GET /auth/session liefert die effektiven Rechte (permissions).
Fehler
Fehler sind Problem-Dokumente nach RFC 9457 (application/problem+json):
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"code": "validation_failed",
"detail": "validation failed",
"request_id": "5f2c…",
"problems": [{ "code": "mac_required", "field": "mac" }]
}
codeist stabil und Teil des Vertrags; die Oberfläche übersetzt ihn.detailist Englisch und nur für Logs gedacht.problemslistet Feldfehler mit eigenemcode, optionalfieldundparams.request_identspricht dem HeaderX-Request-IDund findet sich in den Server-Logs wieder.
Wichtige Statuscodes: 401 (nicht angemeldet, mfa_required), 403 (forbidden, csrf, license_read_only, license_limit, license_feature, password_change_required), 404, 409 (Konflikt, z. B. network_overlap, version_conflict), 422 (Validierung), 429 (zu viele Anmeldeversuche, mit Retry-After).
Schreibschutz durch die Lizenz
Ist der Server schreibgeschützt (siehe LICENSING.md), antworten alle ändernden Endpunkte mit 403 license_read_only. Lesen, Export, Anmeldung, eigene Filter und die Lizenzverwaltung bleiben erlaubt. Überschreitet eine Änderung ein Limit der Lizenz (Adressen, Agents), antwortet der Server mit 403 license_limit (Parameter kind, limit); braucht sie eine nicht freigeschaltete Funktion, mit 403 license_feature (Parameter feature, ADR 0027).
Gleichzeitige Änderungen
Netze, Adressen, Cluster, TSIG-Schlüssel, Zonen und Records tragen eine version. Änderungen (PUT) müssen die gelesene Version mitsenden; hat jemand anderes inzwischen geändert, antwortet der Server mit 409 version_conflict.
Adresstabelle
GET /addresses filtert, sortiert und paginiert serverseitig:
| Parameter | Bedeutung |
|---|---|
q |
Suche in IP (Präfix), MAC (beliebige Schreibweise), Hostname, FQDN, Beschreibung, Verantwortlichem |
network_id, type (mehrfach), tag, lease_state |
Filter |
sort, order |
Sortierung (ip, type, mac, hostname, fqdn, network, last_seen, lease, updated_at; asc/desc) |
limit (max. 1000), offset |
Seite |
Die Antwort enthält items und total. GET /addresses/export akzeptiert dieselben Filter und liefert CSV.
POST /addresses/preview beschreibt vorab die Auswirkungen einer Änderung auf DNS und DHCP (z. B. dhcp.add_reservation). Massenänderungen (/addresses/bulk) und CSV-Import (/addresses/import, mit dry_run=true zur Prüfung) gelten ganz oder gar nicht; Probleme werden pro Adresse bzw. Zeile gemeldet. /addresses/bulk kennt außerdem set_description, regenerate_hostnames (neue Zufallsnamen für dynamic-Einträge) und dry_run: Dann ändert sich nichts, die Antwort meldet Probleme und unter effects die zusammengefassten Auswirkungen (Codes wie bei der Vorschau, Parameter count; kommt ein Code nur einmal vor, stehen seine Parameter dabei).
DHCP-Bereiche und IP-Listen (ADR 0025)
Ein Netz hat keine Pools mehr; sein DHCP-Bereich besteht aus den dynamic-Einträgen. Network.pools ist eine abgeleitete, schreibgeschützte Liste der zusammenhängenden Bereiche; NetworkRequest kennt kein pools. dynamic-Einträge ohne Hostnamen erhalten einen Namen dyn- + 8 Zeichen [a-z0-9]. Address.lease_hostname ist der Name, den der DHCP-Client zuletzt gemeldet hat; er wirkt nicht auf DNS.
GET /networks/{id}/ips?offset&limit&filter=all|free|used(Rechtipam.read,limitbis 1024, Standard 256): jede Adresse des Netzes in Adressreihenfolge mit Zustandfree,network,broadcast,gatewayoderused(dann mitaddress).allundfreenur für IPv4-Netze bis /16, sonst422 network_too_large.POST /networks/{id}/range(Rechtipam.write):{"start", "end", "action": "assign"|"clear", "type", "types", "dry_run"}.assignlegt für jede freie Adresse des Bereichs einen Eintrag vom Typdynamic,staticoderreservedan (Netz-, Broadcast- und Gateway-Adresse sowie belegte Adressen zählen alsskipped);clearlöscht die Einträge der Typentypes(Standarddynamicundreserved). Höchstens 65.536 Adressen, ein Audit-Eintragnetwork.range_assignbzw.network.range_clearje Aufruf. Fehlercodes:range_invalid,range_outside_network,range_too_large,invalid_type; Regelverstöße der Einträge (z. B.dhcp_disabled) alsvalidation_failed.POST /addresses/check(Rechtipam.read, 1–100 IDs): je Eintrag Ping (unprivilegiertes ICMP-Echo, Statusreachable,unreachableoderunavailablemit Grund) und für Einträge mit DNS-Namen die Vorwärts- und Rückwärtsauflösung bei den autoritativen Servern der Zone (Statusok,missing,mismatch,error, mit befragtem Server und Antworten). Unbekannte IDs:404 not_found.
Geheimnisse
TSIG-Schlüssel und HA-Passwörter erzeugt der Server selbst (ADR 0023). Die API liefert sie nur an einer Stelle aus: GET /tsig-keys/{id}/secret (Recht settings.admin, jeder Abruf steht im Audit-Log – ohne das Geheimnis). Dateien mit Schlüsselmaterial erscheinen in Vorschau, Revision, Diff und offenen Änderungen mit secret: true und leerem Inhalt; Diffs nennen für sie nur den Status. Das HA-Passwort eines DHCP-Clusters wird nie angezeigt.
Der Systemschlüssel ddi-agent-update (ADR 0026) entsteht mit der ersten dynamischen Zone und steht mit system: true in GET /tsig-keys. Mit ihm gleichen die DNS-Agents die von DDI verwalteten Records dynamischer Zonen ab (Dateien ddi-suite-update.key, geheim, und dynamic-records.json). Er lässt sich rotieren, aber nicht löschen (409 key_system); sein Name ist reserviert (409 key_exists).
Ziele von Revisionen
Dateien in Vorschau, Revision und Diff tragen ein target: leer für die Standardgruppe (Agents ohne Cluster), sonst die Agent-ID eines Cluster-Mitglieds. targets beschreibt die Ziele mit Rolle, Cluster und Mitgliedsrolle zum Zeitpunkt der Revision. Ein Agent erhält die Dateien seines Ziels, wenn die Revision eines hat, sonst die der Standardgruppe.
Betriebsendpunkte
Außerhalb von /api/v1, ohne Anmeldung:
| Pfad | Zweck |
|---|---|
GET /healthz |
Prozess lebt |
GET /readyz |
bereit (Datenbank erreichbar) |
GET /metrics |
Prometheus-Metriken |