BLOG | NGINX

Authentifizierung und inhaltsbasiertes Routing mit JWTs und NGINX Plus

NGINX-Teil-von-F5-horiz-schwarz-Typ-RGB
Alan Murphy Miniaturbild
Alan Murphy
Veröffentlicht am 01. März 2018

NGINX Plus Release 10 führte die Unterstützung für das Offloading der Authentifizierung von Web- und API-Diensten mit JSON Web Tokens (JWTs, ausgesprochen „Jots“) ein. Seit der Veröffentlichung von R10 haben wir die Funktionalität in jeder neuen Version kontinuierlich erweitert.

Ab NGINX Plus R14 unterstützt NGINX Plus JWTs, die verschachtelte Ansprüche und Array-Daten enthalten. Bei Verwendung in einem API-Gateway-Szenario kann NGINX Plus JWTs verwenden, um Clients zu authentifizieren, die Verbindungen zu Backend-Diensten und API-Zielen anfordern.

Ich wurde gelegentlich gebeten, eine Basiskonfiguration bereitzustellen, die NGINX Plus zur Authentifizierung von JWTs verwendet und dann basierend auf JWT-Informationen erweiterte Entscheidungen zum Lastenausgleich trifft. Die einfachste Lösung besteht darin, den Zugriff auf einen Dienst einfach zuzulassen, wenn die Authentifizierung erfolgreich ist, und die Verbindung zu blockieren oder umzuleiten, wenn sie nicht erfolgreich ist.

Die exemplarische Vorgehensweise in diesem Beitrag ist ein umfassender Proof of Concept für die JWT-Authentifizierung und das inhaltsbasierte Routing mit NGINX Plus. Um ein möglichst breites Spektrum an Möglichkeiten abzudecken und die Notwendigkeit von Vorkenntnissen oder Erfahrungen mit JWTs zu verringern, habe ich eine „JWT 101“-Anleitung erstellt, mit der Sie diese Lösung (mit Beispielen und Hintergrundinformationen) ohne Vorkenntnisse zu JWTs bereitstellen können.

Wenn Sie bereits über JWT-Erfahrung verfügen oder in Ihrer Umgebung bereits JWTs installiert sind, können Sie die ersten beiden Abschnitte überspringen und die bereitgestellten NGINX Plus-Konfigurationsausschnitte an Ihre Umgebung anpassen und mit der Erstellung erweiterter Entscheidungen zum Lastenausgleich auf Grundlage Ihrer JWT-Anspruchsdaten beginnen.

Voraussetzungen

Dieses Dokument setzt eine Neuinstallation von NGINX Plus mit Standardkonfigurationsdateien an den folgenden Speicherorten voraus:

  • /etc/nginx/nginx.conf
  • /etc/nginx/conf.d/default.conf

Weitere Informationen zur Installation und den ersten Schritten mit NGINX Plus finden Sie im NGINX Plus-Administratorhandbuch .

Alle CLI‑Befehle setzen Root‑ Berechtigungen voraus, daher müssen Nicht‑ Root‑ Benutzer in ihrer Umgebung über Sudo‑ Berechtigungen verfügen.

Weitere Hintergrundinformationen und andere Anwendungsfälle für JWTs mit NGINX Plus finden Sie unter den folgenden Links:

Erstellen eines JWT und des zugehörigen Signaturschlüssels

Die folgenden Anweisungen führen Sie durch die Erstellung eines JWT von Grund auf mit für unser Beispiel spezifischen Nutzlastdaten und veranschaulichen, wie NGINX Plus für die grundlegende Verarbeitung von JWT-Ansprüchen konfiguriert wird. Wenn Sie anstelle des Beispiel-JWT ein vorhandenes JWT verwenden, müssen Sie sicherstellen, dass Ihre „Secrets“-Datei die Base64URL-codierte Zeichenfolge enthält, die mit dem Signaturschlüssel übereinstimmt, den Sie zum Erstellen des JWT verwenden. Wahrscheinlich müssen Sie auch die Ansprüche in der JWT-Nutzlast ändern.

Notiz: Unabhängig davon, wie Sie Ihr JWT generieren, müssen Sie die Base64URL-Kodierung verwenden, die Auffüllungen (durchgeführt mit dem = -Zeichen) sowie andere nicht HTTP-kompatible Zeichen, die normalerweise in der Base64-Kodierung verwendet werden, korrekt verarbeitet. Viele Tools erledigen dies automatisch, manuelle CLI-basierte Base64-Encoder und einige JWT-Erstellungstools tun dies jedoch nicht. Weitere Informationen zur Base64URL-Kodierung finden Sie unter „Base64URL-Kodierung“ von Brock Allen und RFC 4648 .

Für dieses Beispiel verwenden wir die GUI unter jwt.io (die die Base64URL-Kodierung korrekt durchführt), um ein symmetrisches HS256-JWT zu erstellen. Der folgende Screenshot zeigt, wie die GUI aussieht, nachdem Sie die in den folgenden Anweisungen angegebenen Werte eingegeben und die Signatur überprüft wurde.

Erstellen Sie mithilfe der GUI unter jwt.io ein HS256 JWT, indem Sie die angegebenen Werte in den Feldern der Spalte „Decodiert“ auf der rechten Seite überprüfen oder einfügen:

  1. Überprüfen Sie, ob im Feld HEADER der folgende Standardwert angezeigt wird, und ändern Sie den Inhalt bei Bedarf entsprechend:

    { "alg": "HS256",
    "Typ": "JWT"
    }
  2. Ersetzen Sie im Feld „SIGNATURE VERIFY“ den Wert im Feld (standardmäßig „ secret“ ) durch nginx123 . (Sie nehmen diese Änderung vor, bevor Sie Daten in das Feld PAYLOAD eingeben, um ein Problem zu vermeiden, das auftritt, wenn Sie die beiden Schritte vertauschen.)

  3. Ersetzen Sie den Inhalt des Feldes PAYLOAD durch Folgendes:

    { "exp": 1545091200,
    "Name": "Neuen Benutzer erstellen",
    "sub": "cuser",
    "gname": "wheel",
    "guid": "10",
    "vollständigerName": „John Doe“, „uname“: „jdoe“, „uid“: "222",
    "sudo": wahr,
    "dept": "IT",
    "url": "http://secure.example.com"
    }

    Notiz: Der exp- Anspruch legt das Ablaufdatum und die Ablaufzeit des JWT fest und stellt es als UNIX-Epochenzeit dar (die Anzahl der Sekunden seit Mitternacht UTC am 1. Januar 1970 ). Der Beispielwert stellt Mitternacht UTC am 18. Dezember 2018 dar. Um das Ablaufdatum anzupassen, ändern Sie die Epochenzeit.

  4. Überprüfen Sie, ob die Leiste unter den Feldern blau ist und „Signatur überprüft“ anzeigt.

  5. Kopieren Sie den Wert in der linken Spalte „Kodiert“ in eine Datei oder einen Puffer. Es handelt sich um den vollständigen Text des JWT, den der Benutzer jdoe vorlegen muss, um auf http://secure.example.com zuzugreifen, und wir werden ihn in unseren Tests weiter unten verwenden. Wir zeigen das JWT hier aus Anzeigegründen mit Zeilenumbrüchen, es muss NGINX Plus jedoch als einzeilige Zeichenfolge präsentiert werden.

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOi
    JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkI
    joiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
    Iiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGx
    lLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

Befolgen Sie bei der Arbeit auf dem NGINX Plus-Host diese Schritte, um die Schlüsseldatei zu erstellen, die NGINX Plus zum Überprüfen von mit nginx123 signierten JWTs verwendet:

  1. Führen Sie diesen Befehl aus, um die Base64URL-codierte Zeichenfolge zu generieren, die der Signaturzeichenfolge entspricht. (Die tr -Befehle nehmen die für die Base64URL-Kodierung erforderlichen Zeichenersetzungen vor.)

    # echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '=' bmdpbngxMjM
  2. Erstellen Sie im Verzeichnis /etc/nginx/ die Schlüsseldatei namens api_secret.jwk, die von NGINX Plus zum Überprüfen von JWT-Signaturen verwendet werden soll. Fügen Sie den folgenden Inhalt ein. Der Wert im Feld „k“ ist die Base64URL-codierte Form von nginx123 , die wir im vorherigen Schritt generiert haben.

    {"keys": [{
    "k":"bmdpbngxMjM",
    "kty":"oct"
    }]
    }

Konfigurieren von NGINX Plus zur Handhabung von JWTs

Die Anweisungen in diesem Abschnitt konfigurieren NGINX Plus so, dass das in einer Anfrage enthaltene JWT validiert wird und bei autorisiertem Client eine geschützte Ressource angezeigt wird (anstelle der Standardseite, die nicht autorisierte Clients sehen). Wir definieren außerdem ein neues Protokollformat, das JWT-bezogene Informationen erfasst.

Konfigurieren der JWT-Validierung und des inhaltsbasierten Routings

