Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
102 lines
4.1 KiB
Markdown
102 lines
4.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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.
|