BLOG | NGINX

Do OpenAPI ao NGINX como um API Gateway usando uma API declarativa

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Fabrizio Fiorucci Miniatura
Fabrizio Fiorucci
Publicado em 17 de junho de 2024

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.

Apresentando o API Gateway

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.

Projeto de API declarativa NGINX

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 .

Pré-requisitos

Para executar o conteúdo deste blog, você precisa:

  • Uma instância em execução do NGINX Instance Manager
  • Uma assinatura (ou teste gratuito de 30 dias ) para NGINX Plus e NGINX App Protect WAF . O agente NGINX deve ser instalado para se conectar ao NGINX Instance Manager e fazer parte do grupo de instâncias declarativeAPITest
  • Um host Linux (bare metal ou VM) com docker e docker-compose para executar o projeto NGINX Declarative API
  • O carteiro deve enviar as solicitações declarativas da API
  • Um host cliente para executar o Postman

Visão geral do laboratório

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

Implementando a API Declarativa

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
ID DO CONTÊINER IMAGEM COMANDO CRIADO STATUS PORTAS NOMES


2. No host Linux, clone o repositório Github:


f5@ubuntu:~$ git clone https://github.com/f5devcentral/NGINX-Declarative-API/
Clonando em 'NGINX-Declarative-API'...
remoto: Enumerando objetos: 4072, feito.
remoto: Contando objetos: 100% (1982/1982), feito.
remoto: Comprimindo objetos: 100% (1332/1332), concluído.
remoto: Total 4072 (delta 668), reutilizado 876 (delta 609), pacote-reutilizado 2090
Recebendo objetos: 100% (4072/4072), 19,05 MiB | 4,88 MiB/s, concluído.
Resolução de deltas: 100% (1154/1154), concluído.
f5@ubuntu:~$


3. Mude para o diretório docker-compose:


f5@ubuntu:~$ cd NGINX-API-Declarativa/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
-> Atualizando imagens do docker
[+] Puxando 11/11
[...]
-> Implantando NGINX Declarative API
[+] Executando 4/4
✔ Rede nginx-dapi_dapi-network Criado 0,1s 
✔ Contêiner redis Iniciado 1,5s 
✔ Contêiner devportal Iniciado 1,5s 
✔ Contêiner nginx-dapi Iniciado


5. Verifique os contêineres docker em execução:


f5@ubuntu:~/NGINX-Declarative-API/contrib/docker-compose$ docker ps
ID DO CONTÊINER IMAGEM COMANDO CRIADO STATUS PORTAS NOMES
e29a2f783da2 nginx-declarative-api "/deployment/env/bin…" 5 minutos atrás Ativo 5 minutos 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp nginx-dapi
97142840eaf7 redis "docker-entrypoint.s…" 5 minutos atrás Ativo 5 minutos 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
6b50c0426643 nginx-declarative-api-devportal "/deployment/src/sta…" 5 minutos atrás Up 5 minutos 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 executada
  • ncg_port - Porta TCP para a API declarativa NGINX: 5000 é o padrão
  • nim_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 Manager
  • nim_password - senha de autenticação do NGINX Instance Manager

9. 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:


{
"saída": {
"tipo": "nms",
"nms": {
"url": "{{nim_host}}",
"nome de usuário": "{{nim_username}}",
"senha": "{{nim_password}}",
"grupo de instâncias": "{{nim_instancegroup}}",
"tempo de sincronização": 0,
"módulos": [
"ngx_http_app_protect_module"
],
"certificados": [
{
"tipo": "certificado",
"nome": "test_cert",
"conteúdo": {
"conteúdo": "{{github_gitops_root}}/v4.2/testcert.crt"
}
},
{
"tipo": "chave",
"nome": "test_key",
"conteúdo": {
"conteúdo": "{{github_gitops_root}}/v4.2/testcert.key"
}
}
],
"políticas": [
{
"tipo": "app_protect",
"nome": "política-de-produção",
"tag_ativa": "xss-bloqueado",
"versões": [
{
"tag": "xss-bloqueado",
"displayName": "Política de Produção - XSS bloqueado",
"description": "Esta é uma política pronta para produção - XSS bloqueado",
"contents": {
"content": "{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json"
}
},
{
"tag": "xss-allowed",
"displayName": "Política de Produção - XSS permitido",
"description": "Esta é uma política pronta para produção - XSS permitido",
"contents": {
"content": "{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json"
}
}
]
}
]
}
},
"declaration": {
"http": {
"servers": [
{
"name": "API Petstore",
"nomes": [
"apigw.nginx.lab"
],
"resolver": "8.8.8.8",
"ouvir": {
"endereço": "0.0.0.0:443",
"http2": verdadeiro,
"tls": {
"certificado": "test_cert",
"chave": "test_key",
"cifras": "PADRÃO",
"protocolos": [
"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": "Autenticação JWT do Petstore"
}
],
"enforceOnPaths": true,
"paths": [
"/user/login",
"/user/logout"
]
},
"authorization": [
{
"profile": "Autorização baseada em função JWT",
"enforceOnPaths": true,
"paths": [
"/user/login",
"/user/logout"
]
}
],
"rate_limit": [
{
"profile": "petstore_ratelimit",
"httpcode": 429,
"explosão": 0,
"atraso": 0,
"enforceOnPaths": verdadeiro,
"caminhos": [
"/usuário/login",
"/usuário/logout"
]
}
]
},
"log": {
"acesso": "/var/log/nginx/petstore-access_log",
"erro": "/var/log/nginx/petstore-error_log"
},
"app_protect": {
"habilitado": verdadeiro,
"política": "política de produção",
"log": {
"nome_do_perfil": "secops_dashboard",
"habilitado": verdadeiro,
"destino": "127.0.0.1:514"
}
}
}
]
}
],
"rate_limit": [
{
"nome": "petstore_ratelimit",
"chave": "$binary_remote_addr",
"tamanho": "10m",
"taxa": "2r/s"
}
],
"autenticação": {
"cliente": [
{
"nome": "Autenticação JWT Petstore",
"type": "jwt",
"jwt": {
"realm": "Autenticação Petstore",
"chave": "{\"chaves\": [{\"k\":\"ZmFudGFzdGljand0\",\"kty\":\"oct\",\"kid\":\"0001\"}]}",
"cachetime": 5
}
}
]
},
"autorização": [
{
"nome": "Autorização baseada em função JWT",
"type": "jwt",
"jwt": {
"claims": [
{
"name": "roles",
"value": [
"~(devops)"
],
"errorcode": 403 } ] } } ] } } }


