Ir al contenido

Tus dos repositorios

Objetivo de este módulo: tener tus dos repositorios creados con tu nombre, y los entornos de GitHub listos para recibir la configuración de AWS.

La infraestructura y la aplicación cambian a ritmos distintos. La infraestructura se toca pocas veces; la aplicación, varias veces al día. Juntarlas obliga a que cada cambio de una línea de CSS pase por el pipeline que puede destruir un bucket.

Pero la razón de fondo es de permisos:

Repo de infraestructura Repo de la aplicación
Qué hace su CI fmt, validate y plan construye y despliega
Permisos en AWS solo lectura escribir en un bucket, invalidar caché
Quién aplica cambios tú, desde tu terminal el pipeline, solo

El terraform apply no corre en el pipeline, y es deliberado. Aplicar requiere poder crear buckets, distribuciones, certificados y roles de IAM. Un rol de CI con esos permisos es un objetivo muy valioso, y en un taller no aporta nada: quieres ver el plan y el apply con tus propios ojos. El pipeline de la aplicación solo escribe archivos, así que ahí sí tiene sentido que despliegue solo.

Todo el taller se parametriza con un identificador que es tuyo. Usa tu nombre o tu usuario de GitHub, en minúsculas y sin espacios.

Los ejemplos de esta guía usan p01. Reemplázalo por el tuyo en todos lados. Con ese identificador vas a terminar con:

Valor
Repo de infraestructura taskflow-p01-infra
Repo de la aplicación taskflow-p01-app
Bucket de desarrollo taskflow-p01-dev-<id-de-cuenta>
Sitio de desarrollo el dominio por defecto de CloudFront
Sitio de producción p01.workshop.v0x.site

Desarrollo no lleva subdominio propio a propósito: sin dominio no hay certificado que validar ni DNS que esperar, así que ese entorno queda funcionando en minutos. El dominio propio se trabaja una sola vez, en producción.

Se crean a partir de dos plantillas. No trabajas en las plantillas: creas tus copias.

Desde ~/protecso-workshops, con el alias taller que definiste en los prerequisitos:

Ventana de terminal
cd ~/protecso-workshops
taller bash

Y ya dentro del contenedor:

Ventana de terminal
YO=p01 # tu identificador
ORG=Protecso-SAC
gh repo create $ORG/taskflow-$YO-infra \
--template $ORG/taskflow-infra-template \
--private --clone
gh repo create $ORG/taskflow-$YO-app \
--template $ORG/taskflow-app-template \
--private --clone
ls -d taskflow-*
# taskflow-p01-app taskflow-p01-infra
exit

Los clones caen en /work, que es tu ~/protecso-workshops, así que al salir del contenedor las dos carpetas están en tu máquina.

De aquí en adelante ya no necesitas el alias: cada repositorio trae su propio Makefile.

Ventana de terminal
cd taskflow-p01-app && make help

Antes de configurar nada en GitHub, vale la pena entender qué vamos a montar, porque es la parte del taller que más se malinterpreta.

En el pipeline no vas a guardar una llave de acceso de AWS. En su lugar:

  1. El workflow le pide a GitHub un token firmado de vida corta, que describe quién es: qué repositorio, qué entorno, qué referencia de git.

  2. El workflow le presenta ese token a AWS.

  3. AWS lo verifica contra el proveedor OIDC de GitHub, que ya está creado en la cuenta del taller.

  4. Si las condiciones del rol coinciden con lo que dice el token, AWS entrega credenciales temporales. Si no, lo rechaza.

Lo que sí crea tu bootstrap son tus roles, que son solo tuyos:

Rol Quién lo puede asumir Para qué
taskflow-p01-deploy-dev tu repo de app, entorno dev subir a S3, invalidar caché
taskflow-p01-deploy-prod tu repo de app, entorno prod, solo desde un tag lo mismo, en producción
taskflow-p01-plan tu repo de infra, entorno plan solo lectura, para el plan

Un entorno de GitHub no es decorativo: su nombre viaja dentro del token OIDC. El rol de AWS confía en repo:Protecso-SAC/taskflow-p01-app:environment:prod, y esa cadena la construye GitHub a partir del nombre del repositorio y del entorno que declara el job. Si el nombre no coincide, AWS rechaza el despliegue.

  1. Ve a Settings → Environments → New environment y crea dev.

  2. Crea otro llamado prod.

  3. En prod, marca Required reviewers y agrégate. Así producción exige una aprobación humana antes de desplegar, incluso viniendo de un tag correcto.

Ventana de terminal
cd taskflow-p01-app
make shell

Dentro del contenedor:

