Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
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:
- Rohdaten (
application/octet-streamo. ä.) — wird direkt durchgestreamt, nichts wird gepuffert oder auf Platte geschrieben. Der Dateiname kommt ausContent-Disposition. - Base64 in JSON (
application/json) — Feldcontentoderdata, optionalfilename. 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.