A seção de saída define:

  • O servidor NGINX Instance Manager da API Declarativa publicará a configuração do NGINX para
  • Certificados e chaves TLS - eles podem ser referenciados pela URL da fonte da verdade onde estão armazenados
  • O aplicativo NGINX protege as políticas de segurança do WAF - elas podem ser referenciadas pela URL da fonte da verdade onde estão armazenadas

A seção de declaração descreve:

  • O servidor NGINX a ser criado
  • Se o descarregamento TLS é executado ou não
  • Onde registrar entradas de acesso e erro
  • O URI base /petstore onde a configuração do API Gateway será implantada e disponibilizada aos clientes
  • A configuração do API Gateway e o portal do desenvolvedor serão publicados
  • Como o NGINX App Protect WAF é habilitado, qual política de segurança usar e onde registrar violações de segurança
  • Como autenticar e autorizar solicitações de clientes

A 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": {
"habilitado": verdadeiro,
"strip_uri": verdadeiro,
"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": {
"habilitado": verdadeiro,
"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 :


"autenticação": {
"cliente": [
{
"perfil": "Autenticação JWT do Petstore"
}
],
"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 :


"autorização": [
{
"perfil": "Autorização baseada em função JWT",
"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": [
{
"perfil": "petstore_ratelimit",
"httpcode": 429,
"explosão": 0,
"atraso": 0,
"enforceOnPaths": verdadeiro,
"caminhos": [
"/usuário/login",
"/usuário/logout"
]
}
]
},


12. Use o botão Postman Send para publicar a solicitação na API declarativa. A resposta é semelhante a:


{
"código": 200,
"conteúdo": {
"createTime": "2024-04-26T17:09:10.419574328Z",
"detalhes": {
"falha": [],
"pendente": [],
"sucesso": [
{
"nome": "vm-test"
}
]
},
"id": "1060ec49-120e-45ca-820b-5203c8b3538d",
"mensagem": "Instance Group config publicado com sucesso para 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.

Testando o API Gateway

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 
data: Sex, 26 Abr 2024 17:13:54 GMT
content-type: application/json
access-control-allow-origin: *
access-control-allow-methods: OBTER, POSTAR, EXCLUIR, COLOCAR
access-control-allow-headers: Tipo de conteúdo, api_key, Autorização

{"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 
data: Sex, 26 Abr 2024 17:14:51 GMT
content-type: text/html
content-length: 179
www-autenticar: Bearer realm="Autenticação Petstore"
<html>
<head><title>Autorização 401 necessária</title></head>
<body>
<center><h1>Autorização 401 necessária</h1></center>
<hr><center>nginx/1.25.3</center>
</body>
</html>
HTTP/2 429 
data: Sex, 26 Abr 2024 17:14:51 GMT
content-type: text/html
content-length: 169
<html>
<head><title>429 Muitas solicitações</title></head>
<body>
<center><h1>429 Muitas solicitações</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 "Autorização: Portador `cat jwt.devops`"
HTTP/2 200 
data: Sex, 26 Abr 2024 17:15:41 GMT
content-type: application/json
access-control-allow-origin: *
access-control-allow-methods: OBTER, POSTAR, EXCLUIR, COLOCAR
access-control-allow-headers: Tipo de conteúdo, api_key, Autorização
x-expires-after: Sex Abr 26 18:15:41 UTC 2024
x-rate-limit: 5000

{"code":200,"type":"unknown","message":"usuário conectado sessão:1714151741883"}



5. Autenticação e autorização inválida:


$ curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Autorização: Portador `cat jwt.guest`"
HTTP/2 403 
data: Sex, 26 Abr 2024 17:16:07 GMT
content-type: text/html
content-length: 153
<html>
<head><title>403 Proibido</title></head>
<body>
<center><h1>403 Proibido</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 tipo de conteúdo: texto/html; conjunto de caracteres=utf-8 controle de cache: sem cache pragma: sem cache comprimento do conteúdo: 246
<html><head><title>Solicitação rejeitada</title></head><body>A URL solicitada foi rejeitada. Consulte seu administrador.Seu ID de suporte é: 7283327928460093545[Voltar]

7. O portal do desenvolvedor pode ser acessado navegando até


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


Iniciar

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."