paint-brush
Cómo crear servicios internos multiinquilino en AWS y CDK (Parte 1): API Gateway y AppSyncpor@filletofish
2,433 lecturas
2,433 lecturas

Cómo crear servicios internos multiinquilino en AWS y CDK (Parte 1): API Gateway y AppSync

por Filipp Fediakov11m2023/09/19
Read on Terminal Reader

Demasiado Largo; Para Leer

En la primera entrega de esta serie multiinquilino, exploramos las complejidades de crear servicios internos multiinquilino en AWS. Profundizamos en AWS API Gateway y AppSync, cubriendo aspectos cruciales como el aislamiento, el monitoreo y el escalado de inquilinos. Descubra las mejores prácticas para proteger y optimizar su arquitectura multiinquilino, con ideas y ejemplos prácticos.
featured image - Cómo crear servicios internos multiinquilino en AWS y CDK (Parte 1): API Gateway y AppSync
Filipp Fediakov HackerNoon profile picture
0-item



En esta serie de publicaciones de blog, me gustaría analizar las mejores prácticas para crear servicios multiinquilino en AWS . La literatura existente sobre cómo crear servicios multiinquilino suele estar dirigida a aplicaciones SaaS con cientos de clientes (por ejemplo , creación de una solución SaaS multiinquilino utilizando servicios sin servidor de AWS ).


El motivo principal de esta serie es centrarse en crear servicios multiinquilino para casos de uso con menos clientes y todos implementados en cuentas de AWS. Por lo general, esto se aplicaría a escenarios en los que se crea un servicio multiinquilino para uso interno.


Dividiré la serie de publicaciones del blog en tres partes para cada tipo de integración de servicio a servicio: integración sincrónica, asincrónica y por lotes.


La parte 1 analizará la arquitectura multiinquilino para dos servicios de AWS: API Gateway y AppSync. A lo largo del artículo, hago referencia al código de la aplicación de muestra creada para este artículo en Typecript y AWS CDK: https://github.com/filletofish/aws-cdk-multi-tenant-api-example/tree/main .


Descripción general del contenido

  1. Multiinquilino para servicios internos

    1.1. Aislamiento de inquilinos

    1.2. Monitoreo multiinquilino

    1.3. Escalada

  2. Multiinquilino para servicios internos

    2.1. Aislamiento de inquilinos - control de acceso

    2.2 Aislamiento de inquilinos: problema de vecinos ruidosos

    2.3 Monitoreo de múltiples inquilinos

    2.4 Métricas, Alarmas, Paneles

    2.5 Incorporación y baja de clientes API

  3. Multiinquilino con AWS AppSync

  4. Conclusión

1. Multiinquilino para servicios internos


El multiinquilino es la capacidad del software para atender a varios clientes o inquilinos con una única instancia del software.


Una vez que permite que más de un equipo llame a su API de servicio, su servicio se vuelve multiinquilino. La arquitectura multiinquilino introduce complejidad adicional a sus servicios, como aislamiento de inquilinos, monitoreo a nivel de inquilinos y escalamiento.


Ejemplo de servicio interno multiinquilino


1.1. Aislamiento de inquilinos

Generalmente, el aislamiento de inquilinos aborda los problemas de seguridad al garantizar que se impida que los inquilinos accedan a los recursos de otros inquilinos. Además, se implementa el aislamiento de inquilinos para garantizar que cualquier falla causada por un inquilino no afecte a otros inquilinos de su servicio. También se suele denominar problema de vecino ruidoso. Obtenga más información en el documento técnico de AWS sobre estrategias de aislamiento de inquilinos https://d1.awsstatic.com/whitepapers/saas-tenant-isolation-strategies.pdf .


1.2. Monitoreo multiinquilino

Una vez que varios inquilinos comiencen a compartir recursos de infraestructura, deberá monitorear cómo cada uno de sus inquilinos usa su sistema. Por lo general, significa que el nombre o identificador del inquilino debe estar presente en sus registros, métricas y paneles. La supervisión multiinquilino podría resultar útil por varios motivos:


  1. Solución de problemas: simplifica la identificación y resolución de problemas, distinguiendo los problemas específicos de los inquilinos de los más amplios.
  2. Asignación de recursos y planificación de capacidades. La supervisión multiinquilino puede ayudarle a realizar un seguimiento del consumo de recursos por inquilino para la asignación de recursos y la planificación de capacidad. Incluso si su servicio no tiene servidor, aún necesita comprender el consumo de recursos de su cliente para saber si pronto alcanzará alguno de los límites de AWS (un ejemplo típico es el límite de ejecución concurrente de la función Lambda).
  3. Gestión de SLA: permite el seguimiento del rendimiento específico de los inquilinos frente a los SLA.
  4. Facturación. Es poco probable que empieces a facturar a otros equipos por utilizar tu servicio interno. Sin embargo, en alguna escala de crecimiento de la empresa, facturar a otros equipos podría ser una buena idea para garantizar un uso frugal del servicio.


1.3. Escalada

Es probable que los servicios multiinquilino estén más expuestos a desafíos de escalamiento que los servicios de un solo inquilino. Sin embargo, la escalabilidad es un tema muy amplio y no lo cubriré en esta publicación de blog.


2. Multiinquilino con API Gateway

Si está creando su servicio web de AWS con API REST , HTTP o WebSocket en AWS, lo más probable es que esté utilizando API Gateway.


2.1. Aislamiento de inquilinos - control de acceso

AWS recomienda implementar cada servicio en sus propias cuentas de AWS para aislar los recursos y datos del servicio, facilitar la administración de costos y separar los entornos de prueba y producción (consulte los detalles en el documento técnico de AWS Cómo organizar su entorno de AWS mediante varias cuentas ).


Si los servicios de su empresa están implementados en AWS, la solución más obvia para administrar el acceso a su API Gateway es AWS IAM. AWS Cognito es otra opción para administrar el acceso a API multiinquilino (consulte Limitación de una API REST multiinquilino por niveles a escala mediante API Gateway , Los argumentos a favor y en contra de Amazon Cognito ).


La comparación entre AWS IAM y AWS Cognito merece un análisis profundo por separado. Pero para este artículo, me quedaría con AWS IAM ya que es la forma más sencilla de administrar el acceso cuando los servicios de su empresa están en AWS.


Una vez que habilite la autorización de AWS IAM para el método API Gateway (consulte CFN ), todas las solicitudes de API para este método deben firmarse con credenciales de identidad de IAM autorizadas para llamar a su API Gateway.


De forma predeterminada, no se permite ningún acceso entre cuentas de AWS. Por ejemplo, se producirá un error al invocar su API Gateway con las credenciales de otra cuenta de AWS. Para integrar a sus clientes con su API, necesita configurar el acceso entre cuentas. Para otorgar acceso entre cuentas a su API Gateway, puede utilizar dos métodos: autorización basada en recursos (no disponible para la API HTTP de API Gateway) y autorización basada en identidad (consulte más en https://repost.aws/knowledge-center/ acceso-api-gateway-cuenta ):


  1. Incorporación de un cliente con autorización basada en recursos . Para el acceso basado en recursos, debe actualizar la política de recursos de API Gateway y agregar la cuenta de AWS de su cliente. La principal desventaja de este método es que una vez que actualiza la política de recursos, es necesario volver a implementar la etapa API Gateway para que los cambios surtan efecto (consulte los documentos de AWS [1] y [2] ). Sin embargo, si utiliza CDK, puede automatizar la implementación de nuevas etapas (consulte AWS CDK Docs para Api Gateway ). Otra desventaja es el límite de duración máxima de la política de recursos.


  2. Incorporación de un cliente con autorización basada en identidad . Para el control de acceso basado en identidad, debe crear una función de IAM para el cliente y permitir que el cliente la asuma actualizando la política de recursos de la función (relaciones de confianza). Podría utilizar usuarios de IAM, pero los roles de IAM son mejores desde el punto de vista de la seguridad. Los roles permiten la autenticación con credenciales temporales y no requieren almacenar las credenciales de usuario de IAM. Hay un límite de 1000 roles por cuenta, pero este límite es ajustable. Además, otra desventaja del método basado en roles para obtener acceso entre cuentas a su API es que necesita crear un rol de IAM para cada nuevo cliente API. Sin embargo, la gestión de funciones se puede automatizar con CDK (consulte el ejemplo de código de la aplicación CDK proporcionada ).



La autorización de AWS IAM solo le permite controlar el acceso a API Gateway (mediante la política de IAM, puede especificar qué cuenta de AWS puede llamar a qué puntos finales de API Gateway). Es su responsabilidad implementar control de acceso a los datos y otros recursos subyacentes de su servicio. Dentro de su servicio, puede utilizar el ARN de AWS IAM de la persona que llama que se pasa con la solicitud de puerta de enlace API para un mayor control de acceso:


 export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => { // IAM Principal ARN of the api caller const callerArn = event.requestContext.identity.userArn!; // .. business logic based on caller return { statusCode: 200, body: JSON.stringify({ message: `Received API Call from ${callerArn}`, }) }; };



2.2. Aislamiento de inquilinos: problema de vecinos ruidosos

El límite predeterminado de API Gateway es 10 000 TPS ( cuotas y límites de API Gateway ). Sin embargo, debido a sus dependencias posteriores, su servicio podría requerir un límite de TPS más bajo. Para evitar una sobrecarga de solicitudes de API de un solo inquilino que afectará la disponibilidad de todo el sistema, debe implementar una limitación de la tasa de API por inquilino (también conocida como "limitación" o "control de admisión").


Puede utilizar claves y planes de uso de API de API Gateway para configurar límites para cada cliente por separado (para obtener más detalles, consulte la documentación de AWS [1], [2] y [3]).


2.3. Monitoreo multiinquilino

API Gateway tiene dos tipos de registros:

  1. Registros de ejecución de API Gateway: contiene datos como valores de parámetros de solicitud o respuesta, qué claves de API se requieren, si los planes de uso están habilitados, etc. No está habilitado de forma predeterminada, pero se puede configurar.


  2. Función de registros de acceso a API Gateway: le permite registrar quién accedió a su API, cómo se accedió, a qué punto final se accedió y el resultado de la llamada a la API. Puede proporcionar su formato de registro y elegir qué registrar con variables de contexto (ver documentos, en CDK).


Para monitorear las solicitudes de sus clientes API, recomendaría habilitar el registro de acceso. Puede registrar al menos el ARN de AWS IAM de la persona que llama ( $context.identity.userArn ), la ruta de solicitud ( $context.path ), el código de estado de respuesta de su servicio $context.status y la latencia de llamada API ( $context.responseLatency ) .


Personalmente, para un servicio con función AWS IAM Auth y Lambda como cálculo, encontré útil esta configuración de registro de acceso de API Gateway:

 const formatObject = { requestId: '$context.requestId', extendedRequestId: '$context.extendedRequestId', apiId: '$context.apiId', resourceId: '$context.resourceId', domainName: '$context.domainName', stage: '$context.stage', path: '$context.path', resourcePath: '$context.resourcePath', httpMethod: '$context.httpMethod', protocol: '$context.protocol', accountId: '$context.identity.accountId', sourceIp: '$context.identity.sourceIp', user: '$context.identity.user', userAgent: '$context.identity.userAgent', userArn: '$context.identity.userArn', caller: '$context.identity.caller', cognitoIdentityId: '$context.identity.cognitoIdentityId', status: '$context.status', integration: { // The status code returned from an integration. For Lambda proxy integrations, this is the status code that your Lambda function code returns. status: '$context.integration.status', // For Lambda proxy integration, the status code returned from AWS Lambda, not from the backend Lambda function code. integrationStatus: '$context.integration.integrationStatus', // The error message returned from an integration // A string that contains an integration error message. error: '$context.integration.error', latency: '$context.integration.latency', }, error: { responseType: '$context.error.responseType', message: '$context.error.message', }, requestTime: '$context.requestTime', responseLength: '$context.responseLength', responseLatency: '$context.responseLatency', }; const accessLogFormatString = JSON.stringify(formatObject); const accessLogFormat = apigw.AccessLogFormat.custom(accessLogFormatString);


Una vez habilitado el registro, puede utilizar CloudWatch Insights para obtener fácilmente las últimas llamadas de un cliente API elegido con:

 fields @timestamp, path, status, responseLatency, userArn | sort @timestamp desc | filter userArn like 'payment-service' | limit 20


2.4. Métricas, Alarmas, Paneles

Las métricas de CloudWatch admitidas por API Gateway de forma predeterminada se agregan para todas las solicitudes. Pero puede analizar los registros de acceso de API Gateway para publicar métricas personalizadas de CloudWatch con una dimensión adicional de su nombre de cliente para poder monitorear el uso de su API por parte del cliente (inquilino). Como mínimo, recomendaría publicar métricas de CloudWatch por cliente Count, 4xx, 5xx, Latency split by Dimension=${Client} . También puede agregar dimensiones como código de estado y ruta API.


2.4.1. Uso de filtros de registro de métricas para publicar métricas por cliente


Los filtros de registro de métricas de CloudWatch (consulte los documentos) le permiten proporcionar un filtro personalizado y extraer valores de métricas de los registros de acceso de API Gateway (consulte el ejemplo a continuación). Los filtros de registro de métricas también permiten extraer valor para dimensiones de métricas personalizadas de los registros. Para la supervisión de múltiples inquilinos, la dimensión Cliente podría ser el ARN de IAM de la persona que llama.


Las principales ventajas de los filtros de registro de métricas son (1) no hay que administrar ningún cálculo (2) es simple y económico. Pero no puede realizar modificaciones en los datos (por ejemplo, establecer nombres de clientes más legibles en lugar de ARN de IAM) y existe un límite de 100 filtros de métricas por grupo de registros (documentos).


Ejemplo de filtro de registro de métricas de CloudWatch para publicar Count con la dimensión Client y Path

 new logs.MetricFilter(this, 'MultiTenantApiCountMetricFilter', { logGroup: accessLogsGroup, filterPattern: logs.FilterPattern.exists('$.userArn'), metricNamespace: metricNamespace, metricName: 'Count', metricValue: '1', unit: cloudwatch.Unit.COUNT, dimensions: { client: '$.userArn', method: '$.httpMethod', path: '$.path',},}); });


Vea todos los filtros de métricas para errores 4xx, 5xx y latencia en la aplicación CDK de muestra proporcionada .


2.4.2. Uso de la función Lambda para publicar métricas por cliente

La opción alternativa es crear una función Lambda para analizar los registros, extraer métricas y publicarlas. Esto le permite hacer más cosas personalizadas, como filtrar clientes desconocidos o extraer el nombre del cliente del usuario.


Con solo un par de líneas de código CDK para suscribir la función Lambda a los registros de acceso de API Gateway:


 const logProcessingFunction = new lambda.NodejsFunction( this, 'log-processor-function', { functionName: 'multi-tenant-api-log-processor-function', } ); new logs.SubscriptionFilter(this, 'MultiTenantApiLogSubscriptionFilter', { logGroup: accessLogsGroup, destination: new logsd.LambdaDestination(logProcessingFunction), filterPattern: logs.FilterPattern.allEvents(), });


Vea el ejemplo completo en el código , así como la implementación de la función Lambda del procesador de registros .


Agregar claves de uso y función Lambda para publicar métricas por cliente



Una vez que haya comenzado a publicar métricas de API Gateway divididas por Cliente, ahora puede crear CloudWatch Dashboards y CloudWatch Alarms para cada cliente por separado.



Ejemplo de métricas por cliente en CloudWatch Dashboard



2.5. Incorporación y baja de clientes API

Su aplicación CDK podría ser una solución sencilla para almacenar una configuración con nombres de clientes, sus cuentas de AWS, límites de TPS solicitados y otros metadatos. Para incorporar un nuevo cliente API, deberá agregarlo a la configuración administrada en el código:


 interface ApiClientConfig { name: string; awsAccounts: string[]; rateLimit: number; burstLimit: number; } const apiClients: ApiClientConfig[] = [ { name: 'payment-service', awsAccounts: ['111122223333','444455556666'], rateLimit: 10, burstLimit: 2, }, { name: 'order-service', awsAccounts: ['777788889999'], rateLimit: 1, burstLimit: 1, }, ];


Con esta configuración, la aplicación CDK puede crear una función de IAM, una clave de uso de API Gateway y pasar el nombre del cliente a la función Lambda que analiza los registros de acceso (consulte el código de la aplicación de muestra).


3. Multiinquilino con AWS AppSync

Si su servicio tiene una API GraphQL , probablemente use AppSync. De manera similar a API Gateway, puede utilizar IAM Auth para autorizar solicitudes de AppSync. AppSync no tiene una política de recursos (consulte el problema de GH ), por lo que solo puede usar una autorización basada en roles para configurar el control de acceso a la API de AppSync. De manera similar a API Gateway, crearía una función de IAM separada para cada nuevo inquilino de su servicio.


Desafortunadamente, AppSync tiene soporte limitado para la limitación por cliente que necesitamos para el aislamiento y monitoreo de inquilinos. Si bien puede configurar límites de TPS para AppSync con WAF, no puede crear límites separados por cliente para aislar a los inquilinos de su servicio. De manera similar, AppSync no proporciona registros de acceso como lo hace API Gateway.


¿Solución? Puede agregar API Gateway como proxy a su AppSync y utilizar todas las funciones de API Gateway descritas anteriormente para implementar requisitos de múltiples inquilinos, como el aislamiento y la supervisión de inquilinos. Además, puede utilizar otras funciones de API Gateway, como Lambda Authorizers, Custom Domain y administración del ciclo de vida de API que aún no existen en AppSync. La desventaja es una ligera latencia adicional para sus solicitudes.




Solicitudes de proxy a AppSync con API Gateway


4. Conclusión

Eso es todo. Si tienes alguna pregunta o idea, házmelo saber en los comentarios o contáctame directamente. En la siguiente parte de esta serie, revisaré las mejores prácticas para la integración interna asíncrona con AWS Event Bridge y AWS SQS/SNS.


Si desea profundizar en el tema de la creación de servicios multiinquilino sobre AWS, estos recursos me resultaron útiles:

  1. Documento técnico de AWS sobre estrategias de aislamiento de inquilinos de SaaS
  2. Equidad en sistemas multiinquilino
  3. AWS re:Invent 2021: patrones de arquitectura SaaS: del concepto a la implementación



También publicado aquí.