spsmexico / aws_sam_github_quickstart_template

Repositorio base para proyectos SAM con CI/CD en Github Actions
2 stars 1 forks source link

Cookiecutter Github SAM API

Este proyecto es una plantilla que permite generar un proyecto "serverless" básico, que sirva como punto inicial a proyectos pequeños de un solo repositorio.

Si requieres crear un proyecto más complejo: multiples repositorios, más de 3 desarrolladores o la plantilla ya tiene demasidadas lambdas contacta al equipo de CI/CD.

Diagrama:

API Diagram

Tipo: API

Descripción: Esta API le permite a un zoológico llevar el control de sus animales.

Si quieres pulir tus habilidades en AWS puedes contribuir agregando más funcionalidades.

Recuperación de desastres:

Lenguaje: Python 3.9

Dependencias:

Servicios:

Herramientas:

Crear proyecto: Cookiecutter


Índice

  1. AWS y Serverless
  2. Github y Github Actions
  3. Cookiecutter y Cruft
  4. Contribuciones

AWS y Serverless

AWS tiene varios servicios administrados que se cobran por uso, los más comunes: colas de mensajes, bus de eventos, administración de APIs, orquestación de servicios y envío de notificaciones. No es necesario instalar un producto en un servidor y mantenerlo actualizado, AWS se encarga de estas tareas y así nos concentramos en elegir la mejor herramienta para nuestro caso de uso.

También permite ejecutar código sin necesidad de un servidor dedicado: al recibir un evento que cumple ciertas condiciones AWS crea una instancia que ejecuta nuestro código, según la demanda puede crear más instancias. El cobro es por el tiempo que duró la ejecución del código y el número de instancias creadas.

Se pueden diseñar soluciones completas utilizando estas herramientas y a este tipo de aplicaciones se les conoce como "serverless" (sin servidor).

https://aws.amazon.com/serverless/

CloudFormation

Es posible habilitar y configurar todos estos servicios de distintas maneras:

Todas son útiles en distintos escenarios pero AWS ha creado otro servicio que permite tener estas definiciones en archivos de texto (YAML o JSON) que pueden ser agregados a un repositorio de código como este y utilizarlo para crear y modificar recursos en AWS. De esta manera se puede tener una trazabilidad sobre los cambios que se han realizado en un sistema, colaborar y realizar modificaciones modificando esta definición (infraestructura como código).

Crear stack ¿Cómo funciona CloudFormation?: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html

SAM

SAM template specification

Las plantillas de CloudFormation pueden crecer rápidamente y definir todos los recursos de una aplicación puede ser una tarea repetitiva y tardada, para solucionar esto AWS ha creado un framework que permite definir la mayoría de recursos de una aplicación "serverless" de una forma simple y con menos líneas.

SAM a Cloudformation Especificación de plantilas SAM: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html

Estas definiciones cortas soportan la mayoría de servicios utilizados en una aplicación "serverless" como:

SAM command line interface

SAM también ofrece un CLI que permite inicializar proyectos basados en plantillas, construir y desplegar una plantilla de SAM, crear eventos de pruebas, ejecutar localmente el proyecto y obtener logs los componentes luego de desplegados en AWS.

SAM CLI Inciando con el CLI de SAM: https://www.sqlshack.com/getting-started-with-the-aws-sam-cli/

sam init

Usando Docker (No requiere que tengas Python instalado)

sam build --use-container

Usando Docker y una imagen en especifico (No requiere que tengas Python instalado)

sam build --use-container --build-image public.ecr.aws/sam/build-python3.8:1.32.0

Si necesitas ver un ejemplo de la estructura del evento que recibe tu lambda puede utilizar estos comandos.

sam local generate-event apigateway aws-proxy --method GET --path document --body "{"test": "1", "tests2": "2"}"

Para visualizar la lista de servicios de los que se pueden generar eventos favor de visitar: sam local generate-event - AWS Serverless Application Model

sam local start-api

Si necesitas validar el funcionamiento de tu lambda puede pasarle un evento en formato json si necesidad de desplegar. (Requiere Docker instalado)

sam local invoke -e events/event.json

Para mayor información de comandos de CLI de SAM: AWS SAM CLI command reference - AWS Serverless Application Model

Cursos

Si quieres aprender a crear aplicaciones con herramientas "serverless" de AWS puedes tomar alguno de estos cursos (en negritas están los recomendados):

AWS IDE Toolkits

AWS ofrece extensiones para distintos IDEs, los relevantes para este repositorio son:

Utilizar alguna de estas extensiones en tu IDE favorito te facilitará el desarrollo de aplicaciones SAM.

Referencias

Estas referencias pueden ser útiles cuando estás desarrollando una aplicación con SAM:

Github y Github Actions

Github inicio como una plataforma para subir repositorios de código basados en Git, con el tiempo ha ido agregando más funcionalidades al punto de volverse una plataforma para administrar todo el ciclo de vida de una aplicación:

Ramas (Explicación de trunk based development)

Todo repositorio de código debe tener definidas algunas reglas para trabajar y colaborar. Trunk base development es la estrategia que mejor nos ha funcionado pues reduce la cantidad de conflicto al reducir la cantidad de "merges" o "pull requests":

Trunk based development Trunk based development: https://trunkbaseddevelopment.com/

main

La rama main es la rama principal (trunk en el diagrama) todo el código se sube directamente ahí, si se agrego un nuevo desarrollador que aún no está familiarizado con el código se puede solicitar que introduzca sus cambios mediante "pull request" para que sean revisados por su mentor o guía en el proyecto, eventualmente podrá introducir cambios directamente en main.

releases/x.x.x

Una vez que se libera el código a producción se genera una rama de release, estas ramas están protegidas (ya no se pueden modificar) y deben utilizar versionado semántico para indicar la versión.

Ejemplo: releases/1.0.0

fix/x.x.x

Recuerda que las ramas releases/x.x.x están protegidas.

En caso de que ocurra un bug en producción, hay dos posibles caminos:

  1. Si en main no se han introducido nuevos cambios al código, el fix se deberá realizar directamente en main y al generar un nuevo release se incrementará la versión parche.
    • Ejemplo: 1.0.0 -> 1.0.1
  2. Si el código en main ya cambio porque se está trabajando en una nueva funcionalidad, este código aún no está listo para enviarse a producción así que no podemos realizar el fix sobre main. En estos casos se crea una rama fix con la versión de parche incrementada a partir de la rama release que queremos corregir. Una vez arreglado el código se despliega en producción y se crea una nueva rama releases.
    • Ejemplo: releases/1.0.0 -> fix/releases/1.0.1 -> releases/1.0.1

Github Workflows (Como los workflows en el repo permiten seguir la estrategia de ramas y desplegar con algunos clics)

workflows

Workflow reusables (Como los workflows hacen llamados a los workflows reusables para completar tareas y liga a la administración de workflows)

Agregar nota: Si el proyecto crece y se crean multiples repositorios, se debe crear un repo independiente en el que puedan guardarse los workflows reusables y otras utilerías

Referencias

Cookiecutter y Cruft

Crea un proyecto (Crear proyecto a partir de plantilla de cookiecutter y agregar los número de cuenta de los ambientes como secretos en Github)

Prerequisitos:

Contar con las siguientes herramientas instaladas:

  graph TD;

      AWS-->1_IAM;
      1_IAM-->crear_identity_provider;
      crear_identity_provider-->crear_rol_despliegue;
      crear_rol_despliegue-->agregar_politicas_requeridas;
      agregar_politicas_requeridas-->agregar_tags_del_proyecto;
      agregar_tags_del_proyecto-->copiar_account_id;
      copiar_account_id-->agregar_account_id;

      AWS-->2_KMS;
      2_KMS-->crear_llave_simetrica_multiregion_SSM;
      crear_llave_simetrica_multiregion_SSM-->copiar_ARN;
      2_KMS-->crear_llave_simetrica_multiregion_DynamoDB;
      crear_llave_simetrica_multiregion_DynamoDB-->copiar_ARN;
      crear_llave_simetrica_multiregion_SSM-->configurar_regionalidad_en_region_dr;
      crear_llave_simetrica_multiregion_DynamoDB-->configurar_regionalidad_en_region_dr;
      configurar_regionalidad_en_region_dr-->copiar_ARN;
      copiar_ARN-->ingresarlos_al_inicializar_cookiecutter;    

      3_GitHub-->crear_repositorio;
      crear_repositorio-->crear_ambientes;
      crear_ambientes-->configurar_secretos_ambiente;
      agregar_account_id-->configurar_secretos_ambiente;

- Los pasos 1 y 2 deberán ser realizados en las cuentas AWS de cada ambiente (develop, prod)

Pasos


1. Generación de rol de despliegue \ 2. Creación de llaves KMS \ 3. Creación de repositorio y ambientes \ 4. Inicialización del proyecto \ 5. Post-inicialización del proyecto \

Generación de rol de despliegue


Para poder realizar los despliegues a una cuenta AWS, es importante generar un rol en lugar de un usuario en las cuentas AWS destino. Esto para ejercer mejores prácticas de seguridad en AWS.

Nota: este paso debe realizarse en las cuentas de AWS de todos los ambientes.

Creando identity provider:

Para crear un identity provider es necesario ingresar a IAM daremos clic en la opción de la barra lateral izquierda "identity providers" y daremos clic en el botón azul de "Add provider".

En provider URL ingresaremos: https://token.actions.githubusercontent.com En "Audience" ingresaremos: sts.amazonaws.com

Posteriormente daremos clic en "get thumbprint"

y para terminar daremos clic en "Add provider"

Creando rol

En esta sección se sugiere nombrar el rol con identificador-del-proyecto-github-actions-role (sin agregarle el sufijo de ambiente. Para crear el rol, nos iremos en la sección de IAM > Roles y daremos clic en "Create role", en el tipo de entidad confiable daremos clic en "Web identity" y seleccionaremos el identity provider y audience que acabamos de crear en el paso anterior y daremos clic en "Next":

Agregar las políticas necesarias:

En este punto es indispensable que el rol que desplegará, cuente con acceso a Cloudformation y los servicios que estará desplegando:

Permisos sugeridos:

Estos permisos se sugieren habilitar para poder realizar su despliegue. Salvo que haya alguno que sobre o alguno que falte deberá ser agregado/eliminado:

La siguiente política puede insertarse directamente al rol para poder desplegar:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:UntagRole",
                "iam:TagRole",
                "iam:UpdateRoleDescription",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:AttachRolePolicy",
                "iam:PutRolePolicy",
                "iam:TagPolicy",
                "iam:CreatePolicy",
                "iam:DetachRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:UntagPolicy",
                "iam:UpdateRole"
            ],
            "Resource": "*"
        }
    ]
}

Agregar tag relacionado al proyecto:

Por acá estaremos agregando el tag "Proyecto" con el nombre del proyecto para el que se utilizará este rol:

Una vez que el rol haya sido creado, abriremos el rol que creamos y daremos clic en "Edit trust policy":

En este bloque agregaremos lo siguiente sustituyendo los siguientes valores:

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "Federated": "arn:aws:iam::<NUMERO_CUENTA_AWS>:oidc-provider/token.actions.githubusercontent.com"
           },
           "Action": "sts:AssumeRoleWithWebIdentity",
           "Condition": {
               "StringEquals": {
                   "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
               },
               "StringLike": {
                   "token.actions.githubusercontent.com:sub": "repo:<ORGANIZACION_GITHUB>/<NOMBRE_REPOSITORIO>:*"
               }
           }
       }
   ]
}

NUMERO_CUENTA_AWS = Número de cuenta de la cuenta AWS donde se estará desplegando, en este caso podemos obtenerla en la parte superior derecha de la consola AWS.

ORGANIZACION_GITHUB = Organización o usuario de GitHub a la que pertenece el repositorio.

NOMBRE_REPOSITORIO = Nombre del repositorio.

Por último daremos clic en "Update Policy".

Recursos: https://www.automat-it.com/post/using-github-actions-with-aws-iam-roles

Creación de llaves KMS


Como prerequisito es importante crear 2 llaves KMS simétricas "multiregión", una para SSM y otra para DynamoDB. La región de creación de la llave será la región principal. Y la secundaría será la destinada para DR.

El nombrado debe seguir el siguiente estándar: identificador_del_proyecto-servicio_de_aws-ambiente

Ejemplo de llave SSM:

Identificador = proyectonuevo\ Servicio = ssm\ Ambiente = dev

Nombre de la nueva llave a crear: proyectonuevo-ssm-dev

Ejemplo de llave DynamoDB:

Identificador = proyectonuevo\ Servicio = dynamo\ Ambiente = dev

Nombre de la nueva llave a crear: proyectonuevo-dynamodb-dev

NOTA: Este proceso debe realizarse en ambas cuentas (desarrollo y producción). Cuando inicialicemos el proyecto con cookiecutter nos solicitará los ARN's de las llaves llaves. Por lo que es importante tenerlas a la mano cuando se inicialice el proyecto.

Creación de repositorio


Se debe crear un repositorio nuevo. El repositorio debe ser creado vacío, para que se pueda inicializar correctamente el proyecto.

Creación de ambientes

Es necesario crear 2 ambientes en el repositorio para poder inicializar el proyecto, develop y production

Ambiente develop:

Para ello nos dirigiremos a "Settings" > "Environments" > "New environment":

Agregaremos el ambiente "develop" y daremos clic en "Configure environment":

Posteriormente, daremos clic em "Save protection rules".:

Ambiente production:

Sería el mismo paso que seguimos en el ambiente develop:

Esta vez se nombrará como production:

Por último, agregaremos a los equipos o personas que pueden aprobar despliegues en este ambiente:

Configurar secretos por ambiente

Nota: Los nombres de los secretos a mostrar son los valores default, se recomienda que permanezcan así. Pero en caso de ser necesario agregarles un sufijo o utilizar otro nombrado al inicializar el proyecto se deberán especificar.

Una vez creados los ambientes:

Seleccionaremos el ambiente develop, y en la parte inferior daremos clic en "add secret":

Agregaremos los números de cuenta en los secretos del repositorio de GitHub. Esto será para ambos ambientes:

Número de cuenta AWS del ambiente develop:

Acto seguido procederemos a dirigirnos al ambiente production:

Número de cuenta AWS del ambiente production:

Inicializar proyecto

Una vez concluidos los pasos anteriores podemos proseguir a inicializar el proyecto, nos moveremos hacia la carpeta donde se alojará el repositorio y ejecutaremos el siguiente comando:

cookiecutter https://github.com/spsdevops/aws_sam_github_quickstart_template

Ingresaremos los valores que nos pide la plantilla. Algunas opciones cuentan con valores default.

A continuación se describen cada una de las opciones:

nombre_repo: Nombre del repositorio de GitHub.

org_or_user_github: Usuario de GitHub u Organización a la que pertenece el repositorio.

cfn_stack: Nombre del stack en AWS.

Es importante que no incluya el identificador o sufijo del proyecto.

project: Identificador del proyecto.

Pueden ser las iniciales de la empresa o nombre del proyecto. Se utilizará como sufijo para los recursos del proyecto.

region_primaria: Región primaria en la que se desplegarán los recursos del proyecto.

Ejemplo: us-east-1

region_secundaria: Región secundaria en la que se desplegarán los recursos del proyecto.

Ejemplo: us-west-2

DEV_ARN_SSM_KMS: Llave multiregion para Parameter Store. DEV

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de Desarrollo.

DEV_ARN_DYNAMODB_KMS: Llave multiregion para DynamoDB. DEV

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de Desarrollo.

DEV_ARN_SSM_KMS_DR: Llave multiregion para Parameter Store. DR. DEV

Es una de las llaves que creamos para la región DR en Creación de llaves KMS para el ambiente de Desarrollo.

DEV_ARN_DYNAMODB_KMS_DR: Llave multiregion para DynamoDB. DR. DEV

Es una de las llaves que creamos para la región DR en Creación de llaves KMS para el ambiente de Desarrollo.

PRE_ARN_SSM_KMS: Llave multiregion para Parameter Store. PRE/QA

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de QA/Preproducción.

PRE_ARN_SSM_KMS_DR: Llave multiregion para Parameter Store. PRE/QA

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de QA/Preproducción.

PROD_ARN_SSM_KMS: Llave multiregion para Parameter Store. PROD

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de Producción.

PROD_ARN_DYNAMODB_KMS: Llave multiregion para DynamoDB. PROD

Es una de las llaves que creamos para la región principal en Creación de llaves KMS para el ambiente de Producción.

PROD_ARN_SSM_KMS_DR: Llave multiregion para Parameter Store. DR. PROD

Es una de las llaves que creamos para la región DR en Creación de llaves KMS para el ambiente de Producción.

PROD_ARN_DYNAMODB_KMS_DR: Llave multiregion para DynamoDB. DR. PROD

Es una de las llaves que creamos para la región DR en Creación de llaves KMS para el ambiente de Producción.

sam_container: public.ecr.aws/sam/build-python3.8:1.32.0.

Es el contenedor que construye la aplicación, en esta caso está como default uno de Python. Pero de ser requerido usar una lambda de otro lenguaje se puede especificar en esta opción.

sam_bucket: Nombre del bucket para SAM.

Es el bucket que necesita SAM para realizar los despliegues.

DEV_secret_aws_account_id: DEV_AWS_ACCOUNT_ID.

Aquí se deja por default este valor, salvo se haya especificado uno diferente en la configuración de secretos por ambiente

PRE_secret_aws_account_id: PRE_AWS_ACCOUNT_ID.

Aquí se deja por default este valor, salvo se haya especificado uno diferente en la configuración de secretos por ambiente

PROD_secret_aws_account_id: PROD_AWS_ACCOUNT_ID.

Aquí se deja por default este valor, salvo se haya especificado uno diferente en la configuración de secretos por ambiente

DEV_ROLE_DEPLOY: Nombre del rol de despliegue en el ambiente de desarrollo.

Es el nombre del rol que creamos en la sección de creando rol para el ambiente de desarrollo.

PRE_ROLE_DEPLOY: Nombre del rol de despliegue en el ambiente de QA/preproducción.

Es el nombre del rol que creamos en la sección de creando rol para el ambiente de QA/preproducción.

PROD_ROLE_DEPLOY: Nombre del rol de despliegue en el ambiente de producción.

Es el nombre del rol que creamos en la sección de creando rol para el ambiente de producción.

Post inicialización del proyecto

Al terminar de generar el proyecto, por medio de un script se vincula el repo generado con el repo remoto que creamos en GitHub. Por lo tanto ya es posible comenzar a trabajar en él. Pero antes, se recomienda agregar alguna modificación en el archivo template.yaml para desplegar el proyecto Hello world por primera vez y evitar que se tengan problemas relacionados con un primer despliegue fallido.

Contribuciones

Lista de deseos: