top of page
Foto del escritorRan Isenberg

AWS CDK: mejores prácticas desde la práctica


AWS CDK: mejores prácticas desde la práctica

¿Qué es AWS CDK?

AWS CDK le permite crear aplicaciones confiables, escalables y rentables en la nube con el considerable poder expresivo de un lenguaje de programación.

Creo que AWS CDK revolucionó la forma en que creamos recursos en la nube.

AWS CDK permite a los desarrolladores escribir infraestructura como código y sentirse como en casa.

Es una herramienta tan flexible y poderosa que es fácil cometer errores.

Algunos errores resultan muy costosos.


Hace un par de semanas, pregunté a los desarrolladores en LinkedIn y Twitter por qué no usan AWS CDK (dejando de lado la multicloud) y recibí muchas respuestas e inquietudes. ¡Gracias por compartir sus experiencias!

Me considero un defensor de AWS CDK; he dado conferencias sobre CDK internamente en mi lugar de trabajo, organicé unseminario web y di una charla en el primerAWS CDK Day 2020 .


Así que decidí que la mejor manera de abordar esas preocupaciones y convertir a la gente al CDK era:

1. Escriba mi opinión sobre una guía de mejores prácticas de CDK recopilada a lo largo de casi tres años de desarrollo con CDK.

2. Proporcionar un proyecto de plantilla CDK funcional que implemente estas prácticas, que se pueden encontrar aquí .

 

Prácticas recomendadas de AWS CDK

Logotipo de CDK

Estas pautas amplían las mejores prácticas oficiales de AWS CDK .

Tenga en cuenta que esta publicación de blog asume que tiene conocimientos básicos de AWS CDK y comprende los conceptos de pila y construcciones.

Estas directrices se dividen en varias categorías:

  1. Estructura del proyecto y pautas de la pila

  2. Construye pautas

  3. Directrices de CI/CD

  4. Resiliencia y seguridad

  5. Consejos generales de desarrollo

Si quieres la versión en vídeo, está disponible a continuación:


 

Estructura del proyecto y pautas de la pila

Estas directrices analizan una estructura de proyecto recomendada.


Un repositorio, una aplicación, una pila

“Cada aplicación comienza con una única pila en un único repositorio”: guía de prácticas recomendadas de AWS CDK

De acuerdo con las mejores prácticas oficiales de AWS CDK, su repositorio de código no debe contener más de una aplicación CDK, una pila con una o varias construcciones mantenidas por un equipo.

Estoy de acuerdo con esta práctica.

Agregar más pilas y aplicaciones al repositorio aumentará el tiempo de implementación y el radio de acción en caso de errores.

En lugar de múltiples pilas, utilice numerosas construcciones.

Sin embargo, ¿cómo saber cuándo dividir una pila en varias pilas?

Mi regla general es dividir cuando:

  1. La nueva pila es un servicio o microservicio diferente con requisitos o estrategias de implementación adicionales (implementar en múltiples regiones, etc.).

  2. Un equipo diferente mantendrá la nueva pila.

  3. La nueva pila tiene un dominio comercial diferente.

  4. La implementación se ha vuelto demasiado larga o demasiado compleja en la pila. Divida la pila en microservicios que distribuyan varios repositorios. La dependencia o el contrato entre los microservicios se definirán con API REST/SQS/EventBridge/SNS, etc.

Estructura del repositorio de servicios SaaS de AWS

El código AWS CDK y el controlador del servicio AWS Lambda residen en el mismo repositorio, pero en carpetas diferentes, como módulos de Python separados.

El proyecto se construye a partir de dos proyectos internos: el proyecto CDK de infraestructura como código y el código del servicio (código del controlador AWS Lambda con pruebas).

Estos dos proyectos internos están separados para reducir el radio de explosión en caso de errores y mejorar la facilidad de prueba de cada proyecto.

Dado que desarrollo servicios sin servidor, el ejemplo describe un proyecto sin servidor. Sin embargo, la estructura sigue siendo la misma para cualquier servicio que no sea sin servidor.


Las carpetas principales del proyecto son:

