opnsense-portal/docs/opnsense-api.md
Carsten Abele e49882b8a8 feat(opnsense,certmatch): read-only Export-Client mit Streaming und CN-Zuordnung
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
2026-08-14 09:15:53 +02:00

4.1 KiB

OPNsense-API: genutzte Endpunkte und Annahmen

Das Portal spricht ausschließlich das Plugin os-openvpn-client-export an und ausschließlich lesend.

Diese Annahmen sind mit go test -tags integration ./internal/opnsense/ gegen eine echte Instanz zu bestätigen, bevor v1 ausgeliefert wird. Die exakten Feldnamen und Antwortformen wechseln zwischen OPNsense-Versionen; der Client ist deshalb bewusst tolerant gebaut.

Genutzte Endpunkte

Methode Pfad Zweck
GET /api/openvpn/export/providers Liste der exportierbaren VPN-Instanzen
GET /api/openvpn/export/accounts/{vpnid} Zertifikate einer Instanz
GET /api/openvpn/export/download/{vpnid}/{format}/{certref} Konfiguration herunterladen

Alle drei sind GET. Das Portal ruft keinen schreibenden Endpunkt auf und übergibt keine Exportoptionen — die auf der Firewall hinterlegten Einstellungen sind die Quelle der Wahrheit.

Authentifizierung

HTTP Basic Auth mit API-Key als Benutzername und API-Secret als Passwort. Der API-Benutzer braucht ausschließlich das Privileg „VPN: OpenVPN Client Export" — niemals einen Admin-Key.

Bei ungültigem Key antwortet OPNsense je nach Version mit 401 oder mit 200 und einer HTML-Loginseite. Der Client behandelt beides als ErrUnauthorized; die HTML-Erkennung prüft sowohl den Content-Type als auch ein führendes < im Body.

Akzeptierte Feldnamen

Der Client akzeptiert mehrere Schreibweisen und nimmt den ersten nicht-leeren Treffer (internal/opnsense/types.go, rawAccount):

Bedeutung Akzeptierte JSON-Felder
Common Name commonName, common_name
Beschreibung description, descr
Ablaufdatum validTo, valid_to, validto
Revoziert isRevoked, revoked, is_revoked
VPN-ID (Provider) vpnid, sonst der Map-Schlüssel
Instanzname name, description, sonst VPN <id>

Revoziert gilt, sobald eines der drei Felder wahr meldet — im Zweifel restriktiv. Als „wahr" zählen true, 1, "1", "true", "yes", "on".

Akzeptierte Datumsformate

time.RFC3339, 2006-01-02T15:04:05, 2006-01-02 15:04:05, 2006-01-02, Jan _2 15:04:05 2006 MST (OpenSSL-Stil), 060102150405Z (ASN.1 UTCTime) sowie Unix-Zeitstempel als Zahl.

Ein nicht auswertbares oder fehlendes Ablaufdatum führt nicht zum Ausschluss des Zertifikats — die Revocation-Prüfung bleibt maßgeblich, und ein unbekanntes Datum darf keine gültige Konfiguration blockieren. Der Integrationstest TestIntegrationAccountsExpiryIsParsed schlägt fehl, wenn kein Zertifikat ein auswertbares Datum liefert; das ist das Signal, die Layout-Liste zu ergänzen.

Antwortformen des Downloads

Zwei Varianten sind implementiert und werden am Content-Type unterschieden:

  1. Rohdaten (application/octet-stream o. ä.) — wird direkt durchgestreamt, nichts wird gepuffert oder auf Platte geschrieben. Der Dateiname kommt aus Content-Disposition.
  2. Base64 in JSON (application/json) — Feld content oder data, optional filename. Lässt sich der Inhalt nicht Base64-dekodieren, wird er als Klartext behandelt.

Unterstützte Exportformate

Das Portal bietet genau zwei Formate an: ovpn (inline .ovpn) und viscosity. Weitere Formate sind bewusst nicht wählbar.

Mindestversion

Beim ersten erfolgreichen Integrationstestlauf hier eintragen:

  • OPNsense: (zu ermitteln)
  • os-openvpn-client-export: (zu ermitteln)

Integrationstests ausführen

export OPNSENSE_URL="https://fw01.firma.local"
export OPNSENSE_KEY="..."
export OPNSENSE_SECRET="..."
export OPNSENSE_CA="/pfad/zur/firma-ca.pem"     # optional
export OPNSENSE_REVOKED_CN="testuser-revoked"   # optional, für den Revocation-Test
export OPNSENSE_VPNID="1"                       # optional, für den Export-Test
export OPNSENSE_CERT_REF="abc123"               # optional, für den Export-Test

go test -tags integration ./internal/opnsense/ -v

Ohne gesetzte Variablen überspringen sich die Tests selbst; sie laufen deshalb nie versehentlich in der normalen Testsuite mit.