Nossa experiência na criação de um API Gateway

Algumas empresas, incluindo nosso cliente, desenvolvem produtos por meio de uma rede de parceiros. Por exemplo, grandes lojas online estão integradas com serviços de entrega — você faz um pedido e logo recebe um número de rastreamento do pacote. Outro exemplo é que, junto com o bilhete aéreo, você compra um seguro ou um bilhete para o aerotrem.

Para isso, utilizamos uma API, que deve ser disponibilizada para os parceiros através do API Gateway. Essa foi a tarefa que realizamos. Neste artigo, falaremos os detalhes.

Dado: um ecossistema e um portal de API com uma interface onde os usuários estão registrados, recebem informações, etc. Precisamos criar um API Gateway conveniente e confiável. No processo, precisávamos garantir

  • o registro,
  • o controle de conexão à API,
  • o monitoramento de como os usuários utilizam o sistema final,
  • o acompanhamento de indicadores de negócios.

Nossa experiência na criação de um API Gateway

Neste artigo, compartilharemos nossa experiência na criação de um API Gateway, na qual resolvemos as seguintes tarefas:

  • a autenticação do usuário,
  • a autorização do usuário,
  • a modificação da solicitação de entrada,
  • o proxypassing da solicitação,
  • o pós-processamento da resposta.


Existem dois tipos de gerenciamento de API:

1. O padrão, que funciona da seguinte forma. Antes de se conectar, o usuário testa as funcionalidades, depois paga e integra em seu site. É mais comumente utilizado por pequenas e médias empresas.

2. O gerenciamento de API B2B em grande escala, onde a empresa primeiro toma uma decisão de negócios sobre a conexão, torna-se parceira da empresa com um compromisso contratual, após o que se conecta à API. E somente depois de resolver todas as formalidades, a empresa obtém acesso de teste, passa por testes e entra em produção. Mas isso não é possível sem a decisão gerencial sobre a conexão.

Nossa experiência na criação de um API Gateway

Nossa solução

Nesta parte, falaremos sobre a criação do API Gateway.

Os usuários finais do gateway de API criado são os parceiros de nosso cliente. Para cada um deles, já armazenamos os contratos necessários. Precisamos apenas expandir a funcionalidade, marcando o acesso fornecido ao gateway. Portanto, é necessário um processo controlado de conexão e gestão.

Sem dúvida, poderíamos ter adotado uma solução pronta para resolver a tarefa de gerenciamento de API e a criação do API Gateway em particular. Por exemplo, uma dessas soluções poderia ser Azure API Management. Não funcionou para nós, porque já tínhamos um portal API e uma grande ecossistema construído ao redor dele. Todos os usuários já estavam registrados, eles já entendiam onde e como poderiam obter as informações necessárias. No portal API já existiam as interfaces necessárias, só precisávamos do API Gateway. Na verdade, foi isso que começamos a desenvolver.

O que chamamos de API Gateway é uma espécie de proxy. Novamente, tivemos a escolha — podíamos escrever nosso próprio proxy ou optar por algo já pronto. Neste caso, optamos pela segunda opção e escolhemos a combinação nginx+Lua. Por quê? Precisávamos de um software confiável e testado que suportasse escalabilidade. Não queríamos, após a implementação, verificar tanto a lógica de negócios quanto a funcionalidade do proxy.

Qualquer servidor web tem um pipeline de processamento de solicitações. No caso do nginx, ele se apresenta da seguinte forma:

Nossa experiência na criação de um API Gateway

(diagrama de GitHub Lua Nginx)

Nosso objetivo era nos integrar a esse pipeline no momento em que pudéssemos modificar a solicitação original.

Queremos criar um proxy transparente, para que a solicitação funcional permaneça como chegou. Apenas controlamos o acesso à API final, ajudando a solicitação a chegar até ela. Caso a solicitação seja incorreta, o erro deve ser retornado pela API final, e não por nós. A única razão pela qual podemos rejeitar uma solicitação é devido à falta de acesso do cliente.

Já existe um extensão para Lua. Lua é uma linguagem de script, muito leve e fácil de aprender. Assim, implementamos a lógica necessária usando Lua.

A configuração do nginx (uma analogia ao route de um aplicativo), onde toda a operação é realizada, é bastante compreensível. O destaque aqui é a última diretiva — post_action.

location /middleware {
      more_clear_input_headers Accept-Encoding;
      lua_need_request_body on;
      rewrite_by_lua_file 'middleware/rewrite.lua';
      access_by_lua_file 'middleware/access.lua';
      proxy_pass https://someurl.com;
      body_filter_by_lua_file 'middleware/body_filter.lua';
      post_action /process_session;
}

Vamos analisar o que acontece nesta configuração:
more_clear_input_headers — limpa o valor dos cabeçalhos especificados após a diretiva.
lua_need_request_body — define se deve ler o corpo original da solicitação antes de executar as diretivas rewrite/access/access_by_lua ou não. Por padrão, o nginx não lê o corpo da solicitação do cliente, e se você precisar acessá-lo, esta diretiva deve estar definida como on.
rewrite_by_lua_file — caminho até o script que descreve a lógica para modificar a solicitação
access_by_lua_file — caminho até o script que descreve a lógica que verifica a presença de acesso ao recurso.
proxy_pass — url para o qual a solicitação será proxy.
body_filter_by_lua_file — caminho até o script que descreve a lógica para filtrar a solicitação antes de retorná-la ao cliente.
E, finalmente, post_action — uma diretiva oficialmente não documentada, que permite realizar outras ações após a resposta ter sido enviada ao cliente.

A seguir, explicaremos em ordem como resolvemos nossas tarefas.

Autorização/autenticação e modificação da solicitação

Autorização

Construímos a autorização e autenticação por meio de acessos por certificado. Existe um certificado raiz. Para cada novo cliente do contratante, é gerado um certificado pessoal, com o qual ele pode acessar a API. Este certificado é configurado na seção server das configurações do nginx.

ssl on;
ssl_certificate /usr/local/openresty/nginx/ssl/cert.pem;
ssl_certificate_key /usr/local/openresty/nginx/ssl/cert.pem;
ssl_client_certificate /usr/local/openresty/nginx/ssl/ca.crt;
ssl_verify_client on;

Modificação

Uma pergunta justa pode surgir: o que fazer com um cliente certificado, se de repente quisermos desconectá-lo do sistema? Não vamos emitir novos certificados para todos os outros clientes.

Assim, chegamos suavemente à próxima tarefa — a modificação da solicitação original. A solicitação original do cliente, em geral, não é válida para o sistema final. Um dos objetivos é adicionar as partes faltantes à solicitação para torná-la válida. A questão é que os dados ausentes são diferentes para cada cliente. Sabemos que o cliente nos apresenta um certificado, do qual podemos extrair a impressão digital e obter os dados necessários do cliente do banco de dados.

Se em algum momento for necessário desconectar o cliente do nosso serviço, seus dados desaparecerão do banco de dados e ele não poderá fazer nada.

Trabalhando com os dados do cliente

Precisávamos garantir alta disponibilidade da solução, especialmente no que diz respeito à forma como obtemos os dados do cliente. A complexidade está no fato de que a fonte original desses dados é um serviço externo, que não garante operação ininterrupta e uma largura de banda suficientemente alta.

Portanto, precisávamos garantir alta disponibilidade dos dados dos clientes. Como ferramenta, escolhemos Hazelcast, que nos fornece:

  • acesso rápido aos dados,
  • a capacidade de organizar um cluster de várias nodes com dados replicados em diferentes nodes.

Optamos pela estratégia mais simples de entrega de dados em cache:

Nossa experiência na criação de um API Gateway

O trabalho com o sistema final ocorre dentro de sessões, e há um limite para o número máximo. Se o cliente não fechar a sessão, teremos que fazê-lo.

Os dados sobre a sessão aberta vêm do sistema final e são inicialmente processados no lado do Lua. Decidimos usar o Hazelcast para armazenar esses dados com um job escrito em .NET. Em seguida, verificamos periodicamente a validade das sessões abertas e fechamos as que estão expiradas.

Acesso ao Hazelcast tanto do Lua quanto do .NET

Não há clientes para Lua que trabalhem com Hazelcast, mas o Hazelcast tem uma API REST, que decidimos utilizar. Para .NET, existe leve, através do qual planejamos acessar os dados do Hazelcast do lado do .NET. Mas não foi tão simples.

Nossa experiência na criação de um API Gateway

Ao salvar dados via REST e recuperá-los através do cliente .NET, diferentes serializadores/deserializadores são utilizados. Portanto, não é possível enviar dados via REST e recuperá-los através do cliente .NET e vice-versa.

Se houver interessados, contaremos mais sobre esse problema em um artigo separado. Spoiler — na figura.

Nossa experiência na criação de um API Gateway

Registro e monitoramento

Nosso padrão corporativo para registro via .NET é o Serilog, todos os logs acabam no Elasticsearch, e a análise é feita através do Kibana. Algo semelhante queríamos fazer nesse caso. O único leve para trabalhar com Elastic em Lua que foi encontrado quebrou na primeira importação. Então usamos o Fluentd.

Fluentd é uma solução open source para fornecer uma camada unificada de registro de aplicações. Permite coletar logs de diferentes camadas da aplicação e depois transmiti-los para uma fonte única.

O API Gateway funciona no K8S, então decidimos adicionar um contêiner com o fluentd no mesmo pod, para escrever logs na porta TCP aberta existente do fluentd.

Também investigamos como o fluentd se comportaria se não tivesse conexão com o Elasticsearch. Durante dois dias, o gateway recebeu solicitações contínuas, os logs foram enviados para o fluentd, mas o IP do Elastic foi bloqueado para o fluentd. Após a restauração da conexão, o fluentd conseguiu transferir todos os logs para o Elastic.

Conclusão

A abordagem escolhida para a implementação nos permitiu entregar um produto funcional ao ambiente de produção em apenas 2,5 meses.

Se você algum dia se deparar com tarefas semelhantes, recomendamos que, em primeiro lugar, entenda claramente qual problema você está resolvendo e quais recursos você já possui. Esteja atento às complexidades da integração com sistemas de gerenciamento de API existentes.

Entenda para si mesmo o que exatamente você pretende desenvolver — apenas a lógica de negócios para processar solicitações ou, como poderia ser em nosso caso, o proxy como um todo. Não se esqueça de que tudo o que você fizer por conta própria deve ser rigorosamente testado posteriormente.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster