Nuestra experiencia en la creación de API Gateway

Algunas empresas, incluyendo a nuestro cliente, desarrollan el producto a través de una red de socios. Por ejemplo, grandes tiendas en línea están integradas con el servicio de entrega: usted ordena un producto y, poco después, recibe un número de seguimiento del paquete. Otro ejemplo es que junto con el boleto de avión, compra un seguro o un boleto para el aerotren.

Para esto se utiliza una única API, que debe ser proporcionada a los socios a través del API Gateway. Esta fue la tarea que resolvimos. En este artículo compartiremos los detalles.

Dado: un ecosistema y un portal API con una interfaz donde los usuarios están registrados, reciben información, etc. Necesitamos crear un API Gateway cómodo y fiable. En el proceso, necesitábamos asegurarnos de

  • registro,
  • control de la conexión a la API,
  • monitoreo de cómo los usuarios utilizan el sistema final,
  • consideración de indicadores empresariales.

Nuestra experiencia en la creación de API Gateway

En el artículo hablaremos sobre nuestra experiencia en la creación de un API Gateway, durante la cual resolvimos las siguientes tareas:

  • autenticación del usuario,
  • autorización del usuario,
  • modificación de la solicitud original,
  • proxy de la solicitud,
  • postprocesamiento de la respuesta.


Hay dos tipos de gestión de API:

1. Estándar, que funciona de la siguiente manera. Antes de la conexión, el usuario prueba las capacidades, luego paga e integra en su sitio web. Es más comúnmente utilizado en pequeñas y medianas empresas.

2. Gran B2B API Management, donde la empresa primero toma una decisión comercial sobre la conexión, se convierte en socio de la empresa con un compromiso contractual, después de lo cual se conecta a la API. Y ya después de resolver todas las formalidades, la empresa obtiene acceso de prueba, realiza pruebas y pasa a producción. Pero esto no es posible sin una decisión directiva sobre la conexión.

Nuestra experiencia en la creación de API Gateway

Nuestra solución

En esta parte hablaremos sobre la creación de API Gateway.

Los usuarios finales del gateway API que se está creando son los socios de nuestro cliente. Para cada uno de ellos ya tenemos los contratos necesarios. Solo necesitamos ampliar la funcionalidad, resaltando el acceso proporcionado al gateway. Por lo tanto, se requiere un proceso controlado de conexión y gestión.

Sin duda, podría haberse tomado alguna solución lista para resolver la tarea de gestión de API y la creación de API Gateway en particular. Por ejemplo, podría haber sido Azure API Management. No nos funcionó porque en nuestro caso ya teníamos un portal API y un gran ecosistema construido a su alrededor. Todos los usuarios ya estaban registrados y comprendían dónde y cómo podían obtener la información necesaria. Ya existían las interfaces requeridas en el portal API, solo necesitábamos un API Gateway. En realidad, eso fue lo que comenzamos a desarrollar.

Lo que llamamos API Gateway es una especie de proxy. Aquí nuevamente teníamos una elección: se podía escribir nuestro propio proxy o elegir algo ya existente. En este caso, optamos por la segunda opción y elegimos la combinación nginx+Lua. ¿Por qué? Necesitábamos un software confiable y probado que soportara la escalabilidad. No queríamos verificar después de la implementación tanto la corrección de la lógica de negocio como la funcionalidad del proxy.

Cualquier servidor web tiene un canal de procesamiento de solicitudes. En el caso de nginx, se ve de la siguiente manera:

Nuestra experiencia en la creación de API Gateway

(diagrama de GitHub Lua Nginx)

Nuestro objetivo era integrarse en este canal en el momento en que pudiéramos modificar la solicitud original.

Queremos crear un proxy transparente, de modo que funcionalmente la solicitud permanezca tal como llegó. Solo controlamos el acceso a la API final, ayudamos a que la solicitud llegue a ella. En caso de que la solicitud sea incorrecta, el error debe ser mostrado por la API final, no por nosotros. La única razón por la que podemos rechazar una solicitud es por falta de acceso del cliente.

Para nginx ya existe una extensión en Lua. Lua es un lenguaje de scripting, es muy ligero y fácil de aprender. De esta manera, implementamos la lógica necesaria con Lua.

La configuración de nginx (analogía de la ruta de la aplicación), donde se lleva a cabo todo el trabajo, es bastante comprensible. Lo notable aquí es la última directiva: 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;
}

Veamos qué sucede en esta configuración:
more_clear_input_headers — elimina el valor de los encabezados especificados después de la directiva.
lua_need_request_body — determina si se debe leer el cuerpo original de la solicitud antes de ejecutar las directivas rewrite/access/access_by_lua o no. Por defecto, nginx no lee el cuerpo de la solicitud del cliente, y si necesita acceder a él, esta directiva debe estar configurada como on.
rewrite_by_lua_file — ruta al script que describe la lógica para modificar la solicitud
access_by_lua_file — ruta al script que describe la lógica que verifica el acceso al recurso.
proxy_pass — URL al que se redirigirá la solicitud.
body_filter_by_lua_file — ruta al script que describe la lógica para filtrar la solicitud antes de devolverla al cliente.
Y, por último, post_action — directiva oficialmente no documentada que permite realizar más acciones después de que la respuesta ha sido enviada al cliente.