Carpetas principales del proyecto
  1. Carpeta CDK : en la carpeta "cdk". Una aplicación CDK implementa una pila que consta de una o más construcciones CDK. Las construcciones CDK contienen recursos de AWS y sus conexiones/relaciones. Lea más sobre los detalles del proyecto CDK aquí y aquí.

  2. Carpeta Docs : carpeta de documentación del servicio de páginas de GitHub (opcional).

  3. Carpeta de servicios : archivos del proyecto AWS Lambda: controlador, esquemas de entrada/salida y carpeta de utilidades. Cada controlador tiene su propia carpeta de esquemas. La carpeta de utilidades almacena el código compartido entre varios controladores.

  4. Carpeta de pruebas : pruebas unitarias, de integración y de extremo a extremo. Al separar el código de servicio de la infraestructura, ejecutar las pruebas localmente en el IDE es más sencillo.

Puedes encontrar mi proyecto de plantilla Serverless aquí y el blog al respecto aquí .


Crear proyectos de plantilla

Para acelerar la adopción de Serverless y el uso de CDK, puede crear un proyecto de plantilla que proporcione un nuevo servicio y equipo con un proyecto implementable de CDK funcional con una canalización funcional y controladores de AWS Lambda que contengan todas las mejores prácticas.

Como arquitecto en un grupo de plataforma en la nube, comprendimos que es importante compartir construcciones y brindar guías sobre cómo usar CDK, incluido un proyecto de plantilla.


Puedes encontrar mi proyecto de plantilla Serverless aquí y el blog al respecto aquí .


 

Pautas para la construcción

Esta sección contiene las mejores prácticas para desarrollar constructos.


Composición de la pila

Utilice construcciones para modelar los dominios de infraestructura de su aplicación.

Esfuércese por mantener al mínimo los recursos no constructivos definidos por la pila.

Si dos construcciones tienen la misma dependencia de recursos, ya sea:

  1. Coloque el recurso en una nueva construcción y proporciónelo como parámetro de entrada a ambos

  2. Decide qué construcción tiene el derecho de “poseerlo” y crearlo internamente. Proporciónalo como parámetro de entrada a la otra construcción.


Construcciones orientadas al dominio empresarial

No creo que haya un enfoque correcto o incorrecto para seleccionar recursos para las construcciones, siempre y cuando tenga sentido para usted y pueda encontrar recursos y configuraciones fácilmente.

Sin embargo, creo que lo más sensato es elegir un enfoque basado en el dominio empresarial para seleccionar qué recursos pertenecen juntos en una construcción.

Es más fácil encontrar recursos y comprender sus conexiones simplemente observando el diagrama de arquitectura de servicios. También es más fácil compartir patrones de diseño entre equipos de organizaciones que podrían requerir la misma arquitectura.

Supongamos que tengo un servicio de 'reserva' sin servidor que contiene dos dominios comerciales:

  1. Proporcionar API REST para acciones CRUD para que los clientes utilicen un sistema de reservas.

  2. Envía datos de reservas a través de varios servicios internos (comparte y envía información de reservas en un método asincrónico de servicio a servicio).

Supongamos que he diseñado la siguiente arquitectura:


Arquitectura del servicio de reservas
Arquitectura del servicio de reservas

  1. API GW con funciones CRUD AWS Lambda.

  2. Base de datos de AWS Aurora utilizada por las funciones CRUD para consultas de lectura y escritura.

  3. Las transmisiones de AWS Aurora activan una función de AWS Lambda que envía datos a través de un tema de AWS SNS a otros servicios externos.

  4. AWS SNS: una implementación central de publicación y suscripción entre servicios. Permite que tanto el servicio de "reserva" como los servicios externos se envíen mensajes entre sí a través del tema de reserva.

  5. AWS SQS se suscribió al tema SNS y a un destino de función AWS Lambda del SQS. Esta función Lambda recibe un evento de solicitud del SNS y consulta la base de datos Aurora y envía una respuesta a través del SNS.

Nota: La base de datos de AWS Aurora se accede mediante la API CRUD y las funciones Lambda de SQS/streams. Sin embargo, el uso de CRUD es de lectura y escritura, mientras que las funciones Lambda de SQS/streams son de solo lectura.


¿Cómo creamos los constructos?

Modelo el servicio en dos construcciones de dominio empresarial: CRUD y mensajería .


construcciones de servicios de reserva
construcciones de servicios de reserva

La construcción CRUD creará una instancia de los siguientes recursos:

  1. Funciones de AWS Lambda y sus roles.

  2. Construcción de Aurora: AWS Aurora es relativamente compleja de definir en CDK (VPC, bases de datos, permisos, etc.) y debe manejarse en su propia construcción instanciada dentro de la construcción CRUD.

La construcción de mensajería creará:

  1. Tema de AWS SNS.

  2. AWS SQS con una suscripción al tema AWS SNS.

  3. Función y rol de AWS Lambda activados por AWS SQS. La función Lambda tiene acceso de solo lectura a la base de datos de AWS Aurora y puede enviar eventos a AWS SNS.

  4. Función AWS Lambda activada por transmisiones Aurora que envían datos de reserva a servicios externos a través del tema AWS SNS.

La construcción de mensajería también recibirá la construcción Aurora como parámetro de entrada para definir los permisos y la configuración necesarios para las funciones de AWS Lambda.

Regla general: cualquier recurso compartido utilizado en todas las construcciones (cola de mensajes inactivos SQS o mecanismo de manejo de errores) debe definirse como una construcción independiente y pasarse como entrada a las otras construcciones.


Construcciones compartidas

Cree repositorios de bibliotecas de construcciones CDK que se puedan usar como dependencia de proyectos en toda la organización. Estas construcciones son recursos o incluso patrones seguros y probados.


Es posible que cuente con un equipo de ingeniería de la nube o de DevOps que cree estructuras compatibles. Puede leer sobre ingeniería de plataformas de la nube aquí .

Por ejemplo:

  1. Reglas WAF para distribuciones de AWS API Gateway/CloudFront.

  2. Patrón de activación SNS -> SQS donde SNS y SQS tienen cifrado en reposo definido con las CMK requeridas.

  3. Construcción de configuración dinámica de AWS AppConfig.

 

Directrices de CI/CD

Esta sección describe las pautas para la correcta implementación de la pila, el modelado del entorno y la experiencia del desarrollador con respecto a las pruebas y el desarrollo locales.


Despliegue de pila

“Los equipos de desarrollo deberían poder usar sus propias cuentas para realizar pruebas y tener la capacidad de implementar nuevos recursos en estas cuentas según sea necesario. Los desarrolladores individuales pueden tratar estos recursos como extensiones de su propia estación de trabajo de desarrollo” — Guía de AWS CDK

Se me ocurren varias opciones; elija la que tenga más sentido para usted teniendo en cuenta el tamaño de la empresa, el presupuesto y los gastos generales de gestión de cuentas de AWS.

Asegúrese de utilizar las pautas y las mejores prácticas para administrar esas cuentas con AWS Organizations y AWS ControlTower.


Las empresas más pequeñas utilizan estrategias como cuenta por desarrollador, donde se puede implementar TODA la línea de productos y su gran cantidad de microservicios en una sola cuenta para desarrollar localmente, realizar cambios, implementarlos y probarlos contra versiones locales estables de inmediato.

  1. La experiencia en desarrollo local es excelente.

  2. Las pruebas de integración son más sencillas y se pueden realizar de forma local. Sin embargo, imitar los datos de servicio reales por cuenta de AWS puede resultar complicado y reduce la viabilidad de las pruebas.

  3. Es difícil mantener la observabilidad en muchas cuentas.

  4. Gestionar un gran número de cuentas considerando el pequeño tamaño de la empresa.

Cuando los desarrolladores abren una solicitud de registro, la canalización se implementa en una cuenta diferente. El enfoque recomendado es el de las cuentas por etapa, ya que reduce el radio de explosión en caso de que se produzcan infracciones o errores.


Sin embargo, las empresas más grandes podrían optar por un enfoque diferente.

A veces, implementar todo el portafolio de la empresa en una sola cuenta es imposible debido a la complejidad, las cuotas de recursos y el conocimiento requerido para implementar los servicios.

Una opción viable para las grandes empresas consiste en lo siguiente:

  1. Los diferentes equipos de servicio obtienen sus cuentas de AWS separadas, lo que reduce la fricción, los conflictos y las posibilidades de alcanzar las cuotas de servicio de AWS por cuenta de AWS.

  2. Cada etapa del pipeline de CI/CD obtiene su cuenta de AWS (desarrollo, prueba, ensayo, producción, etc.).

  3. Los desarrolladores desarrollan en la cuenta de desarrollo en conjunto. Implementan sus pilas de CDK de servicio en la misma cuenta. Sin embargo, cada pila tiene un nombre o prefijo diferente para eliminar posibles conflictos de implementación.

  4. Los desarrolladores realizan pruebas contra servicios reales implementados en otras cuentas.

  5. Las pruebas de integración entre múltiples cuentas a veces pueden requerir confianza entre cuentas y pueden ser más desafiantes.

Como puedes ver, cada método tiene sus ventajas y desventajas, y no existe una solución milagrosa.


Modele las etapas de su flujo de trabajo de CI/CD en código

Utilice archivos de configuración locales y variables de entorno junto con condiciones de código (declaraciones 'if') para implementar diferentes configuraciones de recursos en varias cuentas y etapas.

Por ejemplo:

  1. Una cuenta de desarrollo puede tener políticas diferentes (por ejemplo, conservar la política establecida para destruir), pero una cuenta de producción practicará una configuración resistente.

  2. Cada etapa tendrá diferentes secretos y claves API: reduzca el radio de explosión si se vulnera una cuenta.

  3. La cuenta de producción definirá una mayor simultaneidad reservada de AWS Lambda o habilitará la simultaneidad aprovisionada para eliminar los inicios en frío.

  4. Diferentes modelos de facturación para AWS DynamoDB en varias etapas. Reduzca los costos en las cuentas de desarrollo y maximice el rendimiento en producción.

 

Pautas de resiliencia y seguridad


Definir políticas de retención

En un entorno de producción, es fundamental definir políticas de eliminación de recursos críticos o con estado (bases de datos) como "Retener" para no eliminar ni reconstruir los datos que contienen.

En el entorno de desarrollo, está bien eliminar los recursos una vez que se elimina la pila o cambia el ID del recurso.

Esta práctica reducirá sus costos y recursos huérfanos a largo plazo.


Pruebas de AWS CDK

Utilice las pruebas de AWS CDK para garantizar que no se eliminen recursos vitales y que las conexiones de recursos significativas permanezcan intactas.

Estas pruebas se realizan en tiempo de sintetizador, por lo que no hay posibilidad de implementar una versión rota.

Vea ejemplos de pruebas de infraestructura en mi plantilla CDK aquí .

Las pruebas verifican en tiempo de síntesis, antes de la implementación, que el recurso API GW existe.


Vea más ejemplos aquí .


Los valores predeterminados de seguridad no son suficientes

Intente siempre tener permisos y roles con el mínimo de privilegios. Cada AWS Lambda debe tener su propio rol con su subconjunto mínimo de permisos.

Existen muchas pautas de seguridad para distintos recursos. A veces, se reflejan en los valores predeterminados de AWS CDK, como el bloqueo del acceso público por parte de S3 de forma predeterminada. Sin embargo, a veces no es así.

De ti depende tener siempre presente la seguridad:

¿Este recurso debería residir en una VPC? ¿Debería poner la autorización de IAM de esta ruta de API Gateway? ¿Quizás convertirla en una API Gateway privada?

Afortunadamente, existen herramientas que te pueden ayudar a ocultar tus huellas. Deberías utilizar herramientas como CFN Nag y CDK-nag.


Consulte las pruebas nag de CDK que implementé en mi proyecto de plantilla de CDK aquí .

Las comprobaciones de errores del CDK se agregan a la pila y se ejecutan durante la implementación. Cualquier posible violación de seguridad provocará un error en la implementación.


Secretos en CDK

No guarde secretos en su código, ya sea en CDK o en el controlador AWS Lambda. Utilice cadenas cifradas de AWS SSM o AWS Secrets Manager para mantenerlos seguros.

Sin embargo, ¿cómo se pasan los secretos al CDK para que se implementen en AWS Secrets Manager?

Una opción viable es almacenar el secreto como un secreto de GitHub/Jenkins/CI e inyectarlo como un parámetro CDK o una variable de entorno durante el proceso de implementación.


Piensa siempre en la resiliencia

Evite cambiar la identificación lógica de los recursos con estado.

"Evite cambiar el ID lógico de los recursos con estado. Si cambia el ID lógico del recurso, este se reemplazará por uno nuevo en la próxima implementación. El ID lógico se deriva del ID que especifica cuando crea una instancia de la construcción..." — Prácticas recomendadas oficiales de AWS CDK.

Siempre es mejor prevenir que curar. Pueden ocurrir errores.

Se necesita una refactorización ingenua de un recurso CDK con estado (mover construcciones, cambiar el nombre del identificador lógico, etc.) para eliminar una base de datos de producción completa y los datos de los clientes.


Copias de seguridad

Cree copias de seguridad de sus recursos con estado; utilice copias de seguridad integradas, como la recuperación de un punto en el tiempo de DynamoDB, o utilice AWS Backup para crear copias de seguridad personalizadas.


Cambios de visibilidad

Puede utilizar una herramienta llamada ' Notificador CDK ' para proporcionar más visibilidad a su canalización en cada PR.

Ahora, antes de cada fusión de relaciones públicas, puede comprender visualmente los cambios en su infraestructura. Los recursos que se agregan están en verde y los que se eliminan están en rojo.

Los desarrolladores conscientes ahora pueden comprender visualmente si se avecina una catástrofe en las relaciones públicas.

https://github.com/karlderkaefer/cdk-notifier
https://github.com/karlderkaefer/cdk-notifier

¡Gracias, Roy Ben Yosef, por este valioso consejo!

 

Consejos generales de desarrollo


Leer más

Al utilizar recursos y construcciones integradas de CDK, lea la documentación. Asegúrese de comprender cada parámetro y su definición antes de comenzar a trabajar.

Estos parámetros opcionales generalmente contienen políticas de seguridad o recursos que debes definir explícitamente.


Escriba sus propias políticas de IAM

Una de las capacidades más importantes de las construcciones CDK es la gran cantidad de funciones integradas relacionadas con IAM que abstraen las políticas reales de IAM. Por ejemplo: una construcción de tabla de DynamoDB puede otorgar a un rol permisos de lectura y escritura (' grant_read_write_data ').

Si bien esto abstrae las políticas de IAM que se agregan al rol del cesionario, el efecto secundario es que...

  1. Los desarrolladores no comprenden las políticas de IAM ni lo que sus cambios otorgan a la función. Sí, pueden leer la documentación de la función, pero muchos desarrolladores no hacen el esfuerzo adicional.

  2. Algunas de estas funciones agregan permisos que su rol no requiere, lo que contradice el principio de seguridad de "mínimo privilegio".


En el ejemplo, la función define los permisos de configuración de AWS AppConfig. Es fácil de escribir y muy legible.


Conclusión: defina su propio documento de políticas de IAM de AWS. Puede definir políticas en línea o políticas de IAM JSON completas. Cuando sea posible, intente limitar la sección de recursos a un recurso específico: un depósito en particular, una tabla específica de AWS DynamoDB, etc.

Si bien es menos intuitivo, aprenderá sobre IAM y creará servicios mejor seguros, y la política se volverá más precisa y menos abstracta a largo plazo.


Vea este blog para más ejemplos.


Lea más sobre esto aquí .


Primer enfoque de la consola

Al desarrollar CFN, intente usar primero la consola, comprenda las relaciones entre los elementos y luego intente crear los objetos CFN y conectarlos.


No abstraigas demasiado

Escribir AWS CDK es escribir código. Como ingenieros, nos enorgullecemos de las abstracciones y los trucos geniales. Sin embargo, como con todo lo demás en la vida, no exageres, especialmente con el código de infraestructura. Aceptaría una pequeña duplicación de código: una definición de función de AWS Lambda con una definición y configuración claras de las variables del entorno en lugar de un método de fábrica complicado que crea varias funciones Lambda.

El código de infraestructura es fundamental, por lo que debe ser legible y estar organizado tanto como sea posible. Sin embargo, eso no significa que siempre se acepte la duplicación de código. Encuentre el equilibrio que funcione para usted entre abstracción y legibilidad.

 

Gracias a Alon Sadovsk por ayudarme con esta publicación.



bottom of page