SSO für jede App mit oauth2-proxy einrichten
Schützen Sie eine Anwendung ohne eigenen Login mit OIDC: Konfiguration für oauth2-proxy in nginx oder Traefik sowie typische Cookie- und Redirect-Fehler.
Weiterleitungsbasierte Authentifizierung: SSO für eine Anwendung ohne eigenen Login
oauth2-proxy stellt Single Sign-on für eine Anwendung bereit, die keinen eigenen Login besitzt. Das funktioniert, weil der vorgeschaltete Reverse Proxy jede Anfrage anhält, oauth2-proxy fragt, ob die Anfrage eine gültige Sitzung enthält, und die Anfrage nur dann an das Upstream weiterleitet, wenn die Antwort positiv ausfällt. Der Anwendungscode muss nicht geändert werden, weil die Anwendung diese Prüfung nie sieht.
Die Prüfung besteht aus einer zusätzlichen HTTP-Anfrage. Der Proxy sendet eine Kopie der Header der eingehenden Anfrage an /oauth2/auth und liest den Statuscode. 202 bedeutet, dass der Aufrufer eine Sitzung besitzt. Der Proxy leitet die ursprüngliche Anfrage deshalb an die Anwendung weiter. 401 bedeutet, dass keine Sitzung vorhanden ist. Der Proxy leitet den Browser deshalb an /oauth2/sign_in weiter. Dort wird eine OpenID-Connect-Anmeldung (OIDC) bei Ihrem Identity Provider gestartet. OIDC ist die Identitätsschicht auf Basis von OAuth 2.0. Als Provider dient die Lösung, die Sie bereits für Anmeldungen verwenden.
Dieses Muster hat in jedem Reverse Proxy eine eigene Bezeichnung. Nginx nennt die Direktive auth_request. Traefik nennt die Middleware forwardAuth. Caddy schreibt sie forward_auth. Auch der Dienst, der die Subrequest beantwortet, kann ausgetauscht werden. oauth2-proxy ist eine gängige Wahl, weil es direktes OIDC unterstützt und keine eigene Datenbank benötigt.
Vertrauensgrenze festlegen, bevor Sie eine Konfiguration schreiben
Nach einer erfolgreichen Prüfung gibt oauth2-proxy die Identität als Response-Header zurück. Der Reverse Proxy übernimmt diese Header in die Anfrage an das Upstream-System. Mit aktivierter Option set_xauthrequest erhalten Sie X-Auth-Request-User und X-Auth-Request-Email. Die Anwendung liest diese Header und vertraut ihnen.
Das ist das gesamte Sicherheitsmodell. Deshalb muss die Konsequenz klar benannt werden: Alles, was eine TCP-Verbindung zum Anwendungsport öffnen kann, kann diese Header selbst setzen und sich als beliebiger Benutzer ausgeben. Ein einzelnes curl -H "X-Auth-Request-Email: admin@example.com" http://app-host:3000/ reicht für eine vollständige Umgehung aus, wenn es die Anwendung direkt erreicht.
Die Anwendung darf daher nur über den Proxy erreichbar sein. Löschen Sie in Docker Compose das Mapping ports: aus dem Anwendungsdienst. Lassen Sie den Dienst im internen Netzwerk, damit nur der Proxy-Container eine Verbindung zu ihm herstellen kann. Binden Sie die Anwendung auf einem Hostsystem an 127.0.0.1:3000 statt an 0.0.0.0:3000. Prüfen Sie anschließend, was tatsächlich veröffentlicht ist:
sudo ss -tlnp | grep 3000Eine Zeile mit 0.0.0.0:3000 bedeutet, dass die Anwendung auf der öffentlichen IP-Adresse antwortet und Ihre Zugriffssperre nur der Form halber existiert. 127.0.0.1:3000 ist der gewünschte Zustand. Eine Firewall-Regel ist eine sinnvolle zusätzliche Schutzschicht. Die Bind-Adresse bleibt jedoch wirksam, wenn ein anderes Tool Ihren Regelsatz leert.
oauth2-proxy installieren
Im August 2026 ist v7.15.3 die aktuelle Version. Sie wurde im Juni 2026 veröffentlicht. Installieren Sie die Binärdatei und prüfen Sie den Download:
cd /tmp
curl -fsSLO https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.15.3/oauth2-proxy-v7.15.3.linux-amd64.tar.gz
curl -fsSLO https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.15.3/oauth2-proxy-v7.15.3.linux-amd64.tar.gz-sha256sum.txt
sha256sum -c oauth2-proxy-v7.15.3.linux-amd64.tar.gz-sha256sum.txt
tar -xzf oauth2-proxy-v7.15.3.linux-amd64.tar.gz
sudo install -m 755 oauth2-proxy-v7.15.3.linux-amd64/oauth2-proxy /usr/local/bin/oauth2-proxy
oauth2-proxy --versionsha256sum -c muss eine Zeile ausgeben, die mit OK endet. Wenn FAILED ausgegeben wird, beenden Sie den Vorgang und laden Sie die Datei erneut herunter, anstatt die Binärdatei auszuführen.
In Docker lautet das Image quay.io/oauth2-proxy/oauth2-proxy. Sie sollten den Tag festlegen: quay.io/oauth2-proxy/oauth2-proxy:v7.15.3. Wenn latest verwendet wird, wird aus einem routinemäßigen docker compose pull ein ungeplantes Upgrade des einzigen Prozesses, der alle Anwendungen auf dem Server schützt.
Cookie-Secret generieren
Das Session-Cookie ist verschlüsselt, und cookie_secret ist der Schlüssel. Er muss genau 16, 24 oder 32 Byte lang sein, weil daraus ein AES-Schlüssel (Advanced Encryption Standard) wird. Bei jeder anderen Länge verweigert oauth2-proxy den Start und gibt eine Fehlermeldung zum Cookie-Secret aus.
openssl rand -base64 32 | tr -- '+/' '-_'Der tr ist nicht nur eine kosmetische Anpassung. Er wandelt Standard-Base64 in das URL-sichere Alphabet um. Dadurch bleibt der Wert in einer Shell, einer Env-Datei und einem HTTP-Header ohne Probleme mit dem Quoting erhalten.
Für diesen Wert gelten zwei Regeln. Verwenden Sie für jedes Deployment ein anderes Secret. Wenn Sie mehrere oauth2-proxy-Instanzen hinter derselben Domain betreiben, müssen alle dasselbe Secret verwenden. Ein von einer Instanz verschlüsseltes Cookie muss von den anderen Instanzen gelesen werden können.
Konfiguration für oauth2-proxy schreiben
Legen Sie die Einstellungen in einer Datei ab, statt eine lange Befehlszeile zu verwenden. Dadurch erscheint das Client-Secret nie in der Ausgabe von ps.
# /etc/oauth2-proxy/oauth2-proxy.cfg
http_address = "127.0.0.1:4180"
reverse_proxy = true
provider = "oidc"
oidc_issuer_url = "https://id.example.com/application/o/myapp/"
client_id = "REPLACE_ME"
client_secret = "REPLACE_ME"
redirect_url = "https://app.example.com/oauth2/callback"
cookie_secret = "REPLACE_ME"
cookie_secure = true
cookie_domains = [".example.com"]
whitelist_domains = [".example.com"]
email_domains = ["*"]
set_xauthrequest = true
upstreams = ["static://202"]reverse_proxy = true weist oauth2-proxy an, den X-Forwarded-*-Headern des vorgeschalteten Proxys zu vertrauen. Ohne diese Einstellung behandelt oauth2-proxy die eigene Adresse des Proxys als Client-Adresse. Dadurch kann die Prüfung, ob die Anfrage über HTTPS eingegangen ist, falsch ausfallen.
upstreams = ["static://202"] bewirkt, dass oauth2-proxy auf eine authentifizierte Anfrage mit 202 antwortet und keinen Inhalt proxyt. Genau das benötigt Forward Auth, weil der Reverse Proxy das Proxying übernimmt. Bei der anderen Bereitstellungsform steht oauth2-proxy mit upstreams = ["http://127.0.0.1:3000"] direkt im Anfragepfad und verwendet überhaupt kein auth_request. Das ist für eine einzelne Anwendung einfacher, lässt sich aber nicht auf zehn Anwendungen erweitern.
email_domains = ["*"] lässt jede Adresse zu, die Ihr Provider authentifiziert. Beschränken Sie den Wert auf Ihre eigene Domain. Besser ist es, den Zugriff beim Provider über eine Gruppenbindung einzuschränken, weil Sie dort bereits die Benutzer verwalten.
Führen Sie den Dienst unter systemd mit einem eigenen Benutzer aus:
# /etc/systemd/system/oauth2-proxy.service
[Unit]
Description=oauth2-proxy
After=network-online.target
Wants=network-online.target
[Service]
User=oauth2-proxy
Group=oauth2-proxy
ExecStart=/usr/local/bin/oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg
Restart=on-failure
ProtectSystem=strict
PrivateTmp=true
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetsudo useradd --system --no-create-home --shell /usr/sbin/nologin oauth2-proxy
sudo install -d -m 750 /etc/oauth2-proxy
sudo chown -R oauth2-proxy:oauth2-proxy /etc/oauth2-proxy
sudo chmod 600 /etc/oauth2-proxy/oauth2-proxy.cfg
sudo systemctl daemon-reload
sudo systemctl enable --now oauth2-proxy
curl -s http://127.0.0.1:4180/pingWenn /ping OK ausgibt, wurde der Prozess gestartet und seine Konfiguration geladen. Dies ist der eigene Health-Endpunkt von oauth2-proxy. Er fordert niemals eine Sitzung an. Wenn keine Antwort erfolgt, prüfen Sie journalctl -u oauth2-proxy -n 50. Eine falsche Issuer-URL und ein Cookie-Secret mit falscher Länge führen beide bereits beim Start zum Fehler. Beide Ursachen werden dort angegeben.
Registrieren Sie die Redirect-URI bei Ihrem Provider
Erstellen Sie bei Ihrem Provider eine OIDC-Anwendung und setzen Sie ihre Redirect-URI exakt auf den redirect_url aus der Konfiguration: https://app.example.com/oauth2/callback. Exakt bedeutet, dass Schema, Host, Port und Pfad Zeichen für Zeichen übereinstimmen. Ein abschließender Schrägstrich macht daraus eine andere URI.
Dies ist der häufigste Fehler in der gesamten Einrichtung. Er tritt auf, bevor oauth2-proxy überhaupt beteiligt ist. Der Provider lehnt die Autorisierungsanfrage ab und zeigt seine eigene Fehlerseite an. Deshalb erscheint nichts im oauth2-proxy-Log. Erkennbar ist der Fehler an der Adressleiste: Der Browser befindet sich weiterhin auf der Domain Ihres Providers, und die Query-Zeichenfolge enthält error=invalid_request oder die Seite benennt direkt redirect_uri. Wenn Sie das sehen, korrigieren Sie den Anwendungseintrag beim Provider, nicht die Proxy-Konfiguration.
Kopieren Sie die Issuer-URL aus dem Provider, statt sie einzugeben. oauth2-proxy hängt /.well-known/openid-configuration an oidc_issuer_url an und ruft dieses Discovery-Dokument beim Start ab. Prüfen Sie es zuerst selbst:
curl -s https://id.example.com/application/o/myapp/.well-known/openid-configuration | head -c 400JSON mit einem authorization_endpoint-Schlüssel bedeutet, dass die Issuer-URL korrekt ist. Eine 404- oder HTML-Fehlerseite bedeutet, dass sie falsch ist. oauth2-proxy kann bei genau diesem 404-Fehler ebenfalls nicht starten. Wenn Sie noch keinen Provider ausgewählt haben, behandelt der Vergleich von Keycloak, Authentik und Zitadel die jeweiligen Vor- und Nachteile. Authentik als eigenen SSO-Server betreiben beschreibt den Provider-Teil genau dieser Einrichtung.
Nginx: auth_request
Nginx übernimmt die Authentifizierung per Forward Auth mit auth_request. Dabei wird eine interne Subrequest ausgelöst und anhand ihres Statuscodes verzweigt.
# in the http context, next to your other maps
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name app.example.com;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location / {
auth_request /oauth2/auth;
error_page 401 = @oauth2_signin;
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location @oauth2_signin {
return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
}
}Drei Details sind dabei wichtig. proxy_pass_request_body off mit einem leeren Content-Length verhindert, dass nginx den Body jedes POST in die Subrequest kopiert. Das ist relevant, weil oauth2-proxy den Body nicht auswertet. Bei einem Datei-Upload würde die Standardkonfiguration die Datei zweimal übertragen.
Das Paar aus auth_request_set $auth_cookie und add_header Set-Cookie übergibt ein erneuertes Session-Cookie zurück an den Browser. Fehlt es, bewirkt cookie_refresh unbemerkt nichts, weil nginx das Set-Cookie der Subrequest verwirft. Der Browser behält dann den alten Wert, bis die Session abläuft.
error_page 401 = @oauth2_signin wandelt eine fehlgeschlagene Prüfung in eine Anmeldung um. Ohne diese Direktive erhält ein nicht authentifizierter Besucher lediglich eine leere 401 Authorization Required-Seite und kann nicht fortfahren.
Testen Sie die Konfiguration immer vor dem Neuladen:
sudo nginx -t && sudo systemctl reload nginxWenn Ihnen die umgebenden Direktiven noch nicht vertraut sind, erklärt der Aufbau einer nginx-Reverse-Proxy-Konfiguration die darunterliegende Schicht.
Traefik: forwardAuth-Middleware
Traefik benötigt für diese Aufgabe zwei Middlewares. Eine führt die Prüfung aus. Die andere wandelt den Status 401 in eine Browser-Weiterleitung um.
# dynamic configuration
http:
middlewares:
oauth-auth:
forwardAuth:
address: https://oauth.example.com/oauth2/auth
trustForwardHeader: true
oauth-errors:
errors:
status:
- "401-403"
service: oauth-backend
query: "/oauth2/sign_in?rd={url}"
statusRewrites:
"401": 302Binden Sie beide an den Router an, der Ihrer Anwendung vorgeschaltet ist, und veröffentlichen Sie oauth2-proxy über einen eigenen Router unter oauth.example.com, weil der Browser /oauth2/sign_in und /oauth2/callback erreichen muss, ohne die Prüfung zu durchlaufen.
statusRewrites, das 401 in 302 umzuwandeln, wird häufig übersehen. Ohne diese Einstellung liefert Traefik die Anmeldeweiterleitung mit dem Status 401 zurück. Der Browser folgt ihr nicht, und der Besucher sieht eine Seite, die nur das Wort Found. enthält.
trustForwardHeader: true leitet den ursprünglichen Host und die URI an oauth2-proxy weiter. oauth2-proxy benötigt diese Angaben, um den Wert rd zu erstellen, der den Benutzer auf die angeforderte Seite zurückführt. Setzen Sie whitelist_domains so, dass dieser Host ebenfalls abgedeckt ist. Andernfalls verwirft oauth2-proxy den Parameter rd wegen des Risikos einer offenen Weiterleitung, und alle Benutzer landen nach der Anmeldung auf /. Ein Traefik-Server ist normalerweise mehreren Anwendungen vorgeschaltet. Mehrere Docker-Compose-Anwendungen über eine Traefik-Instanz routen zeigt den Aufbau der Router, in den diese Konfiguration eingebunden wird.
Caddy: forward_auth
app.example.com {
handle /oauth2/* {
reverse_proxy oauth2-proxy.internal:4180 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Uri {uri}
}
}
handle {
forward_auth oauth2-proxy.internal:4180 {
uri /oauth2/auth
header_up X-Real-IP {remote_host}
copy_headers X-Auth-Request-User X-Auth-Request-Email
@error status 401
handle_response @error {
redir * /oauth2/sign_in?rd={scheme}://{host}{uri}
}
}
reverse_proxy upstream.internal:3000
}
}Die Reihenfolge ist hier entscheidend. Der Block /oauth2/* kommt zuerst und enthält kein forward_auth, weil ein nicht angemeldeter Besucher die Anmelde- und Callback-Pfade erreichen muss. Wenn Sie die Prüfung vor diese Pfade setzen, leitet die Anmeldung so lange auf sich selbst weiter, bis der Browser abbricht.
copy_headers überträgt die Identität an die Anfrage an das Upstream-System. Dieser Mechanismus liefert nur Werte, wenn oauth2-proxy mit set_xauthrequest = true ausgeführt wird. Die Auswahl zwischen den Proxys ist eine eigene Frage. Der Vergleich von nginx, Caddy und Traefik behandelt sie.
Warum führt die Anmeldung wieder zur Anmeldeseite?
Sie melden sich beim Anbieter an, werden zurückgeleitet, und oauth2-proxy leitet Sie sofort wieder zum Anbieter weiter. Die Schleife bedeutet, dass die Callback-Anfrage ohne das Cookie eingetroffen ist, das oauth2-proxy beim Weiterleiten gesetzt hat. Das Log nennt diesen Fall:
No cookies were found in OAuth callback.oder, wenn ein anderes Cookie angekommen ist, aber nicht das richtige:
Cookies were found in OAuth callback, but none was a CSRF cookie.CSRF steht für Cross-Site Request Forgery. Dieses Cookie stellt sicher, dass ein Callback der Anmeldung zugeordnet werden kann, die ihn gestartet hat. Der Browser zeigt denselben Fehler so an:
Login Failed: Unable to find a valid CSRF token. Please try again.Prüfen Sie diese vier Ursachen in der angegebenen Reihenfolge.
cookie_secure = true, während der Browser die Website über unverschlüsseltes HTTP erreicht hat. Ein Browser speichert ein Cookie mit dem AttributSecurenicht für einehttp://-Origin. Daher wird es nie zurückgesendet. Terminieren Sie TLS (Transport Layer Security) ordnungsgemäß, oder setzen Siecookie_secure = falsenur während Tests auf localhost.- Ein Wert für
cookie_domains, der den Hostnamen in der Adressleiste nicht abdeckt..example.comgilt fürapp.example.comund hat fürapp.example.netkeinerlei Wirkung. - Der Browser verwirft das Cookie. Eine strenge Datenschutz-Erweiterung oder die Blockierung von Cookies anderer Websites kann
_oauth2_proxy_csrfzwischen der ausgehenden Weiterleitung und dem Callback entfernen. - Eine abweichende Systemzeit. Wenn die Serveruhr deutlich von der Uhr des Anbieters abweicht, liegen
iatundexpdes ID-Tokens außerhalb des akzeptierten Zeitfensters, und die Sitzung wird beim Eintreffen abgelehnt.timedatectlsollteSystem clock synchronized: yesmelden.
Beobachten Sie den Ablauf serverseitig, statt die Ursache zu vermuten:
sudo journalctl -u oauth2-proxy -fLaden Sie die Anwendung in einem privaten Fenster. Jede Anfrage wird mit ihrem Status protokolliert. Ein Callback, auf den unmittelbar eine weitere Weiterleitung zum Anbieter folgt, ist die Schleife und im Log eindeutig erkennbar.
Pfade, die den Login umgehen müssen: APIs, Webhooks und Websockets
Forward Auth setzt voraus, dass ein Browser ein Cookie hält. Aufrufer ohne Browser funktionieren damit nicht.
Ein API-Client, der Authorization: Bearer <token> sendet, hat kein Cookie. Er erhält daher eine 302-Weiterleitung zur Login-Seite Ihres Providers und versucht anschließend, HTML als JSON zu verarbeiten. Dafür gibt es zwei saubere Lösungen. Mit skip_jwt_bearer_tokens = true akzeptiert oauth2-proxy ein gültiges Bearer-Token als JWT (JSON Web Token) vom selben Aussteller. Das ist sinnvoll, wenn Ihre API-Clients bereits Tokens vom Provider erhalten. Andernfalls nehmen Sie den Pfad von der Prüfung aus:
skip_auth_routes = [
"^/api/",
"POST=^/webhook/",
"GET=^/healthz$"
]Jeder Wert ist ein regulärer Ausdruck, der gegen den normalisierten Pfad geprüft wird. Optional kann ihm eine HTTP-Methode und = vorangestellt werden. POST=^/webhook/ lässt den Webhook-Empfänger für POST offen, während ein Benutzer, der denselben Pfad im Browser aufruft, weiterhin den Login durchläuft. Jeder Eintrag erzeugt eine Lücke in Ihrer Zugriffssperre. Verankern Sie die Ausdrücke daher mit ^ und halten Sie sie so eng wie vom Aufrufer erlaubt.
Websockets werden häufig falsch behandelt. Die Upgrade-Anfrage ist ein gewöhnlicher HTTP-GET mit denselben Cookies wie jede andere Anfrage. Sie passiert die Prüfung daher normalerweise und benötigt keine Ausnahme. Fehler treten bei der Weiterleitung auf. Ohne die Header Upgrade und Connection am geschützten Standort wird das Upgrade nicht abgeschlossen. Der Client der Anwendung versucht dann dauerhaft erneut, wobei in der Browserkonsole eine Meldung mit WebSocket connection ... failed erscheint. Den Pfad von der Prüfung auszunehmen, behebt das Problem nicht, weil die Anfrage bereits autorisiert war.
Eine tatsächliche Einschränkung bleibt. Die Prüfung läuft einmal beim Upgrade. Ein Websocket, der über Stunden geöffnet bleibt, wird nicht erneut geprüft. Wenn Sie einen Benutzer beim Provider entfernen, wird der bereits bestehende Socket daher nicht geschlossen. Starten Sie die Anwendung neu, um aktive Verbindungen zu trennen.
Sitzungsspeicherung und ein zu großer Cookie
Standardmäßig liegt die gesamte Sitzung verschlüsselt mit Ihrem cookie_secret im Cookie. Dadurch bleibt oauth2-proxy zustandslos und benötigt keinen zusätzlichen Dienst. Die Größe ist jedoch begrenzt, weil Browser einen Cookie auf ungefähr 4 KB begrenzen. Wenn das ID-Token eine lange Liste von Gruppen-Claims enthält, teilt oauth2-proxy die Sitzung auf _oauth2_proxy_0, _oauth2_proxy_1 und weitere Cookies auf. Nach einigen Teilen werden die Request-Header so groß, dass nginx mit 400 Request Header Or Cookie Too Large antwortet, bevor die Anwendung den Request überhaupt erhält.
Verschieben Sie die Sitzung in diesem Fall auf die Serverseite:
session_store_type = "redis"
redis_connection_url = "redis://127.0.0.1:6379"Der Browser enthält dann nur ein kurzes Ticket. Die verschlüsselte Sitzung liegt in Redis. Dafür muss ein zusätzlicher Dienst dauerhaft verfügbar sein. Wenn Redis ausfällt, werden alle Sitzungen ungültig und alle Benutzer gleichzeitig abgemeldet. Der Cookie-Speicher hat ein eigenes Problem: Wenn zwei Requests dieselbe Sitzung gleichzeitig aktualisieren, können sie miteinander kollidieren und eine erneute Anmeldung erzwingen.
Was Forward Auth nicht leistet
Dies ist eine Zugangssperre vor der Anwendung. Sie ersetzt keine Autorisierung innerhalb der Anwendung. Dieser Unterschied entscheidet, ob der Ansatz für Ihren Anwendungsfall geeignet ist.
Sobald ein Benutzer die Sperre passiert hat, sieht die Anwendung weiterhin genau das, was sie zuvor gesehen hat. Wenn die Anwendung eigene Rollen verwendet, füllt Forward Auth diese nicht aus. Das funktioniert nur, wenn die Anwendung eine headerbasierte Authentifizierung unterstützt und einen Header einem Konto zuordnet. Grafana unterstützt dies über seine auth.proxy-Einstellungen. Die meisten selbst gehosteten Anwendungen unterstützen dies nicht. Für die Anwendung sind daher alle Benutzer, die die Sperre passieren, dieselbe einzelne Identität. Dabei handelt es sich häufig um ein Administratorkonto.
Die eigenen API-Tokens der Anwendung werden ebenfalls nicht geschützt. Ein von der Anwendung ausgestelltes persönliches Zugriffstoken authentifiziert sich bei der Anwendung, nicht bei oauth2-proxy. Das Token funktioniert daher nicht mehr, sobald die Sperre davor steht. Wenn Sie den API-Pfad ausnehmen, funktioniert das Token wieder. Dann ist dieses Token jedoch die einzige Schutzmaßnahme für den Pfad. Sie betreiben nun zwei Authentifizierungssysteme für einen Dienst. SSO deckt nur eines davon ab.
Der dritte Schwachpunkt ist der Widerruf. Wenn Sie einen Benutzer bei Ihrem Provider löschen, verhindert dies neue Anmeldungen und die von cookie_refresh durchgeführte Token-Erneuerung. Ein vorhandenes Session-Cookie bleibt jedoch bis zu seinem Ablauf gültig. cookie_expire ist standardmäßig auf 168 hours gesetzt. Für einen gerade entfernten Benutzer bedeutet das eine weitere Woche Zugriff. Setzen Sie cookie_refresh auf einen kurzen Zeitraum, beispielsweise eine Stunde. Dadurch wird der Widerruf innerhalb dieses Zeitfensters wirksam.
Auch der Audit-Trail endet an der Zugangssperre. oauth2-proxy protokolliert, wer die Sperre wann passiert hat. Die Anwendung protokolliert eine nicht benannte Sitzung. Wenn Sie beantworten müssen, wer eine Einstellung geändert hat, ist eine Identität per Header in der Anwendung die Mindestanforderung. Echte Benutzerkonten pro Person sind die belastbare Lösung.
Wenn die SSO-Kosten die bessere Lösung sind
Forward Auth ist das richtige Werkzeug, wenn eine Anwendung überhaupt keine Anmeldung oder nur ein gemeinsames Passwort bietet und Sie Benutzer an einer zentralen Stelle hinzufügen und entfernen möchten. Die Einrichtung kostet einen Nachmittag und einen zusätzlichen Prozess. Sie funktioniert mit jeder Anwendung, die HTTP unterstützt.
Das Werkzeug ist ungeeignet, wenn verschiedene Personen innerhalb derselben Anwendung unterschiedliche Berechtigungen benötigen. Ein vorgeschaltetes Tor kann nicht ausdrücken: „Ana darf die Dashboards bearbeiten, Bo darf sie nur lesen.“ Wenn der Anbieter eine SSO-Stufe verkauft, ist die Zuordnung von Gruppen zu Rollen in der Regel genau das, wofür Sie bezahlen. Diese Zuordnung mit Headern und Proxy-Regeln nachzubauen, ist anfälliger, als dafür zu bezahlen. Das Preismodell hinter diesen SSO-Stufen sollten Sie lesen, bevor Sie sich entscheiden.
Zwei weitere Situationen weisen in dieselbe Richtung. Compliance-Anforderungen, die benutzerbezogene Audit-Datensätze innerhalb der Anwendung erfordern, akzeptieren ein Proxy-Access-Log nicht als Nachweis. Jede Anwendung mit einem mobilen oder Desktop-Client, der keine Browser-Cookies überträgt, wird bei jeder Anfrage mit dem vorgeschalteten Zugriffsschutz Probleme haben.
FAQ
Was ist Forward Auth?
Forward Auth ist ein Muster, bei dem der Reverse Proxy vor der Weiterleitung an das Upstream-Backend einen separaten Authentifizierungsdienst zu jeder eingehenden Anfrage befragt. Der Proxy sendet die Request-Header an einen Endpunkt wie /oauth2/auth und liest den Statuscode aus. 202 bedeutet, dass die Anfrage zulässig ist, und die ursprüngliche Anfrage wird an die Anwendung weitergeleitet. 401 bedeutet, dass keine Sitzung vorhanden ist, und der Proxy leitet den Browser zur Anmeldung weiter. Nginx implementiert dies mit der Direktive auth_request, Traefik mit der Middleware forwardAuth und Caddy mit forward_auth.
Warum leitet mich oauth2-proxy in einer Schleife immer wieder zur Anmeldeseite weiter?
Die Callback-Anfrage hat oauth2-proxy ohne sein CSRF-Cookie erreicht. Deshalb startet oauth2-proxy den Ablauf neu. Im Server-Log steht No cookies were found in OAuth callback. und im Browser wird Login Failed: Unable to find a valid CSRF token. Please try again. angezeigt. Die häufigste Ursache ist cookie_secure = true auf einer Website, die der Browser über unverschlüsseltes HTTP erreicht hat, weil ein Browser kein Secure-Cookie für einen http://-Ursprung speichert. Die zweithäufigste Ursache ist ein cookie_domains-Wert, der den Hostnamen in der Adressleiste nicht abdeckt.
Wie kann ich einen API-Client oder einen Webhook durch oauth2-proxy lassen?
Verwenden Sie skip_auth_routes mit einem regulären Ausdruck und festgelegten Anfangs- und Endpunkten, optional auf eine HTTP-Methode begrenzt, zum Beispiel POST=^/webhook/. Wenn Ihre API-Clients bereits JWTs besitzen, die vom selben Provider ausgestellt wurden, akzeptiert skip_jwt_bearer_tokens = true diese Tokens anstelle eines Cookies, und der Pfad bleibt geschützt. Alles, was in skip_auth_routes aufgeführt ist, ist für alle nicht authentifiziert. Halten Sie deshalb jeden Ausdruck so eng wie es der Aufrufer erlaubt.
Gewährt oauth2-proxy der Anwendung benutzerspezifische Berechtigungen?
Nein. Es ist ein Zugangstor, aber kein Autorisierungssystem. Es entscheidet, wer die Anwendung erreicht. Für die Anwendung sehen jedoch alle erreichten Benutzer identisch aus, sofern die Anwendung Identitäts-Header ausliest und sie Benutzerkonten zuordnet. Grafana kann dies über seine auth.proxy-Einstellungen umsetzen. Die meisten selbst gehosteten Anwendungen können das nicht. Deshalb teilen sich alle Personen hinter dem Zugangstor dieselbe Identität, unter der die Anwendung ausgeführt wird.
Kann jemand oauth2-proxy umgehen, indem er den Identitäts-Header selbst setzt?
Ja, sofern die Person die Anwendung direkt erreichen kann. Die Identität wird als einfacher Header wie X-Auth-Request-Email übermittelt. Die Anwendung vertraut auf den empfangenen Wert. Jeder, der eine Verbindung zum Anwendungsport öffnen kann, kann diesen Header senden und sich als beliebiger Benutzer ausgeben. Binden Sie die Anwendung an 127.0.0.1, oder betreiben Sie sie in einem internen Docker-Netzwerk ohne veröffentlichten Port, und bestätigen Sie dies mit sudo ss -tlnp.