Ventana de terminal
gh api -X PUT "repos/{owner}/{repo}/environments/dev"
gh api -X PUT "repos/{owner}/{repo}/environments/prod"
gh api "repos/{owner}/{repo}/environments" --jq '.environments[].name'
# dev
# prod

Los {owner} y {repo} los resuelve gh a partir del remoto del repositorio en el que estás, así que no hay que escribirlos.

Los revisores obligatorios se configuran desde la web: se hace una sola vez y ahí se ve mejor qué estás activando.

Un solo entorno, llamado plan. Es el que usa el CI para mostrar el plan de Terraform en los pull requests con un rol de solo lectura.

Ventana de terminal
cd taskflow-p01-infra
make shell
Ventana de terminal
gh api -X PUT "repos/{owner}/{repo}/environments/plan"

Aquí conviene entender la diferencia. GitHub distingue secrets de variables: los secrets se ocultan en los logs, las variables se ven.

Todo lo que vamos a registrar son variables, no secrets, y eso es correcto: un ARN de rol no sirve de nada sin la confianza OIDC, y el nombre de un bucket no es información sensible. Guardar como secreto algo que no lo es solo dificulta depurar cuando algo falla.

Repositorio de la aplicación, en los entornos dev y prod:

Variable De dónde sale
AWS_DEPLOY_ROLE bootstrap, salidas deploy_role_dev_arn y deploy_role_prod_arn
AWS_REGION la que usaste, por ejemplo us-east-1
AWS_S3_BUCKET entorno correspondiente, salida bucket_name
AWS_CLOUDFRONT_ID entorno correspondiente, salida distribution_id
SITE_URL entorno correspondiente, salida site_url

Repositorio de infraestructura, en el entorno plan:

Variable De dónde sale
AWS_PLAN_ROLE bootstrap, salida plan_role_arn
AWS_REGION la que usaste
TF_STATE_BUCKET bootstrap, salida state_bucket_name
PARTICIPANTE tu identificador
DEPLOY_ROLE_DEV_NAME bootstrap, salida deploy_role_dev_name

Cuando llegue el momento, registrarlas con gh es más rápido que la web. Desde el repositorio de la app, con make shell:

Ventana de terminal
gh variable set AWS_REGION --env dev --body "us-east-1"
gh variable set AWS_DEPLOY_ROLE --env dev --body "arn:aws:iam::123456789012:role/taskflow-p01-deploy-dev"
gh variable set AWS_S3_BUCKET --env dev --body "taskflow-p01-dev-123456789012"
gh variable set AWS_CLOUDFRONT_ID --env dev --body "E1234567890ABC"
gh variable set SITE_URL --env dev --body "https://d111111abcdef8.cloudfront.net"
gh variable list --env dev

El último comando es el que conviene no saltarse: si una variable quedó con el nombre mal escrito, el workflow falla con un mensaje que no dice cuál era.

En el repositorio de la aplicación, un push a main despliega a desarrollo. Vale la pena que eso pase por un pull request.

  1. Settings → Rules → Rulesets → New branch ruleset.

  2. Aplícalo a la rama por defecto.

  3. Activa Require a pull request before merging y Require status checks to pass, seleccionando el check de validación.

En el repositorio de infraestructura hazlo también: así ningún cambio de infraestructura se fusiona sin que su plan se haya visto en el pull request.

Antes de seguir deberías tener:

  • Dos repositorios creados con tu identificador, y clonados.
  • En el repo de la app: entornos dev y prod, con revisores obligatorios en prod.
  • En el repo de infra: entorno plan.
  • Claro por qué no vas a guardar ninguna llave de AWS en GitHub.

Los entornos están vacíos y así deben estar por ahora. Se llenan cuando Terraform te dé los valores.

Ventana de terminal
cd ~/protecso-workshops
taller bash
YO=p01
ORG=Protecso-SAC
gh repo create $ORG/taskflow-$YO-infra \
--template $ORG/taskflow-infra-template --private --clone
gh repo create $ORG/taskflow-$YO-app \
--template $ORG/taskflow-app-template --private --clone
exit
# entornos del repo de la app
cd taskflow-$YO-app && make shell
gh api -X PUT "repos/{owner}/{repo}/environments/dev"
gh api -X PUT "repos/{owner}/{repo}/environments/prod"
exit
# entorno del repo de infraestructura
cd ../taskflow-$YO-infra && make shell
gh api -X PUT "repos/{owner}/{repo}/environments/plan"
exit

Falta activar Required reviewers en el entorno prod desde la web, y proteger la rama principal de los dos repositorios.

Ahora sí, a construir la aplicación.