O NGINX é reconhecido há muito tempo como uma das principais opções para alimentar servidores web e balanceadores de carga de alto desempenho. No entanto, com o surgimento de arquiteturas de microsserviços e a necessidade de gerenciamento eficiente de API, o NGINX também se tornou uma escolha popular para criar gateways de API.
Neste blog, exploraremos como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, executada como um API Gateway com segurança de Web Application Firewall e um Portal do Desenvolvedor usando uma abordagem de API declarativa.
Forneceremos instruções passo a passo e insights sobre como aproveitar o NGINX Plus para otimizar seus processos de gerenciamento de API e garantir o desempenho ideal para seus aplicativos.
Um gateway de API serve como um hub central para gerenciar e proteger a comunicação entre clientes e serviços de backend. Ele atua como um proxy reverso que fica entre o cliente e os servidores de backend, roteando solicitações recebidas e distribuindo-as para os serviços apropriados. Isso permite uma comunicação mais eficiente entre o cliente e os serviços, além de permitir que o gateway de API lide com tarefas como autenticação , autorização , limitação de taxa e armazenamento em cache.
Além disso, um gateway de API pode atuar como uma camada de segurança , protegendo os serviços de backend contra potenciais ameaças e ataques. Ele pode aplicar medidas de segurança como criptografia, autenticação baseada em tokens e controle de acesso, garantindo que somente usuários autorizados possam acessar os serviços. Ao consolidar e gerenciar esses recursos de segurança em um único lugar, o gateway de API ajuda a simplificar a arquitetura geral de segurança do sistema e a reduzir a complexidade da implementação de medidas de segurança em vários serviços.
O projeto NGINX Declarative API com suporte da comunidade fornece um conjunto de API REST declarativa para o NGINX Instance Manager .
Ele pode ser usado para gerenciar ciclos de vida de configuração do NGINX Plus e para criar configurações do NGINX Plus usando definições de serviço JSON. A integração do GitOps é suportada quando usada com o NGINX Instance Manager: a fonte da verdade é verificada para atualizações de objetos referenciados e as configurações do NGINX são mantidas automaticamente sincronizadas.
Os esquemas OpenAPI podem ser usados para configurar automaticamente o NGINX como um API Gateway. A criação do portal do desenvolvedor é suportada pelo Redocly .
Para executar o conteúdo deste blog, você precisa:
declarativeAPITest
Após instalar e executar todos os pré-requisitos, o NGINX Instance Manager mostra a instância do NGINX Plus como online com o NGINX App Protect WAF.
A instância NGINX Plus faz parte do grupo de instâncias declarativeAPITest
O projeto da API declarativa do NGINX depende da API REST fornecida pelo NGINX Instance Manager e fornece a abstração declarativa baseada em JSON. Siga estas instruções para executar o Projeto de API Declarativa:
1. Execute docker ps para verificar se o Docker está em execução:
f5@ubuntu:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2. No host Linux, clone o repositório 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. Mude para o diretório docker-compose:
f5@ubuntu:~$ cd NGINX-Declarative-API/contrib/docker-compose/
4. Use o script nginx-dapi.sh
para iniciar todos os contêineres por meio do docker-compose. Durante a inicialização, todas as imagens do Docker são criadas automaticamente:
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. Verifique os contêineres docker em execução:
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. No host do cliente, execute o Postman e importe a coleção da API declarativa do NGINX em https://raw.githubusercontent.com/f5devcentral/NGINX-Declarative-API/main/contrib/postman/NGINX%20Declarative%20API.postman_collection.json
7. Edite as variáveis da coleção Postman para ajustá-las ao seu ambiente:
8. Defina as seguintes variáveis:
ncg_host
- nome do host ou endereço IP do host Linux onde a API declarativa docker-compose está sendo executadancg_port
- Porta TCP para a API declarativa NGINX: 5000 é o padrãonim_host
- URL base do gerenciador de instâncias do NGINX (por exemplo, https://nms.k8s.ie.ff.lan)nim_username
- nome de usuário de autenticação do NGINX Instance Managernim_password
- senha de autenticação do NGINX Instance Manager9. Salvar todas as alterações no Postman
10. Na coleção Postman, navegue até Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF
e abra a solicitação
A declaração JSON tem a seguinte aparência:
{
"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
}
]
}
}
]
}
}
}
A seção de saída
define:
A seção de declaração
descreve:
/petstore
onde a configuração do API Gateway será implantada e disponibilizada aos clientesA seção de declaração do API Gateway descreve como a API declarativa entregará seu resultado.
O esquema OpenAPI é referenciado por meio de sua URL completa:
"apigateway": {
"openapi_schema": {
"content": "http://petstore.swagger.io/v2/swagger.json"
},
A criação da configuração do NGINX API Gateway é solicitada e o servidor upstream é definido. Quando o NGINX faz solicitações de proxy reverso para o upstream, o URI base /petstore
é removido:
"api_gateway": {
"enabled": true,
"strip_uri": true,
"server_url": "https://petstore.swagger.io/v2"
},
A criação e implantação do portal do desenvolvedor sob um URI específico é solicitada:
"developer_portal": {
"enabled": true,
"uri": "/petstore-devportal.html"
},
A autenticação de clientes com base no perfil de autenticação de cliente especificado é aplicada para /user/login
e /user/logout
:
"authentication": {
"client": [
{
"profile": "Petstore JWT Authentication"
}
],
"enforceOnPaths": true,
"paths": [
"/user/login",
"/user/logout"
]
},
A autorização de clientes com base no perfil de autorização de cliente especificado é aplicada para /user/login
e /user/logout
:
"authorization": [
{
"profile": "JWT role based authorization",
"enforceOnPaths": true,
"paths": [
"/user/login",
"/user/logout"
]
}
],
A limitação de taxa é aplicada para /user/login
e /user/logout
com base no perfil especificado:
"rate_limit": [
{
"profile": "petstore_ratelimit",
"httpcode": 429,
"burst": 0,
"delay": 0,
"enforceOnPaths": true,
"paths": [
"/user/login",
"/user/logout"
]
}
]
},
12. Use o botão Postman Send
para publicar a solicitação na API declarativa. A resposta é semelhante a:
{
"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. Nesta fase, a instância do NGINX é configurada como um API Gateway, a segurança do WAF é aplicada e o portal do desenvolvedor é publicado.
Observação: presume-se que o FQDN apigw.nginx.lab
seja resolvido para o endereço IP da máquina virtual onde a instância NGINX está sendo executada
1. Mude para o diretório jwt
:
f5@ubuntu:~$ cd ~/NGINX-Declarative-API/contrib/gitops-examples/jwt
2. Acesse um ponto de extremidade da API REST não autenticado:
$ 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. Limitação de taxa:
$ 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. Autenticação e autorização válida:
$ 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. Autenticação e autorização inválida:
$ 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. Violação de segurança do NGINX App Protect WAF e 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
<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.<br><br>Your support ID is: 7283327928460093545<br><br><a href='javascript:history.back();'>[Go Back]</a></body></html>
7. O portal do desenvolvedor pode ser acessado navegando até
https://apigw.nginx.lab/petstore/petstore-devportal.html
Para experimentar as soluções NGINX discutidas nesta postagem, inicie um teste gratuito de 30 dias hoje mesmo ou entre em contato conosco para discutir seus casos de uso:
Baixe o NGINX Agent – é gratuito e de código aberto.
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."