Sicherheit & Authentifizierung

5 Min. Lesezeit

Sicherheit & Authentifizierung

PgArachne verlässt sich vollständig auf das PostgreSQL-Berechtigungssystem. Es erfindet keine Access Control Lists (ACLs) neu. PgArachne unterstützt vier Authentifizierungsmethoden. Die Methoden 1–3 verwenden SET LOCAL ROLE, um die Identität zu wechseln; Methode 4 (direkte Zugangsdaten) verbindet sich direkt als der jeweilige Benutzer, sodass kein Rollenwechsel nötig ist.

Dies gilt für die JSON-RPC- und MCP-Endpunkte. Der SSE-Endpunkt ist die eine Ausnahme — er authentifiziert den Aufrufer, wechselt aber weder die Rolle noch prüft er Berechtigungen auf Kanalebene, da PostgreSQL-LISTEN/NOTIFY-Kanäle keine Datenbankobjekte mit eigenen durchsetzbaren GRANTs sind. Was das in der Praxis bedeutet, steht auf der SSE-Seite.

1. Interaktives Login (JWT)

Benutzer authentifizieren sich mit ihrem echten PostgreSQL-Benutzernamen und -Passwort über die HTTP-Basic-Authentifizierung bei POST /{prefix}/{database}/token. Bei Erfolg erhalten sie ein kurzlebiges JWT. Nachfolgende Anfragen übermitteln dieses Token im Header Authorization: Bearer <token>, und PgArachne wechselt die aktive Rolle für die Dauer jeder Anfrage zu diesem Benutzer.

curl -X POST http://localhost:8080/db/my_database/token -u demo_user:user_password
→ {"token":"eyJhbGciOi...","token_type":"Bearer","expires_in":28800}

Die Zugangsdaten reisen im Authorization-Header, nie in einem JSON-Body, und das Login hat eine eigene URL, sodass ein Reverse-Proxy es ohne Lesen der Request-Bodies ratenbegrenzen kann. Die Antwort ist nie cachebar.

Erfordert JWT_SECRET. Ist es nicht konfiguriert, liefert der Endpunkt HTTP 404 (-32601), und Clients verwenden stattdessen direkte Zugangsdaten (Methode 4) oder API-Token (Methode 2).

2. Service-Konten (API-Token)

Für automatisierte Systeme oder Skripte werden langlebige API-Token empfohlen.

  • Token werden in der Tabelle pgarachne.api_tokens gespeichert.
  • Jedes Token ist einer bestimmten Datenbankrolle zugeordnet.
  • Senden Sie das Token über den Header Authorization: Bearer <token>.

Das Erstellen von API‑Tokens erfordert pgarachne_admin. Verwenden Sie pgarachne.add_api_token(...) mit einer Rolle, die Mitglied von pgarachne_admin ist.

3. Externer Identity Provider (eigenes JWT)

Wenn Benutzer außerhalb von PgArachne authentifiziert werden (z. B. über einen externen Auth-Dienst), kann dieser Dienst dort JWTs ausstellen und direkt an PgArachne senden.

  • Header-Format: Authorization: Bearer <jwt>.
  • Signatur: nur HMAC (HS256 / HS384 / HS512) mit demselben JWT_SECRET, der in PgArachne konfiguriert ist.
  • Pflicht-Claims: db_role (String, nicht leer) und db_name (String, muss mit dem :database-Pfadsegment übereinstimmen).
  • Pflicht-Claim: exp (Unix-Timestamp) für das Ablaufdatum.

Erfordert JWT_SECRET; ohne es werden Bearer-Werte nur als API-Token geprüft.

Minimales Payload-Beispiel:

{
  "db_role": "demo_user",
  "db_name": "my_database",
  "exp": 1767225600
}

Hinweis: asymmetrische JWT-Algorithmen (z. B. RS256 / ES256) werden nicht unterstützt.

4. Direkte Datenbankzugangsdaten (Basic Auth)

Die einfachste Option: Senden Sie den PostgreSQL-Benutzernamen und das Passwort mit jeder Anfrage über Standard-HTTP-Basic-Authentifizierung. PgArachne öffnet einen dedizierten Connection-Pool, der direkt als dieser Benutzer authentifiziert ist — SET LOCAL ROLE wird nicht ausgeführt.

Authorization: Basic <base64(username:password)>

Beispiel mit curl:

curl -X POST http://localhost:8080/db/my_database/jsonrpc \
  -u demo_user:user_password \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"api.hello_world","params":{},"id":1}'