A continuación, explicaremos paso a paso cómo resolvimos nuestras tareas.

Autenticación/Autorización y modificación de la solicitud

Autorización

Construimos la autorización y autenticación a través de accesos por certificado. Hay un certificado raíz. Se genera un certificado personal para cada nuevo cliente del cliente, con el que puede acceder a la API. Este certificado se configura en la sección de server de los ajustes de 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;

Modificación

Puede surgir una pregunta justa: ¿qué hacer con un cliente certificado si de repente queremos desconectarlo del sistema? No vamos a volver a emitir certificados para todos los demás clientes.

Así que llegamos suavemente a la siguiente tarea: la modificación de la solicitud original. La solicitud original del cliente, en general, no es válida para el sistema final. Una de las tareas consiste en agregar las partes faltantes a la solicitud para hacerla válida. La cuestión es que los datos faltantes son diferentes para cada cliente. Sabemos que el cliente nos llega con un certificado, del cual podemos obtener una huella y extraer de la base de datos los datos necesarios del cliente.

Si en algún momento es necesario desconectar al cliente de nuestro servicio, sus datos desaparecerán de la base y no podrá hacer nada.

Trabajo con los datos del cliente

Necesitábamos asegurar una alta disponibilidad de la solución, especialmente en cómo obtenemos los datos del cliente. La dificultad radica en que la fuente original de estos datos es un servicio externo que no garantiza un funcionamiento ininterrumpido y una velocidad de operación suficientemente alta.

Por lo tanto, debíamos asegurar alta disponibilidad de los datos de los clientes. Como herramienta elegimos Hazelcast, que nos proporciona:

  • acceso rápido a los datos,
  • la posibilidad de organizar un clúster de múltiples nodos con datos replicados en diferentes nodos.

Optamos por la estrategia más sencilla para la entrega de datos en la caché:

Nuestra experiencia en la creación de API Gateway

El trabajo con el sistema final se realiza en sesiones y hay un límite en el número máximo de sesiones. Si el cliente no cierra la sesión, tendremos que hacerlo nosotros.

Los datos sobre la sesión abierta provienen del sistema final y se procesan inicialmente en el lado de Lua. Decidimos utilizar Hazelcast para almacenar estos datos con un job escrito en .NET. Luego, de forma periódica, verificamos la validez de las sesiones abiertas y cerramos las caducadas.

Acceso a Hazelcast tanto desde Lua como desde .NET

No hay clientes para Lua que trabajen con Hazelcast, pero Hazelcast tiene una REST API que decidimos utilizar. Para .NET hay cliente, a través del cual planeábamos acceder a los datos de Hazelcast desde .NET. Pero no fue tan sencillo.

Nuestra experiencia en la creación de API Gateway

Al guardar datos a través de REST y recuperarlos a través del cliente de .NET se utilizan diferentes serializadores/deserializadores. Por lo tanto, no es posible guardar datos a través de REST y recuperarlos a través del cliente de .NET, y viceversa.

Si hay interesados, contaremos más sobre este problema en un artículo separado. Spoiler: en el diagrama.

Nuestra experiencia en la creación de API Gateway

Registro y monitoreo

Nuestro estándar corporativo para el registro a través de .NET es Serilog, todos los registros terminan en Elasticsearch, y su análisis lo realizamos a través de Kibana. Queríamos hacer algo similar en este caso. El único cliente cliente para trabajar con Elastic en Lua que se encontró, falló en el primer require. Así que usamos Fluentd.

Fluentd es una solución de código abierto que proporciona una capa unificada de registro de aplicaciones. Permite recopilar registros de diferentes capas de la aplicación y luego transmitirlos a una fuente única.

API Gateway funciona en K8S, por lo que decidimos agregar un contenedor con Fluentd en el mismo pod, para escribir registros en el puerto tcp abierto existente de Fluentd.

También investigamos cómo se comportaría Fluentd si no tuviera conexión con Elasticsearch. Durante dos días, la puerta de enlace recibió solicitudes continuamente, se enviaron registros a Fluentd, pero se bloqueó la IP de Elastic en Fluentd. Después de restaurar la conexión, Fluentd logró transferir todos los registros a Elastic sin problemas.

Conclusión

El enfoque elegido para la implementación nos permitió entregar un producto funcional en el entorno de producción en solo 2.5 meses.

Si alguna vez se encuentra involucrado en cosas similares, le recomendamos que primero entienda claramente qué problema está resolviendo y qué recursos ya tiene. Tenga cuidado con las dificultades de integración con los sistemas de gestión de API existentes.

Entienda para sí mismo qué es lo que planea desarrollar: solo la lógica de negocio para procesar solicitudes o, como podría ser en nuestro caso, el proxy completo. No olvide que todo lo que haga por su cuenta debe ser cuidadosamente probado posteriormente.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster