D’OpenAPI à NGINX comme passerelle d’API à l’aide d’une API déclarative

NGINX | 17 juin 2024

NGINX est depuis longtemps reconnu comme l’une des meilleures solutions pour faire fonctionner des serveurs web et des répartiteurs de charge hautes performances. Cependant, avec l’essor des architectures de microservices et la nécessité d’une gestion efficace des API, NGINX est également devenu un choix populaire pour créer des passerelles API.

Dans cet article, nous verrons comment transformer une définition de schéma OpenAPI en une configuration NGINX entièrement fonctionnelle, utilisée comme passerelle API avec la sécurité d’un « pare-feu d’applications web » et un « portail pour les développeurs », à l’aide d’une approche d’API déclarative.

Nous vous fournirons des instructions détaillées et des conseils pour tirer parti de NGINX Plus afin de simplifier vos processus de gestion des API et de garantir des performances optimales pour vos applications.

Présentation de la passerelle API

Une passerelle API sert de point central pour gérer et sécuriser les communications entre les clients et les services backend. Elle agit comme un proxy inverse placé entre le client et les serveurs backend, acheminant les requêtes entrantes et les distribuant aux services appropriés. Cela permet une communication plus efficace entre le client et les services, tout en permettant à la passerelle API de prendre en charge des tâches telles que l’authentification, l’autorisation, la limitation du débit et la mise en cache.

De plus, une passerelle API peut faire office de couche de sécurité, protégeant ainsi les services backend contre les menaces et attaques potentielles. Elle peut appliquer des mesures de sécurité telles que le chiffrement, l’authentification par jeton et le contrôle d’accès, afin de garantir que seuls les utilisateurs autorisés puissent accéder aux services. En centralisant et en gérant ces fonctionnalités de sécurité en un seul endroit, la passerelle API contribue à simplifier l’architecture de sécurité globale du système et à réduire la complexité liée à la mise en œuvre de mesures de sécurité dans plusieurs services.

Projet d’API déclarative NGINX

Le projet NGINX Declarative API, soutenu par la communauté, fournit un ensemble d’API REST déclaratives pour NGINX Instance Manager.

Il permet de gérer le cycle de vie des configurations NGINX Plus et de créer des configurations NGINX Plus à l’aide de définitions de services JSON. L’intégration GitOps est prise en charge lorsqu’il est utilisé avec NGINX Instance Manager : la source de vérité est vérifiée afin de détecter les mises à jour des objets référencés, et les configurations NGINX sont automatiquement maintenues synchronisées.

Les schémas OpenAPI peuvent être utilisés pour configurer automatiquement NGINX en tant que passerelle d’API. La création d’un portail pour les développeurs est prise en charge par Redocly.

Prérequis

Pour exécuter les exemples présentés dans cet article, vous aurez besoin des éléments suivants :

  • Une instance en cours d’exécution de NGINX Instance Manager
  • Un abonnement (ou un essai gratuit de 30 jours) à NGINX Plus et à NGINX App Protect WAF. NGINX Agent doit être installé pour se connecter à NGINX Instance Manager et faire partie du groupe d’instances declarativeAPITest instance group
  • Un hôte Linux (serveur physique ou machine virtuelle) avec docker et docker-compose pour exécuter le projet NGINX Declarative API
  • Postman pour envoyer les requêtes à l’API déclarative
  • Un hôte client pour exécuter Postman

Présentation du laboratoire

Après l’installation et l’exécution de tous les prérequis, NGINX Instance Manager indique que l’instance NGINX Plus est en ligne avec NGINX App Protect WAF.

Vue d’ensemble de NGINX Instance Manager

L’instance NGINX Plus fait partie du groupe d’instances « declarativeAPITest »

Groupes d’instances NGINX Instance Manager

Déploiement de l’API déclarative

Le projet NGINX Declarative API s’appuie sur l’API REST fournie par NGINX Instance Manager et offre une abstraction déclarative basée sur JSON. Suivez ces instructions pour exécuter le projet Declarative API :

1. Exécutez docker ps pour vérifier que Docker est en cours d’exécution :


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

2. Sur l’hôte Linux, clonez le dépôt Github :


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. Accédez au répertoire docker-compose :


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

4. Utilisez le script « nginx-dapi.sh » pour démarrer tous les conteneurs via docker-compose. Lors du premier démarrage, toutes les images Docker sont créées automatiquement :


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. Vérifiez les conteneurs Docker en cours d’exécution :


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. Sur l’hôte client, lancez Postman et importez la collection NGINX Declarative API disponible à l’adresse suivante : https://raw.githubusercontent.com/f5devcentral/NGINX-Declarative-API/main/contrib/postman/NGINX%20Declarative%20API.postman_collection.json

