Von OpenAPI zu NGINX als API-Gateway mit einer deklarativen API

NGINX | 17. Juni 2024

NGINX gilt seit Langem als eine der besten Lösungen für den Betrieb leistungsstarker Webserver und Load Balancer. Mit dem Aufkommen von Microservices-Architekturen und dem wachsenden Bedarf an effizientem API-Management hat sich NGINX jedoch auch zu einer beliebten Lösung für die Entwicklung von API-Gateways entwickelt.

In diesem Blogbeitrag zeigen wir, wie sich eine OpenAPI-Schemadefinition in eine voll funktionsfähige NGINX-Konfiguration umwandeln lässt, die als API-Gateway mit Web Application Firewall-Sicherheit und einem Entwicklerportal unter Verwendung eines deklarativen API-Ansatzes betrieben wird.

Wir bieten Ihnen eine Schritt-für-Schritt-Anleitung und zeigen Ihnen, wie Sie NGINX Plus nutzen können, um Ihre API-Management-Prozesse zu optimieren und die bestmögliche Leistung Ihrer Anwendungen sicherzustellen.

Einführung in das API-Gateway

Ein API-Gateway dient als zentrale Schnittstelle zur Verwaltung und Absicherung der Kommunikation zwischen Clients und Backend-Diensten. Es fungiert als Reverse-Proxy zwischen dem Client und den Backend-Servern, leitet eingehende Anfragen weiter und verteilt sie an die entsprechenden Dienste. Dies ermöglicht eine effizientere Kommunikation zwischen dem Client und den Diensten. Zudem kann das API-Gateway Aufgaben wie Authentifizierung, Autorisierung, Ratenbegrenzung und Caching übernehmen.

Darüber hinaus kann ein API-Gateway als Sicherheitsschicht fungieren und die Backend-Dienste vor potenziellen Bedrohungen und Angriffen schützen. Es kann Sicherheitsmaßnahmen wie Verschlüsselung, tokenbasierte Authentifizierung und Zugriffskontrolle durchsetzen und so gewährleisten, dass nur autorisierte Benutzer auf die Dienste zugreifen können. Indem diese Sicherheitsfunktionen an einer zentralen Stelle gebündelt und verwaltet werden, trägt das API-Gateway dazu bei, die gesamte Sicherheitsarchitektur des Systems zu vereinfachen und den Aufwand für die Implementierung von Sicherheitsmaßnahmen über mehrere Dienste hinweg zu reduzieren.

Deklaratives API-Projekt von NGINX

Das von der Community unterstützte Projekt NGINX Declarative API stellt eine Reihe deklarativer REST-APIs für NGINX Instance Manager bereit.

Damit lassen sich die Lebenszyklen von NGINX Plus-Konfigurationen verwalten und NGINX Plus-Konfigurationen anhand von JSON-Dienstdefinitionen erstellen. Bei Verwendung mit NGINX Instance Manager wird die GitOps-Integration unterstützt: Die maßgebliche Datenquelle wird auf Aktualisierungen referenzierter Objekte geprüft, und die NGINX-Konfigurationen werden automatisch synchron gehalten.

OpenAPI-Schemas können verwendet werden, um NGINX automatisch als API-Gateway zu konfigurieren. Die Erstellung eines Entwicklerportals wird durch Redocly unterstützt.

Voraussetzungen

Um die Inhalte dieses Blogs auszuführen, benötigen Sie:

  • Eine laufende Instanz von NGINX Instance Manager
  • Ein Abonnement (oder eine kostenlose 30-Tage-Testversion) für NGINX Plus und NGINX App Protect WAF. NGINX Agent muss installiert sein, um eine Verbindung zu NGINX Instance Manager herzustellen und Teil der Instanzgruppe declarativeAPITest zu sein.
  • Ein Linux-Host (Bare Metal oder VM) mit Docker und Docker Compose zum Ausführen des NGINX Declarative API-Projekts
  • Postman zum Senden der deklarativen API-Anfragen
  • Ein Client-Host, auf dem Postman ausgeführt wird

Laborübersicht

Nach der Installation und Ausführung aller Voraussetzungen zeigt NGINX Instance Manager die NGINX Plus-Instanz mit NGINX App Protect WAF als online an.

Übersicht über NGINX Instance Manager

Die NGINX Plus-Instanz ist Teil der Instanzgruppe declarativeAPITest Instance Group

Instanzgruppen von NGINX Instance Manager

Bereitstellen der deklarativen API

Das NGINX Declarative API-Projekt basiert auf der von NGINX Instance Manager bereitgestellten REST-API und bietet eine deklarative, JSON-basierte Abstraktion. Befolgen Sie diese Anweisungen, um das Declarative API-Projekt auszuführen:

1. Führen Sie docker ps aus, um zu überprüfen, ob Docker ausgeführt wird:


f5@ubuntu:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

2. Klonen Sie auf dem Linux-Host das GitHub-Repository:


f5@ubuntu:~$ git clone https://github.com/f5devcentral/NGINX-Declarative-API/
Cloning into 'NGINX-Declarative-API'...
remote: Enumerating objects: 4072, done.
remote: Counting objects: 100% (1982/1982), done.
remote: Compressing objects: 100% (1332/1332), done.
remote: Total 4072 (delta 668), reused 876 (delta 609), pack-reused 2090
Receiving objects: 100% (4072/4072), 19.05 MiB | 4.88 MiB/s, done.
Resolving deltas: 100% (1154/1154), done.
f5@ubuntu:~$

3. Wechseln Sie in das docker-compose-Verzeichnis:


f5@ubuntu:~$ cd NGINX-Declarative-API/contrib/docker-compose/

4. Verwenden Sie das Skript „nginx-dapi.sh“, um alle Container über docker-compose zu starten. Beim ersten Start werden alle Docker-Images automatisch erstellt:


f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ ./nginx-dapi.sh -c start
-> Updating docker images
[+] Pulling 11/11
[...]
-> Deploying NGINX Declarative API
[+] Running 4/4
 ✔ Network nginx-dapi_dapi-network  Created 0.1s 
 ✔ Container redis                  Started 1.5s 
 ✔ Container devportal              Started 1.5s 
 ✔ Container nginx-dapi             Started

5. Laufende Docker-Container überprüfen:


f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED         STATUS         PORTS                                       NAMES
e29a2f783da2   nginx-declarative-api             "/deployment/env/bin…"   5 minutes ago   Up 5 minutes   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   nginx-dapi
97142840eaf7   redis                             "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp   redis
6b50c0426643   nginx-declarative-api-devportal   "/deployment/src/sta…"   5 minutes ago   Up 5 minutes   0.0.0.0:5001->5000/tcp, :::5001->5000/tcp   devportal

6. Führen Sie auf dem Clienthost Postman aus und importieren Sie die NGINX Declarative API-Sammlung unter https://raw.githubusercontent.com/f5devcentral/NGINX-Declarative-API/main/contrib/postman/NGINX%20Declarative%20API.postman_collection.json

7. Bearbeiten Sie die Variablen der Postman-Collection, um sie an Ihre Umgebung anzupassen:

Deklarative NGINX-API