In diesen Anweisungen folgen wir der bewährten Standardmethode, die Konfigurationsdatei default.conf umzubenennen, damit NGINX Plus sie nicht liest, und eine neue Konfiguration speziell zum Testen zu erstellen. Auf diese Weise können Sie die Standardkonfiguration problemlos wiederherstellen, wenn Sie mit dem Testen fertig sind oder während des Tests ein Problem auftritt.

  1. Benennen Sie default.conf um:

    # mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
  2. Erstellen Sie eine neue Konfigurationsdatei namens jwt-test.conf in /etc/nginx/conf.d/ mit dem folgenden Inhalt. Sie konfigurieren JWT-spezifisches Protokollieren, JWT-Validierung und inhaltsbasiertes Routing (eine vollständige Analyse folgt dem Snippet).

    Server {
    listen 80;
    access_log /var/log/nginx/host.access.log jwt;
    
    Standort / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    
    # JWT-Validierung
    auth_jwt „JWT-Testbereich“ token=$arg_myjwt;
    auth_jwt_key_file /etc/nginx/api_secret.jwk;
    error_log /var/log/nginx/host.jwt.error.log debug;
    
    if ( $jwt_claim_uid = 222 ) {
    add_header X-jwt-claim-uid „$jwt_claim_uid“ immer;
    add_header X-jwt-status „Umleitung zu $jwt_claim_url“ immer;
    return 301 $jwt_claim_url;
    }
    
    if ( $jwt_claim_uid != 222 ) {
    add_header X-jwt-claim-uid "$jwt_claim_uid" immer;
    add_header X-jwt-status "Ungültiger Benutzer, keine Weiterleitung" immer;
    }
    }
    }

Die Anweisungen im Standortblock teilen NGINX Plus mit, wie mit HTTP-Anfragen umgegangen werden soll, die ein JWT enthalten. (Informationen zur Protokollierungskonfiguration, die durch die Direktive access_log definiert wird, finden Sie im nächsten Abschnitt .) NGINX Plus führt diese Schritte aus:

  1. Extrahiert das JWT aus dem myjwt -Argument der Anforderungszeichenfolge (wie durch das Token -Argument der auth_jwt- Direktive angegeben).

  2. Dekodiert das JWT mit dem Signaturschlüssel, der durch die Direktive auth_jwt_key-file angegeben ist (hier: api_secret.jwk ). Es wirkt sich wie folgt auf die Nutzlast aus (diese Aktionen sind der JWT-Verarbeitung inhärent und haben keine entsprechenden NGINX Plus-Direktiven):

    • Überprüft, ob das JWT abgelaufen ist. Das bedeutet, dass das durch den Exp -Anspruch in der Nutzlast angegebene Ablaufdatum nicht in der Vergangenheit liegt.
    • Erstellt ein Schlüssel-Wert-Paar für jeden Anspruch in der Nutzlast. Der Schlüsselname ist eine Variable der Form $ jwt_claim_Anspruchsname (z. B. $jwt_claim_uid für den UID -Anspruch).
  3. Protokolliert alle Fehler auf Debugebene in /var/log/nginx/host.jwt.error.log .

  4. Prüft, ob der Wert von $jwt_claim_uid222 (wie durch die beiden if -Direktiven angegeben) und sendet die entsprechende Antwort an den Client. Auf diese Weise werden Informationen im JWT verwendet, um inhaltsbasiertes Routing durchzuführen.

    • Wenn der Wert222 , NGINX Plus sendet eine Antwort, die den Client (die Return -Direktive) an die im URL- Anspruch des JWt angegebene URL weiterleitet. Zu Debugging-Zwecken fügt es der Antwort zwei Header hinzu (die add_header -Direktiven): Der erste erfasst den Wert des UID -Anspruchs und der zweite zeichnet die Tatsache auf, dass der Client umgeleitet wurde.
    • Wenn der Wert nicht222 , NGINX Plus stellt die Standardindexseite bereit (wie durch die Root- und Indexdirektiven im selben Standortblock definiert). Wiederum zu Debuggingzwecken werden Header hinzugefügt, die den Wert des UID -Anspruchs erfassen und die Tatsache aufzeichnen, dass der Client keinen Zugriff auf die im JWT angegebene URL erhalten hat.

    Notiz: Die Verwendung der if -Direktive zum Auswerten von Variablen gilt im Allgemeinen nicht als bewährte Methode . Normalerweise empfehlen wir stattdessen die Verwendung der Map -Direktive. Für die Zwecke dieses einfachen Beispiels funktioniert die if -Direktive jedoch wie vorgesehen.

Tatsächlich ermöglicht die Konfiguration nur autorisierten Benutzern den Zugriff auf geschützte Ressourcen. Das heißt, Benutzer mit einem gültigen JWT erhalten Zugriff auf die im JWT angegebene URL, während Benutzer ohne gültiges JWT Zugriff auf eine Standardseite erhalten.

