La autenticación de GitHub Actions a GCP usa Workload Identity Federation (WIF) con OIDC. No existe ningún JSON key de service account en este repositorio ni en los secretos de GitHub.
Flujo: el job obtiene un JWT firmado por GitHub → lo intercambia por un access token de corta duración en GCP Security Token Service → usa ese token para operar en GCP. El token expira al terminar el job.
| SA | Rol | Permisos |
|---|---|---|
cicd-deployer |
Runner de CI/CD y Terraform | Deploy en Cloud Run, push a Artifact Registry, gestión de IaC |
apiflask-demo-runtime |
Runtime del servicio | Solo leer los secretos que necesita + conectarse a Cloud SQL |
El SA de runtime no puede modificar infraestructura. El SA de CI/CD no puede leer datos de producción.
attribute_condition limita el acceso al pool a los repositorios exactos declarados en Terraform. Un fork o repositorio no autorizado no puede obtener tokens aunque conozca el identificador del pool.
El binding de suplantación añade una segunda restricción: solo jobs del entorno prod pueden suplantar al SA de CI/CD.
El SA cicd-deployer tiene roles/artifactregistry.admin a nivel de proyecto porque Terraform necesita getIamPolicy para refrescar el estado de los recursos iam_member del repositorio de Artifact Registry. Este permiso no existe en roles de nivel repositorio (writer, repoAdmin).
La solución de mínimo privilegio estricto requiere separar en dos SAs: uno para Terraform (permisos amplios de gestión) y otro para el pipeline de deploy (permisos mínimos de operación). Este repositorio usa un único SA como simplificación pragmática.
DATABASE_URL,APP_SECRET_KEYyAPP_SECURITY_PASSWORD_SALTse almacenan en Secret Manager, no en variables de entorno ni en el estado de Terraform.- El estado de Terraform no contiene el valor de ningún secreto:
DATABASE_URLse referencia comosecret_key_refy la contraseña de base de datos se pasa como variable en tiempo deapply, no se escribe en el estado. - El SA de runtime tiene
roles/secretmanager.secretAccessorúnicamente sobre los tres secretos que necesita, no a nivel de proyecto.
- Cloud SQL no acepta conexiones TCP directas:
authorized_networksestá vacío. - La app se conecta a Cloud SQL exclusivamente mediante socket Unix del Cloud SQL Auth Proxy en
/cloudsql/<connection_name>. ipv4_enabled = truees un requisito del Auth Proxy para enrutar la conexión internamente, no una apertura de acceso directo. La regla de TrivyAVD-GCP-0017se suprime con comentario explicativo enmain.tf.
- Backend remoto en Google Cloud Storage con
uniform_bucket_level_access. - El SA de CI/CD tiene
roles/storage.adminúnicamente sobre el bucket de estado, no a nivel de proyecto.
Abre un issue privado o contacta al mantenedor directamente antes de publicar detalles.