8. Legen Sie die folgenden Variablen fest:

  • ncg_host – Hostname oder IP-Adresse des Linux-Hosts, auf dem Docker Compose für die Declarative API ausgeführt wird
  • ncg_port – TCP-Port für die deklarative NGINX-API: Der Standardwert ist 5000
  • nim_host – Basis-URL von NGINX Instance Manager (z. B. https://nms.k8s.ie.ff.lan)
  • nim_username – Benutzername für die Authentifizierung bei NGINX Instance Manager
  • nim_password – Passwort für die Authentifizierung bei NGINX Instance Manager
Variablen der deklarativen NGINX-API

9. Speichern Sie alle Änderungen in Postman

10. Navigieren Sie in der Postman-Sammlung zu „Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF“ und öffnen Sie die Anfrage.

Deklarative NGINX-API-Sammlungen

Die JSON-Deklaration sieht wie folgt aus:


{
    "output": {
        "type": "nms",
        "nms": {
            "url": "{{nim_host}}",
            "username": "{{nim_username}}",
            "password": "{{nim_password}}",
            "instancegroup": "{{nim_instancegroup}}",
            "synctime": 0,
            "modules": [
                "ngx_http_app_protect_module"
            ],
            "certificates": [
                {
                    "type": "certificate",
                    "name": "test_cert",
                    "contents": {
                        "content": "{{github_gitops_root}}/v4.2/testcert.crt"
                    }
                },
                {
                    "type": "key",
                    "name": "test_key",
                    "contents": {
                        "content": "{{github_gitops_root}}/v4.2/testcert.key"
                    }
                }
            ],
            "policies": [
                {
                    "type": "app_protect",
                    "name": "production-policy",
                    "active_tag": "xss-blocked",
                    "versions": [
                        {
                            "tag": "xss-blocked",
                            "displayName": "Production Policy - XSS blocked",
                            "description": "This is a production-ready policy - XSS blocked",
                            "contents": {
                                "content": "{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json"
                            }
                        },
                        {
                            "tag": "xss-allowed",
                            "displayName": "Production Policy - XSS allowed",
                            "description": "This is a production-ready policy - XSS allowed",
                            "contents": {
                                "content": "{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json"
                            }
                        }
                    ]
                }
            ]
        }
    },
    "declaration": {
        "http": {
            "servers": [
                {
                    "name": "Petstore API",
                    "names": [
                        "apigw.nginx.lab"
                    ],
                    "resolver": "8.8.8.8",
                    "listen": {
                        "address": "0.0.0.0:443",
                        "http2": true,
                        "tls": {
                            "certificate": "test_cert",
                            "key": "test_key",
                            "ciphers": "DEFAULT",
                            "protocols": [
                                "TLSv1.2",
                                "TLSv1.3"
                            ]
                        }
                    },
                    "log": {
                        "access": "/var/log/nginx/apigw.nginx.lab-access_log",
                        "error": "/var/log/nginx/apigw.nginx.lab-error_log"
                    },
                    "locations": [
                        {
                            "uri": "/petstore",
                            "urimatch": "prefix",
                            "apigateway": {
                                "openapi_schema": {
                                    "content": "http://petstore.swagger.io/v2/swagger.json"
                                },
                                "api_gateway": {
                                    "enabled": true,
                                    "strip_uri": true,
                                    "server_url": "https://petstore.swagger.io/v2"
                                },
                                "developer_portal": {
                                    "enabled": true,
                                    "uri": "/petstore-devportal.html"
                                },
                                "authentication": {
                                    "client": [
                                        {
                                            "profile": "Petstore JWT Authentication"
                                        }
                                    ],
                                    "enforceOnPaths": true,
                                    "paths": [
                                        "/user/login",
                                        "/user/logout"
                                    ]
                                },
                                "authorization": [
                                    {
                                        "profile": "JWT role based authorization",
                                        "enforceOnPaths": true,
                                        "paths": [
                                            "/user/login",
                                            "/user/logout"
                                        ]
                                    }
                                ],
                                "rate_limit": [
                                    {
                                        "profile": "petstore_ratelimit",
                                        "httpcode": 429,
                                        "burst": 0,
                                        "delay": 0,
                                        "enforceOnPaths": true,
                                        "paths": [
                                            "/user/login",
                                            "/user/logout"
                                        ]
                                    }
                                ]
                            },
                            "log": {
                                "access": "/var/log/nginx/petstore-access_log",
                                "error": "/var/log/nginx/petstore-error_log"
                            },
                            "app_protect": {
                                "enabled": true,
                                "policy": "production-policy",
                                "log": {
                                    "profile_name": "secops_dashboard",
                                    "enabled": true,
                                    "destination": "127.0.0.1:514"
                                }
                            }
                        }
                    ]
                }
            ],
            "rate_limit": [
                {
                    "name": "petstore_ratelimit",
                    "key": "$binary_remote_addr",
                    "size": "10m",
                    "rate": "2r/s"
                }
            ],
            "authentication": {
                "client": [
                    {
                        "name": "Petstore JWT Authentication",
                        "type": "jwt",
                        "jwt": {
                            "realm": "Petstore Authentication",
                            "key": "{\"keys\": [{\"k\":\"ZmFudGFzdGljand0\",\"kty\":\"oct\",\"kid\":\"0001\"}]}",
                            "cachetime": 5
                        }
                    }
                ]
            },
            "authorization": [
                {
                    "name": "JWT role based authorization",
                    "type": "jwt",
                    "jwt": {
                        "claims": [
                            {
                                "name": "roles",
                                "value": [
                                    "~(devops)"
                                ],
                                "errorcode": 403
                            }
                        ]
                    }
                }
            ]
        }
    }
}

Der Abschnitt „output“ definiert:

  • Der NGINX Instance Manager-Server, auf dem die deklarative API die NGINX-Konfiguration veröffentlicht
  • TLS-Zertifikate und -Schlüssel – auf diese kann über die URL der maßgeblichen Quelle verwiesen werden, in der sie gespeichert sind
  • NGINX App Protect WAF-Sicherheitsrichtlinien – auf diese kann über die URL der maßgeblichen Quelle verwiesen werden, in der sie gespeichert sind

Der Abschnitt „declaration“ beschreibt:

  • Der zu erstellende NGINX-Server
  • Ob TLS-Offloading durchgeführt wird
  • Wo Zugriffs- und Fehlereinträge protokolliert werden sollen
  • Der /petstore-Basis-URI, unter der die API-Gateway-Konfiguration bereitgestellt und für Clients zugänglich gemacht wird
  • Die zu veröffentlichende API-Gateway-Konfiguration und das Entwicklerportal
  • Wie NGINX App Protect WAF aktiviert wird, welche Sicherheitsrichtlinie verwendet werden soll und wo Sicherheitsverstöße protokolliert werden sollen
  • So authentifizieren und autorisieren Sie Clientanfragen

Im Abschnitt zur API-Gateway-Deklaration wird beschrieben, wie die deklarative API ihr Ergebnis bereitstellt.

Auf das OpenAPI-Schema wird über seine vollständige URL verwiesen:


"apigateway": {
    "openapi_schema": {
        "content": "http://petstore.swagger.io/v2/swagger.json"
    },

Die Erstellung der NGINX-API-Gateway-Konfiguration wird angefordert und der Upstream-Server wird definiert. Wenn NGINX Anfragen per Reverse-Proxy an den Upstream weiterleitet, wird der Basis-URI /petstore entfernt:


"api_gateway": {
        "enabled": true,
        "strip_uri": true,
        "server_url": "https://petstore.swagger.io/v2"
    },

Die Erstellung und Bereitstellung eines Entwicklerportals unter einem bestimmten URI wird angefordert:


"developer_portal": {
        "enabled": true,
        "uri": "/petstore-devportal.html"
    },

Die Clientauthentifizierung auf Grundlage des angegebenen Clientauthentifizierungsprofils wird für /user/login und /user/logout erzwungen:


"authentication": {
        "client": [
            {
                "profile": "Petstore JWT Authentication"
            }
        ],
        "enforceOnPaths": true,
        "paths": [
            "/user/login",
            "/user/logout"
        ]
    },

Die Clientautorisierung auf Grundlage des angegebenen Clientautorisierungsprofils wird für „/user/login“ und „/user/logout“ erzwungen:


"authorization": [
        {
            "profile": "JWT role based authorization",
            "enforceOnPaths": true,
            "paths": [
                "/user/login",
                "/user/logout"
            ]
        }
    ],

Die Ratenbegrenzung wird für /user/login und /user/logout basierend auf dem angegebenen Profil angewendet:


"rate_limit": [
        {
            "profile": "petstore_ratelimit",
            "httpcode": 429,
            "burst": 0,
            "delay": 0,
            "enforceOnPaths": true,
            "paths": [
                "/user/login",
                "/user/logout"
            ]
        }
    ]
},

12. Verwenden Sie in Postman die Schaltfläche „Send“, um die Anfrage an die deklarative API zu senden. Die Antwort sieht in etwa wie folgt aus:


{
    "code": 200,
    "content": {
        "createTime": "2024-04-26T17:09:10.419574328Z",
        "details": {
            "failure": [],
            "pending": [],
            "success": [
                {
                    "name": "vm-test"
                }
            ]
        },
        "id": "1060ec49-120e-45ca-820b-5203c8b3538d",
        "message": "Instance Group config successfully published to declarativeAPITest",
        "status": "successful",
        "updateTime": "2024-04-26T17:09:10.881509913Z"
    },
    "configUid": "eecf1da6-9d8f-4e44-89cc-a470af79379d"
}

13. In diesem Stadium ist die NGINX-Instanz als API-Gateway konfiguriert, die WAF-Sicherheitsrichtlinien werden durchgesetzt und das Entwicklerportal ist veröffentlicht.

Testen des API-Gateways

Hinweis: Es wird davon ausgegangen, dass der FQDN apigw.nginx.lab in die IP-Adresse der virtuellen Maschine aufgelöst wird, auf der die NGINX-Instanz ausgeführt wird.

1. Wechseln Sie in das Verzeichnis „jwt“:


f5@ubuntu:~$ cd ~/NGINX-Declarative-API/contrib/gitops-examples/jwt

2. Greifen Sie auf einen nicht authentifizierten REST-API-Endpunkt zu:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/store/inventory
HTTP/2 200 
date: Fri, 26 Apr 2024 17:13:54 GMT
content-type: application/json
access-control-allow-origin: *
access-control-allow-methods: GET, POST, DELETE, PUT
access-control-allow-headers: Content-Type, api_key, Authorization

{"totvs":5,"aut":1,"FORsold":1,[...]

3. Ratenbegrenzung:


    $ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login;curl -w '\n' -ki 
    https://apigw.nginx.lab/petstore/user/login
    HTTP/2 401 
    date: Fri, 26 Apr 2024 17:14:51 GMT
    content-type: text/html
    content-length: 179
    www-authenticate: Bearer realm="Petstore Authentication"
    <html>
    <head><title>401 Authorization Required</title></head>
    <body>
    <center><h1>401 Authorization Required</h1></center>
    <hr><center>nginx/1.25.3</center>
    </body>
    </html>
    HTTP/2 429 
    date: Fri, 26 Apr 2024 17:14:51 GMT
    content-type: text/html
    content-length: 169
    <html>
    <head><title>429 Too Many Requests</title></head>
    <body>
    <center><h1>429 Too Many Requests</h1></center>
    <hr><center>nginx/1.25.3</center>
    </body>
    </html>
    

4. Authentifizierung und gültige Autorisierung:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Authorization: Bearer `cat jwt.devops`"
HTTP/2 200 
date: Fri, 26 Apr 2024 17:15:41 GMT
content-type: application/json
access-control-allow-origin: *
access-control-allow-methods: GET, POST, DELETE, PUT
access-control-allow-headers: Content-Type, api_key, Authorization
x-expires-after: Fri Apr 26 18:15:41 UTC 2024
x-rate-limit: 5000

{"code":200,"type":"unknown","message":"logged in user session:1714151741883"}

5. Authentifizierung und ungültige Autorisierung:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Authorization: Bearer `cat jwt.guest`"
HTTP/2 403 
date: Fri, 26 Apr 2024 17:16:07 GMT
content-type: text/html
content-length: 153
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>

6. NGINX App Protect WAF und Cross-Site-Scripting-Sicherheitsverstoß:


$ curl -w '\n' -ki "https://apigw.nginx.lab/petstore/store/inventory?
"
HTTP/2 200 
content-type: text/html; charset=utf-8
cache-control: no-cache
pragma: no-cache
content-length: 246

7. Das Entwicklerportal kann unter folgender Adresse aufgerufen werden:


https://apigw.nginx.lab/petstore/petstore-devportal.html

Erste Schritte

Wenn Sie die in diesem Beitrag vorgestellten NGINX-Lösungen ausprobieren möchten, starten Sie noch heute eine kostenlose 30-Tage-Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen:

Laden Sie NGINX Agent herunter – kostenlos und Open Source.

Teilen
Schlagwörter: F5 NGINX, 2024

Über den Autor

Ähnliche Blogbeiträge

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
NGINX | 23.08.2022

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln

Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
NGINX | 08.09.2021

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen

Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
NGINX | 16.08.2021

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet

Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
NGINX | 12.12.2018

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77

Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.

Ankündigung von NGINX Plus R16
NGINX | 05.09.2018

Ankündigung von NGINX Plus R16

NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
NGINX | 13.10.2016

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing

Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.