7. Modifiez les variables de la collection Postman pour les adapter à votre environnement :

API déclarative NGINX

8. Définissez les variables suivantes :

  • ncg_host - nom d’hôte ou adresse IP de l’hôte Linux sur lequel s’exécute le docker-compose de l’API déclarative
  • ncg_port - Port TCP de l’API déclarative NGINX : 5000 est la valeur par défaut
  • nim_host - URL de base de NGINX Instance Manager (par ex. https://nms.k8s.ie.ff.lan)
  • nim_username - nom d’utilisateur d’authentification de NGINX Instance Manager
  • nim_password - mot de passe d’authentification de NGINX Instance Manager
Variables de l’API déclarative NGINX

9. Enregistrez toutes les modifications dans Postman

10. Dans la collection Postman, accédez à « Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF », puis ouvrez la requête

Collections d’API déclaratives NGINX

La déclaration JSON se présente comme suit :


{
    "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
                            }
                        ]
                    }
                }
            ]
        }
    }
}

La section « output » définit :

  • Le serveur NGINX Instance Manager sur lequel l’API déclarative publiera la configuration NGINX
  • Certificats et clés TLS : ils peuvent être référencés par l’URL de la source de référence où ils sont stockés
  • Politiques de sécurité WAF NGINX App Protect : elles peuvent être référencées à l’aide de l’URL de la source de référence où elles sont stockées

La section declaration décrit :

  • Le serveur NGINX à créer
  • Indique si le déchargement TLS est effectué ou non
  • Où consigner les entrées d’accès et d’erreur
  • L’URI de base /petstore sur laquelle la configuration d’API Gateway sera déployée et rendue accessible aux clients
  • La configuration d’API Gateway et le portail des développeurs à publier
  • Comment NGINX App Protect WAF est activé, quelle politique de sécurité utiliser et où consigner les violations de sécurité
  • Comment authentifier et autoriser les requêtes des clients

La section de déclaration de la passerelle d’API décrit comment l’API déclarative fournira son résultat.

Le schéma OpenAPI est référencé par son URL complète :


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

La création de la configuration de la passerelle API NGINX est demandée et le serveur en amont est défini. Lorsque NGINX transmet les requêtes au serveur en amont en tant que proxy inverse, l’URI de base /petstore est supprimé :


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

La création et le déploiement d’un portail développeur sous un URI spécifique sont demandés :


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

L’authentification des clients basée sur le profil d’authentification client spécifié est appliquée pour « /user/login » et « /user/logout » :


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

L’autorisation des clients basée sur le profil d’autorisation client spécifié est appliquée pour « /user/login » et « /user/logout » :


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

La limitation du débit s’applique à /user/login et /user/logout selon le profil spécifié :


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

12. Utilisez le bouton Send de Postman pour envoyer la requête à l’API déclarative. La réponse ressemble à ceci :


{
    "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. À ce stade, l’instance NGINX est configurée en tant que passerelle API, la sécurité WAF est appliquée et le portail des développeurs est publié.

Tester la passerelle API

Remarque : on suppose que le nom de domaine complet (FQDN) apigw.nginx.lab se résout en l’adresse IP de la machine virtuelle sur laquelle l’instance NGINX s’exécute

1. Accédez au répertoire jwt :


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

2. Accédez à un point de terminaison d’API REST non authentifié :


$ 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. Limitation du débit :


    $ 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. Authentification et autorisation valide :


$ 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. Authentification et autorisation non valide :


$ 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 et violation de sécurité de type Cross-Site Scripting :


$ 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. Le portail des développeurs est accessible à l’adresse suivante :


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

Commencer

Pour essayer les solutions NGINX présentées dans cet article, commencez dès aujourd’hui un essai gratuit de 30 jours ou contactez-nous pour discuter de vos cas d’utilisation :

Téléchargez NGINX Agent : il est gratuit et open source.

Partager
Mots-clés : F5 NGINX, 2024

À propos de l’auteur

Fabrizio Fiorucci
Fabrizio FiorucciArchitecte de solutions NGINX | F5 (EMEA)

Autres articles de Fabrizio Fiorucci

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
NGINX | 13/10/2025

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA

Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
NGINX | 03/11/2023

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?

Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
NGINX | 11/03/2020

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX

Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
NGINX | 11/06/2019

Un testeur d’expressions régulières pour NGINX et NGINX Plus

Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.

Caches partagés avec les clusters de cache NGINX Plus, partie 1
NGINX | 24/01/2017

Caches partagés avec les clusters de cache NGINX Plus, partie 1

Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.

Introduction aux microservices
NGINX | 19/05/2015

Introduction aux microservices

Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.