NGINX ha sido reconocido desde hace mucho tiempo como una de las mejores opciones para potenciar servidores web y balanceadores de carga de alto rendimiento. Sin embargo, con el auge de las arquitecturas de microservicios y la necesidad de una gestión eficiente de API, NGINX también se ha convertido en una opción popular para crear puertas de enlace de API.
En este blog, exploraremos cómo transformar una definición de esquema OpenAPI en una configuración NGINX completamente funcional que se ejecuta como una API Gateway con seguridad de firewall de aplicação web y un portal para desarrolladores utilizando un enfoque de API declarativa.
Proporcionaremos instrucciones paso a paso y conocimientos sobre cómo aprovechar NGINX Plus para optimizar sus procesos de gestión de API y garantizar un rendimiento óptimo para sus aplicações.
Una puerta de enlace API funciona como un centro central para administrar y proteger la comunicación entre clientes y servicios backend. Actúa como un proxy inverso que se ubica entre el cliente y los servidores back-end, enrutando las solicitudes entrantes y distribuyéndolas a los servicios apropiados. Esto permite una comunicación más eficiente entre el cliente y los servicios, además de permitir que la puerta de enlace API gestione tareas como autenticación , autorización , limitación de velocidad y almacenamiento en caché.
Además, una puerta de enlace API puede actuar como una capa de seguridad , protegiendo los servicios backend de posibles amenazas y ataques. Puede aplicar medidas de seguridad como cifrado, autenticación basada en tokens y control de acceso, garantizando que solo los usuarios autorizados puedan acceder a los servicios. Al consolidar y administrar estas funciones de seguridad en un solo lugar, la puerta de enlace API ayuda a simplificar la arquitectura de seguridad general del sistema y a reducir la complejidad de implementar medidas de seguridad en múltiples servicios.
El proyecto NGINX Declarative API, respaldado por la comunidad, proporciona un conjunto de API REST declarativas para NGINX Instance Manager .
Se puede utilizar para administrar los ciclos de vida de configuración de NGINX Plus y para crear configuraciones de NGINX Plus utilizando definiciones de servicio JSON. La integración de GitOps es compatible cuando se utiliza con NGINX Instance Manager: se verifica la fuente de verdad para las actualizaciones de los objetos referenciados y las configuraciones de NGINX se mantienen sincronizadas automáticamente.
Los esquemas OpenAPI se pueden utilizar para configurar automáticamente NGINX como una API Gateway. La creación de un portal para desarrolladores se realiza a través de Redocly .
Para ejecutar los contenidos de este blog, necesitas:
pruebaAPI declarativa
grupo de instanciasDespués de instalar y ejecutar todos los requisitos previos, NGINX Instance Manager muestra la instancia NGINX Plus como en línea con NGINX App Protect WAF.
La instancia NGINX Plus es parte del grupo de instancias declarativeAPITest
El proyecto de API declarativa de NGINX se basa en la API REST proporcionada por NGINX Instance Manager y proporciona la abstracción declarativa basada en JSON. Siga estas instrucciones para ejecutar el proyecto de API declarativa:
1.Ejecute docker ps para verificar que Docker se esté ejecutando:
f5@ubuntu:~$ docker ps
ID DEL CONTENEDOR IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
2.En el host Linux, clona el repositorio de Github:
f5@ubuntu:~$ git clone https://github.com/f5devcentral/NGINX-Declarative-API/
Clonando en 'NGINX-Declarative-API'...
remoto: Enumeración de objetos: 4072, listo.
remoto: Contando objetos: 100% (1982/1982), hecho.
remoto: Comprimiendo objetos: 100% (1332/1332), listo.
remoto: Total 4072 (delta 668), reutilizados 876 (delta 609), reutilizados en paquete 2090
Objetos recibidos: 100% (4072/4072), 19,05 MiB | 4,88 MiB/s, listo.
Resolviendo deltas: 100% (1154/1154), hecho.
f5@ubuntu:~$
3.Cambiar al directorio docker-compose:
f5@ubuntu:~$ cd API declarativa de NGINX/contrib/docker-compose/
4.Utilice el script nginx-dapi.sh
para iniciar todos los contenedores a través de docker-compose. Durante el inicio inicial, todas las imágenes de Docker se crean automáticamente:
f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ ./nginx-dapi.sh -c start
-> Actualizando imágenes de Docker
[+] Recuperando 11/11
[...]
-> Implementando API Declarativa de NGINX
[+] Recuperando 4/4
✔ Red nginx-dapi_dapi-network (Creada 0.1s)
✔ Contenedor redis (Iniciado 1.5s)
✔ Contenedor devportal (Iniciado 1.5s)
✔ Contenedor nginx-dapi (Iniciado)
5.Comprueba los contenedores Docker en ejecución:
f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ docker ps
ID DE CONTENEDOR IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
e29a2f783da2 nginx-declarative-api "/deployment/env/bin…" Hace 5 minutos 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp nginx-dapi
97142840eaf7 redis "docker-entrypoint.s…" Hace 5 minutos 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
6b50c0426643 nginx-declarative-api-devportal "/deployment/src/sta…" hace 5 minutos. Activo hace 5 minutos. 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp devportal.
6.En el host del cliente, ejecute Postman e importe la colección de API declarativa de NGINX en https://raw.githubusercontent.com/f5devcentral/NGINX-Declarative-API/main/contrib/postman/NGINX%20Declarative%20API.postman_collection.json
7.Edite las variables de colección de Postman para ajustarlas a su entorno:
8.Establezca las siguientes variables:
ncg_host
: nombre de host o dirección IP del host Linux donde se ejecuta la API declarativa docker-composencg_port
- Puerto TCP para la API declarativa NGINX: 5000 es el valor predeterminadonim_host
: URL base del administrador de instancias de NGINX (por ejemplo, https://nms.k8s.ie.ff.lan)nim_username
- Nombre de usuario de autenticación del administrador de instancias de NGINXnim_password
- Contraseña de autenticación del administrador de instancias de NGINX9.Guardar todos los cambios en Postman
10.En la colección Postman, busque Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF
y abra la solicitud
La declaración JSON se ve así:
{
"salida": {
"tipo": "nms",
"nms": {
"url": "{{nim_host}}",
"nombre de usuario": "{{nim_nombre de usuario}}",
"contraseña": "{{nim_contraseña}}",
"grupo de instancias": "{{nim_grupo de instancias}}",
"tiempo de sincronización": 0,
"módulos": [
"ngx_http_app_protect_module"
],
"certificados": [
{
"tipo": "certificado",
"nombre": "certificado_de_prueba",
"contenido": {
"contenido": "{{github_gitops_root}}/v4.2/testcert.crt"
}
},
{
"tipo": "clave",
"nombre": "clave_de_prueba",
"contenido": {
"contenido": "{{github_gitops_root}}/v4.2/testcert.key"
}
}
],
"políticas": [
{
"tipo": "app_protect",
"nombre": "política_de_producción",
"etiqueta_activa": "xss-blocked",
"versiones": [
{
"etiqueta": "xss-blocked",
"nombre_para_mostrar": "Política de producción - XSS bloqueado",
"descripción": "Esta es una política lista para producción - XSS bloqueado",
"contents": {
"content": "{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json"
}
},
{
"tag": "xss-allowed",
"displayName": "Política de producción - XSS permitido",
"descripción": "Esta es una política lista para producción - XSS permitido",
"contents": {
"content": "{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json"
}
}
]
}
]
}
},
"declaration": {
"http": {
"servers": [
{
"name": "API de la tienda de mascotas",
"nombres": [
"apigw.nginx.lab"
],
"resolver": "8.8.8.8",
"escuchar": {
"dirección": "0.0.0.0:443",
"http2": verdadero,
"tls": {
"certificado": "certificado_de_prueba",
"clave": "clave_de_prueba",
"cifrados": "PREDETERMINADO",
"protocolos": [
"TLSv1.2",
"TLSv1.3"
]
}
},
"registro": {
"acceso": "/var/log/nginx/apigw.nginx.lab-access_log",
"error": "/var/log/nginx/apigw.nginx.lab-error_log"
},
"ubicaciones": [
{
"uri": "/petstore",
"urimatch": "prefijo",
"apigateway": {
"openapi_schema": {
"contenido": "http://petstore.swagger.io/v2/swagger.json"
},
"api_gateway": {
"habilitado": verdadero,
"strip_uri": verdadero,
"server_url": "https://petstore.swagger.io/v2"
},
"portal_desarrollador": {
"habilitado": verdadero,
"uri": "/petstore-devportal.html"
},
"autenticación": {
"cliente": [
{
"perfil": "Autenticación JWT de la tienda de mascotas"
}
],
"enforceOnPaths": true,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
},
"authorization": [
{
"profile": "Autorización basada en roles JWT",
"enforceOnPaths": verdadero,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
}
],
"rate_limit": [
{
"profile": "petstore_ratelimit",
"httpcode": 429,
"estallido": 0,
"retraso": 0,
"enforceOnPaths": verdadero,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
}
]
},
"log": {
"access": "/var/log/nginx/petstore-access_log",
"error": "/var/log/nginx/petstore-error_log"
},
"app_protect": {
"enabled": verdadero,
"policy": "política de producción",
"log": {
"profile_name": "secops_dashboard",
"enabled": verdadero,
"destination": "127.0.0.1:514"
}
}
}
]
}
],
"límite_de_velocidad": [
{
"nombre": "límite_de_velocidad_de_almacén_de_mascotas",
"clave": "$dirección_remota_binaria",
"tamaño": "10 m",
"velocidad": "2r/s"
}
],
"autenticación": {
"cliente": [
{
"nombre": "Autenticación JWT de la tienda de mascotas",
"tipo": "jwt",
"jwt": {
"reino": "Autenticación de la tienda de mascotas",
"clave": "{\"claves\": [{\"k\":\"ZmFudGFzdGljand0\",\"kty\":\"oct\",\"niño\":\"0001\"}]}",
"tiempo de caché": 5
}
}
]
},
"autorización": [
{
"nombre": "Autorización basada en roles JWT",
"tipo": "jwt",
"jwt": {
"reclamos": [
{
"nombre": "roles",
"valor": [
"~(devops)"
],
"código de error": 403
}
]
}
}
]
}
}
}
La sección de salida
define:
La sección de declaración
describe:
/petstore
donde se implementará la configuración de API Gateway y será accesible para los clientesLa sección de declaración de API Gateway describe cómo la API declarativa entregará su resultado.
El esquema OpenAPI se referencia a través de su URL completa:
"apigateway": {
"openapi_schema": {
"content": "http://petstore.swagger.io/v2/swagger.json"
},
Se solicita la creación de la configuración de NGINX API Gateway y se define el servidor ascendente. Cuando NGINX realiza un proxy inverso de las solicitudes al origen, se elimina el URI base /petstore
:
"api_gateway": {
"enabled": verdadero,
"strip_uri": verdadero,
"server_url": "https://petstore.swagger.io/v2"
},
Se solicita la creación e implementación del portal para desarrolladores bajo una URI específica:
"developer_portal": {
"enabled": true,
"uri": "/petstore-devportal.html"
},
La autenticación de clientes basada en el perfil de autenticación de cliente especificado se aplica para /user/login
y /user/logout
:
"autenticación": {
"cliente": [
{
"perfil": "Autenticación JWT de la tienda de mascotas"
}
],
"enforceOnPaths": true,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
},
La autorización de clientes basada en el perfil de autorización de cliente especificado se aplica para /user/login
y /user/logout
:
"Autorización": [
{
"Perfil": "Autorización basada en roles JWT",
"enforceOnPaths": verdadero,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
}
],
Se aplica una limitación de velocidad para /user/login
y /user/logout
según el perfil especificado:
"límite_de_tasa": [
{
"perfil": "límite_de_tasa_de_tienda_de_mascotas",
"código_http": 429,
"estallido": 0,
"retraso": 0,
"enforceOnPaths": verdadero,
"paths": [
"/usuario/inicio de sesión",
"/usuario/cierre de sesión"
]
}
]
},
12.Utilice el botón Enviar de
Postman para publicar la solicitud en la API declarativa. La respuesta es similar a esta:
{
"código": 200,
"contenido": {
"crearHora": "2024-04-26T17:09:10.419574328Z",
"detalles": {
"error": [],
"pendiente": [],
"éxito": [
{
"nombre": "vm-test"
}
]
},
"id": "1060ec49-120e-45ca-820b-5203c8b3538d",
"mensaje": "Configuración del grupo de instancias publicada correctamente en declarativeAPITest",
"status": "successful",
"updateTime": "2024-04-26T17:09:10.881509913Z"
},
"configUid": "eecf1da6-9d8f-4e44-89cc-a470af79379d"
}
13.En esta etapa, la instancia NGINX se configura como API Gateway, se aplica la seguridad WAF y se publica el portal para desarrolladores.
Nota: se supone que el FQDN apigw.nginx.lab
se resuelve en la dirección IP de la máquina virtual donde se ejecuta la instancia NGINX
1.Cambiar al directorio jwt
:
f5@ubuntu:~$ cd ~/NGINX-Declarative-API/contrib/gitops-examples/jwt
2.Acceder a un punto final de API REST no autenticado:
$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/store/inventory
HTTP/2 200
fecha: Vie, 26 Abr 2024 17:13:54 GMT
tipo de contenido: aplicação/json
control-de-acceso-permitir-origen: *
métodos de control de acceso permitidos: OBTENER, PUBLICAR, ELIMINAR, PONER
encabezados de control de acceso permitidos: Tipo de contenido, clave API, Autorización
{"totvs":5,"aut":1,"FORsold":1,[...]
3.Limitación de velocidad:
$ 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
fecha: Vie, 26 Abr 2024 17:14:51 GMT
Tipo de contenido: texto/html
Longitud del contenido: 179
www-autenticación: Portador realm="Autenticación de tienda de mascotas"
<html>
<head><title>401 Autorización requerida</title></head>
<body>
<center><h1>401 Autorización requerida</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
HTTP/2 429
fecha: Vie, 26 Abr 2024 17:14:51 GMT
Tipo de contenido: texto/html
Longitud del contenido: 169
<html>
<head><title>429 Demasiadas solicitudes</title></head>
<body>
<center><h1>429 Demasiadas solicitudes</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
4.Autenticación y autorización válida:
$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Autorización: Portador `cat jwt.devops`"
HTTP/2 200
fecha: Vie, 26 Abr 2024 17:15:41 GMT
tipo de contenido: aplicação/json
control-de-acceso-permitir-origen: *
métodos de control de acceso permitidos: OBTENER, PUBLICAR, ELIMINAR, PONER
encabezados de control de acceso permitidos: Tipo de contenido, clave API, autorización
x-caduca-después: Vie 26 Abr 18:15:41 UTC 2024
x-rate-limit: 5000
{"código":200,"tipo":"desconocido","mensaje":"sesión de usuario iniciada: 1714151741883"}
5.Autenticación y autorización no válida:
$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Autorización: Portador `cat jwt.guest`"
HTTP/2 403
fecha: Vie, 26 Abr 2024 17:16:07 GMT
Tipo de contenido: texto/html
Longitud del contenido: 153
<html>
<head><title>403 Prohibido</title></head>
<body>
<center><h1>403 Prohibido</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
6.Violación de seguridad de NGINX App Protect WAF y Cross-Site Scripting:
$ curl -w '\n' -ki "https://apigw.nginx.lab/petstore/store/inventory?
"
HTTP/2 200 tipo de contenido: texto/html; conjunto de caracteres=utf-8 control de caché: sin caché pragma: sin caché longitud del contenido: 246
<html><head><title>Solicitud rechazada</title></head><body>La URL solicitada fue rechazada. Consulte con su administrador.Su ID de soporte es: 7283327928460093545[Volver]
7.Se puede acceder al portal para desarrolladores navegando hasta
https://apigw.nginx.lab/petstore/petstore-devportal.html
Para probar las soluciones NGINX analizadas en esta publicación, comience hoy mismo una prueba gratuita de 30 días o contáctenos para analizar sus casos de uso:
Descargue NGINX Agent : es gratis y de código abierto.
"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.