Protokollieren von JWT-Daten

Wir schließen die Konfiguration der JWT-Verarbeitung für inhaltsbasiertes Routing ab, indem wir ein Protokollierungsformat namens jwt definieren, auf das durch die Direktive access_log in jwt-test.conf verwiesen wird. Es erfasst JWT-Daten im Zugriffsprotokoll.

  1. Fügen Sie die folgende log_format- Direktive zu /etc/nginx/nginx.conf hinzu:

    log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
    '$jwt_header_alg $jwt_claim_uid $jwt_claim_url';

    Dieses Format umfasst die beiden JWT-Ansprüche, die in dieser exemplarischen Vorgehensweise verwendet werden ( uid und url ), Sie können jedoch beliebige JWT-Anspruchsdaten mit dem dem Anspruch entsprechenden Variablennamen in der Form $jwt_claim_claim ‑name protokollieren.

  2. Speichern Sie nginx.conf und führen Sie dann den folgenden Befehl aus, um die gesamte Konfiguration (einschließlich der neuen Datei jwt-test.conf ) auf syntaktische Gültigkeit zu testen. Korrigieren Sie alle gemeldeten Fehler.

    # nginx -t
  3. Laden Sie NGINX Plus neu.

    # nginx -s neu laden
    

Testen der Konfiguration

Mithilfe eines Browsers oder eines CLI-Tools wie curl können wir testen, ob NGINX Plus das JWT korrekt validiert, den Client authentifiziert, der es präsentiert, und ein inhaltsbasiertes Routing durchführt. (Um nur Authentifizierung und Validierung, nicht aber inhaltsbasiertes Routing zu testen, kommentieren Sie die beiden if- Blöcke in jwt-test.conf aus.)

Um den Test auszuführen, fügen wir das Argument myjwt in die Anforderungs-URL ein und geben den vollständigen Text des JWT an, in dem der URL- Anspruch enthalten ist.222 . Auch hier haben wir aus Anzeigegründen Zeilenumbrüche hinzugefügt.

http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
je1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

Hier ist der entsprechende Curl -Befehl (ohne Zeilenumbrüche, Sie können ihn also kopieren und einfügen, wenn Sie möchten):

# curl -v beispiel.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.YYQ CNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

Da der Wert des UID -Anspruchs im JWT222 , erwarten wir, dass NGINX Plus den Inhalt der eingeschränkten Seite http://secure.example.com anzeigt.

Nun testen wir, ob der URL -Anspruch im JWT nicht222 , NGINX Plus zeigt nicht den Inhalt der eingeschränkten Seite an, sondern präsentiert stattdessen die Seite index.html des lokalen Servers, in diesem Fall http://example.com/index.html .

Wir beginnen mit der Generierung eines weiteren JWT bei jwt.io mit einem anderen UID -Anspruch als222 ; der Einfachheit halber machen wir es111 . Hier ist die Anforderungs-URL mit diesem JWT:

http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
je1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5l
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg

Der Curl -Befehl lautet:

# curl -v beispiel.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg

In diesem Fall erwarten wir, dass NGINX Plus http://example.com/index.html bereitstellt.

Unter beiden Testbedingungen können Sie ein Header-Überprüfungstool (z. B. curl oder die mit einigen Browsern bereitgestellten Entwicklertools) verwenden, um zu überprüfen, ob die neuen Header X-jwt-claim-uid und X-jwt-status zur Antwort hinzugefügt wurden.

Wenn während des Tests Probleme auftreten, überprüfen Sie die Zugriffs- und Fehlerprotokolle unter /var/log/nginx/host.jwt* . Insbesondere das Fehlerprotokoll offenbart Probleme bei der Verifizierung, beim Zugriff auf deine Verifizierungsdatei usw.

Übergeben des JWT in einem Cookie

In unserem einfachen Beispiel extrahiert NGINX Plus das JWT aus dem myjwt -Argument der Anforderungs-URL. NGINX Plus unterstützt auch die Übergabe des JWT in einem Cookie (Einzelheiten finden Sie in der NGINX JWT- Referenzdokumentation). Ändern Sie in jwt-test.conf die Direktive auth_jwt so, dass das erste Element im Token- Parameter $cookie statt $arg ist:

auth_jwt "JWT-Testbereich" token=$cookie_myjwt;

Um das JWT in einem Cookie namens myjwt bereitzustellen, lautet der entsprechende Curl -Befehl:

# curl -v --cookie myjwt= JWT-Text beispiel.com/index.html

Probieren Sie inhaltsbasiertes Routing mit JWTs selbst aus: Starten Sie noch heute Ihre kostenlose 30-Tage-Testversion von NGINX oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen .


„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."