Wann Sie direkte Zugangsdaten verwenden sollten:
  • Schnelles Prototyping und lokale Entwicklung — kein Token-Management erforderlich.
  • Interne Dienste, die Zugangsdaten bereits sicher verwalten.
  • Szenarien, in denen das vorherige Ausstellen eines JWT unnötige Komplexität hinzufügt.

Wesentliche Unterschiede zu den token-basierten Methoden:

  • Es ist kein GRANT demo_user TO pgarachne erforderlich — PgArachne wechselt keine Rollen.
  • PostgreSQL Row-Level Security und GRANT-Berechtigungen werden wie gewohnt durchgesetzt, da die Verbindung als der tatsächliche Benutzer läuft.
  • Verbindungs-Pools werden pro Benutzer für maximal 5 Minuten vorgehalten. Nach einer Passwortänderung laufen alte Verbindungen innerhalb dieses Zeitfensters ab.
  • Damit Idempotency Keys mit direkten Zugangsdaten funktionieren, erteilen Sie dem Benutzer EXECUTE ON FUNCTION pgarachne.save_idempotency_key(text, text).

Proxy-Privilegien: Nur für Methoden 1–3 erforderlich

Bei der JWT- und API-Token-Authentifizierung verbindet sich PgArachne als der in DB_USER definierte Systembenutzer (z. B. pgarachne) und wechselt die Identität über SET LOCAL ROLE. Der Systembenutzer muss Mitglied jeder Zielrolle sein.

-- Required for JWT / API-token auth only:
GRANT demo_user TO pgarachne;

Dieses GRANT ist nicht erforderlich, wenn Sie direkte Zugangsdaten (Methode 4) verwenden.

Vergleich der Authentifizierungsmethoden

MethodeHeaderSET LOCAL ROLEGRANT … TO pgarachneAm besten für
JWT (/token)Bearer <jwt>✅ JaErforderlichEndnutzer-Sitzungen
API-TokenBearer <token>✅ JaErforderlichAutomatisierte Dienste
Externes JWTBearer <jwt>✅ JaErforderlichIntegration externer Identity Provider
Direkte ZugangsdatenBasic <b64>❌ NeinNicht erforderlichEntwicklung, interne Dienste

Welche Funktionen aufrufbar sind

PgArachne hat keine eigene Schema-Allowlist — was eine Rolle aufrufen darf, entscheiden ausschließlich die PostgreSQL-Berechtigungen. Eine Funktion ist aufrufbar (und wird von capabilities, MCP tools/list und dem OpenAPI-Export aufgelistet), wenn sie einen einzigen jsonb-Parameter hat, die Rolle EXECUTE darauf hat und die Rolle USAGE auf ihrem Schema hat. Funktionen in pg_catalog, information_schema, pgarachne sowie Funktionen von Extensions werden der Übersichtlichkeit halber nicht aufgelistet, für sie gelten aber dieselben Berechtigungen.

Die PostgreSQL-Standardeinstellungen sind freizügig

Standardmäßig gewährt PostgreSQL EXECUTE auf jede neue Funktion an PUBLIC, und jede Rolle hat USAGE auf dem Schema public. Eine Hilfsfunktion public.something(jsonb) ist daher für jede authentifizierte Rolle über die API aufrufbar, solange Sie die Berechtigung nicht entziehen. Empfohlene Einrichtung:

-- New functions are not executable by everyone (run as the role that creates them):
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

-- Keep API functions in a dedicated schema and grant explicitly:
GRANT USAGE ON SCHEMA api TO demo_user;
GRANT EXECUTE ON FUNCTION api.hello_world(jsonb) TO demo_user;

Schutz vor Brute-Force-Angriffen

LOGIN_RATE_LIMIT und LOGIN_RATE_LIMIT_PER_IP gelten für jede Authentifizierungsmethode, auf jedem Endpunkt (JSON-RPC, MCP, SSE, OpenAPI):

  • /token: Jeder Versuch zählt gegen das Budget pro (IP, Benutzername) und das Budget pro IP.
  • Direkte Zugangsdaten (Basic Auth): Fehlgeschlagene Versuche zählen gegen das Budget pro (IP, Benutzername) und das Budget pro IP. Erfolgreiche Anfragen werden nicht gezählt, sodass ein legitimer Client, der bei jeder Anfrage Zugangsdaten sendet, nie gedrosselt wird.
  • Bearer-Token (JWT oder API-Token): Fehlgeschlagene Versuche zählen gegen das Budget pro IP.

Ist ein Budget aufgebraucht, werden weitere Versuche mit HTTP 429 abgewiesen, bis das Zeitfenster (LOGIN_RATE_WINDOW) abgelaufen ist — ohne die Zugangsdaten überhaupt zu prüfen.