AWS SSO + Terraform: seguridad sin claves estáticas
Migrar desde credenciales IAM compartidas a AWS SSO (ahora IAM Identity Center) en Terraform elimina los riesgos de seguridad que vienen con claves estáticas almacenadas en secrets. El cambio permite auditoría individual, rotación automática de credenciales temporales y compatibilidad nativa con multi-cuenta, tanto en desarrollo local como en CI/CD con GitHub Actions o GitLab.
En 30 segundos
- Cambiar de usuario IAM compartido a SSO elimina la falta de accountability en CloudTrail (hoy muestra solo “deployment user”, mañana muestra quién realmente fue)
- AWS SSO genera credenciales temporales que expiran automáticamente (por defecto cada 12 horas), sin necesidad de rotación manual
- En CI/CD, usá OIDC (OpenID Connect) con GitHub Actions para obtener tokens temporales sin almacenar secrets estáticos
- Terraform asume roles multi-cuenta de forma nativa con
assume_role_arn, reemplazando el modelo antiguo de un usuario compartido - La migración toma ~1-2 horas por setup (configuración SSO + permisos + providers + workflows), sin downtime
Qué es AWS SSO y por qué Terraform lo necesita
AWS SSO, rebrandizado en 2022 como IAM Identity Center, es el gestor centralizado de identidades y acceso de Amazon. En lugar de crear usuarios IAM individuales con access keys estáticas, configurás un único directorio de usuarios (en AWS o sincronizado desde tu AD corporativo) que pueden asumir roles específicos en cada cuenta.
Para Terraform, esto significa que vos —el ingeniero— autenticás una sola vez contra SSO, obtenés credenciales temporales, y Terraform las usa para interactuar con AWS sin que nunca una clave estática toque un secrets manager, un .env, o un commit accidental en git.
El problema: credenciales compartidas en Terraform
Ponele que tu equipo tiene un setup clásico multi-cuenta: una cuenta shared (donde vive el S3 backend de Terraform, DynamoDB locks, módulos), una dev, una production. Hoy día, tenés un usuario IAM llamado “terraform-deployer” (o directamente “terraform-shared”, depende) con un access key guardado en los secrets de GitHub.
El usuario tiene permiso de asumir un rol en dev y otro en prod. Cuando GitHub Actions corre terraform apply, usa ese access key estático para autenticarse. El problema:
- No hay accountability. CloudTrail muestra que “terraform-deployer” hizo el cambio, pero no quién lo disparó. ¿Fue María desde una rama feature? ¿Fue García desde el merge a main? No sabés.
- Una fuga = compromiso total. Si alguien filtra o commits accidentalmente el access key, tiene acceso permanente a todas las cuentas hasta que rotes la clave. Y rotar significa actualizar secrets en GitHub, en local, en todos lados.
- Compliance no te deja. HIPAA, PCI DSS, SOC 2 exigen trazabilidad individual. Una clave compartida automáticamente falla auditoría.
- Credenciales que nunca mueren. El access key sigue siendo válido hasta que lo revokes explícitamente. Si se filtra y no te enteras, está activa.
Dicho esto, el setup funciona. Muchas compañías lo usan. Pero cuando algo se rompe, o cuando Security llega con un audit, es dolor de cabeza.
Por qué las claves estáticas son un problema de seguridad real
No es que “podrían ser” un problema. Lo son. Acá van los detalles que importan:
- Imposible revocar por usuario. Si María se va, revocas el access key y pierden acceso todos. Incluida García que sigue siendo del equipo.
- Historial mezclado. CloudTrail muestra “terraform-deployer” para todo. ¿Quién agregó ese módulo roto en prod? Ni idea. No hay forma de investigar.
- Commits accidentales. Git grep “AKIA” en el historio completo de la empresa. Vas a encontrar access keys en comments, en configfiles olvidados, en branches feature que alguien pushó sin querer.
- Rotación manual = error humano. Cada 90 días (si tu política es estricta) generás una clave nueva, actualizás GitHub secrets, avisás al equipo, esperas a que todos actualicen local. Alguien se olvida. Ahora tenés dos claves flotando.
- Compatibilidad con HIPAA / PCI / SOC 2. Si trabajás con clientes que tienen compliance requirements, la auditoría falla. Necesitas trazabilidad por usuario, rotación automática, y credenciales corta vida. Las claves estáticas fallan las tres.
La realidad es que si usás claves compartidas, estás diciendo “confío en que nadie commitea un secret, confío en que nadie deja acceso abierto cuando se va, confío en que nadie usa la clave en un lado que no debería”. Eso es fe, no seguridad.
Introducción a AWS SSO e IAM Identity Center
AWS rebrandizó SSO a IAM Identity Center en 2022. Técnicamente el producto es el mismo, pero la UI, features, y documentación mejoraron. Si tu AWS Organization está en una cuenta principal (management account), configurás un único directorio de usuarios en Identity Center.
Cada usuario tiene credenciales que nunca toca. En vez de eso, usá un browser o CLI para autenticarse contra SSO, generás una sesión temporal, y obtenés credenciales que expiran (por defecto entre 1 y 12 horas, vos elegís). En ejecutar agentes sin almacenar credenciales profundizamos sobre esto.
Para multi-cuenta: configurás “Permission Sets” — básicamente templates de IAM policies que asignás a usuarios en cuentas específicas. Un usuario puede tener admin en dev pero reader en prod. Y lo mejor: cada acción que ese usuario hace en una cuenta asumiendo el rol de SSO aparece en CloudTrail con su nombre real, no un usuario compartido.
La diferencia con el setup anterior:
| Aspecto | IAM estático (hoy) | AWS SSO (propuesto) |
|---|---|---|
| Credenciales | Access key + secret key permanentes | Temporales que expiran automáticamente (1-12h) |
| Rotación | Manual cada 90 días | Automática sin intervención |
| Accountability | CloudTrail muestra “terraform-deployer” | CloudTrail muestra el usuario real (ej: ariel.blanco) |
| Revocar acceso | Generar clave nueva, actualizar todos los places | Eliminar usuario de Permission Set, listo |
| Multi-cuenta | Usuario asume roles via AssumeRole | Permission Sets definen qué roles asume el usuario en cada cuenta |
| CI/CD sin secrets | Almacenar access key en GitHub secrets | OIDC: GitHub obtiene token, lo intercambia por credenciales sin guardar secrets |
| Compliance (HIPAA/PCI) | Falla auditoría | Pasa auditoría: trazabilidad + rotación automática |

Configurar AWS SSO con Terraform localmente
Primero, un asueto: si ya tenés SSO configurado en tu AWS Organization, saltá este paso. Si no, necesitás:
1. Habilitá Identity Center en tu account management. Abrí AWS Console → Identity Center → Enable (toma ~10 minutos).
2. Creá tu usuario: Identity Center → Users → Add user. Podés sincronizar desde tu AD corporativo también si tenés.
3. Creá Permission Sets: vos definis qué permisos tiene el usuario en cada cuenta. Ejemplo: “Terraform-Admin-Dev” (todos los permisos en dev), “Terraform-Readonly-Prod” (solo read en prod).
4. Asignás el usuario a las cuentas con los Permission Sets. Ojo: no estás asignando un usuario a una cuenta. Estás asignando usuario + permission set a cuenta + rol.
Ahora, en local. Abrís terminal y hacés:
aws configure sso
Te pregunta por:
SSO session name: inventá uno, ej “dev” o “prod” (lo usás después en comandos)SSO start URL: sacá de Identity Center dashboard, algo comohttps://d-xxxxxxxx.awsapps.com/startSSO region: donde está tu Identity Center, ejus-east-1SSO registration scopes: dejá default
Te abre un browser, loguéas con tu usuario SSO, le das permisos a la CLI. Listo.
Ahora tu ~/.aws/config tiene algo así:
[sso-session dev] sso_start_url = https://d-xxxxxxxx.awsapps.com/start sso_region = us-east-1 sso_registration_scopes = sso:account:access [profile development] sso_session = dev sso_account_id = 111111111111 sso_role_name = Terraform-Admin-Dev region = us-east-1 Ya lo cubrimos antes en proteger credenciales en tus pipelines.
Y en Terraform, especificás el profile:
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { profile = "development" region = var.aws_region assume_role { role_arn = "arn:aws:iam::111111111111:role/Terraform-Admin-Dev" } }
Cuando corres terraform plan, Terraform ve que necesita credenciales, revisa tu profile, nota que estás en SSO, genera un token temporal (o lo re-usa si está vigente), y usa eso para hablar con AWS. Sin ni una clave estática.
Error común acá: si tu config tiene Caso real (del artículo original en dev.to): un equipo con tres cuentas AWS. Shared account (state, locks, módulos), dev, prod. Hoy tienen un usuario "terraform-deployer" que asume roles en dev y prod desde la shared account. El plan de migración: El tiempo de downtime es cero. Hoy coexisten ambos: algunos developers usan SSO, otros siguen con claves estáticas. Cuando estés seguro, apagas las viejas. Acá viene lo complicado, porque CI/CD no tiene navegador. No podés hacer Opción 1 (simple, pero no ideal): almacenar las credenciales de SSO generadas localmente en GitHub secrets. Funciona, pero son temporales y expiran. Tedioso. Cubrimos ese tema en detalle en herramientas modernas de automatización. Opción 2 (profesional): OIDC con GitHub Actions. GitHub genera un JWT (token), se lo pasa a AWS, AWS verifica que es legítimo (sin almacenar secrets), y devuelve credenciales temporales. Cómo configurar OIDC: Ejemplo de workflow: Sin un solo secret almacenado en GitHub. GitHub genera el JWT, lo verifica AWS, y listo. Si el token expira o algo falla, GitHub simplemente rechaza el request. No hay credenciales flotando. Error 1: Mantener credenciales estáticas activas "por si acaso". Creás los users en SSO, configurás todo bonito, pero dejas el access key del usuario "terraform-deployer" ahí "por si algo falla". Obvio: algo va a fallar. Un workflow de back a claves estáticas, algunos developers siguen usando clave, y ya tenés dos sistemas conviviendo. Compliance falla. Solución: cuando migrés, desactivá el access key inmediatamente (no lo deletees aún, en caso de rollback urgente, pero desactivá). Probá todo en staging primero, luego mové a prod. Error 2: Confundir sso vs sso_session en ~/.aws/config. Antiguo (v1 de AWS CLI): Nuevo (v2+): Si mezclás formatos, Terraform se confunde. Borrá Error 3: Las credenciales de SSO expiran en CI/CD. Almacenaste las credenciales temporales en un secret de GitHub. Funciona 1 semana, luego expiran. Workflows fallan sin contexto claro. Solución: no almacenes credenciales temporales. Usá OIDC (arriba) o, si no podés, regenerá los secrets semanales (no scalea). Error 4: Asignar permisos demasiado amplios a los roles SSO. Si el role de Terraform en dev tiene permisos de borrar DynamoDB, CloudTrail, o cambiar IAM, y alguien roba tu sesión SSO (ej: una XSS que captura el token), pueden hacer daño. Principio de mínimo privilegio: Terraform en dev solo puede crear/editar/destruir los recursos que dev realmente tiene (EC2, RDS, S3 data buckets). Excluí IAM, KMS, CloudTrail, Secret Manager, a menos que específicamente lo necesites. Error 5: No revocar claves viejas inmediatamente. Desactivaste el access key del usuario "terraform-deployer", pero no lo borraste. Tres meses después, alguien que se fue sigue teniendo el repo clonado con esa clave en .git/config. La revisa, la usa en otra compañía. Solución: cuando desactivés, programá un recordatorio para borrar en 30 días. Después, antes de 30 días, verificá que nada la usa (logs de acceso en CloudTrail). Ejecutá No hay trazabilidad (CloudTrail muestra un usuario genérico, no quién realmente hizo el cambio), rotación manual que falla (alguien se olvida de actualizar), imposibilidad de revocar acceso individual, y problemas con compliance (HIPAA, PCI, SOC 2 requieren auditoría por usuario). Si la clave se filtra, compromete todas las cuentas hasta que la rotas. Habilitá Identity Center, creá Permission Sets (admin en dev, readonly en prod), asignales a usuarios en cada cuenta, creá roles con trust policy OIDC en cada cuenta, actualizá tus providers de Terraform, mové CI/CD a OIDC (sin secrets), y luego desactivá/eliminá las claves viejas. Configurá OIDC entre GitHub y AWS, creá un role con trust policy que verifique los JWTs de GitHub, y usá Son el mismo producto. AWS rebrandizó SSO a IAM Identity Center en 2022 para reflejar que es un gestor de identidades completo, no solo SSO. Para Terraform, funcionan idéntico: el nombre técnico en Migrar desde credenciales IAM compartidas a AWS SSO en Terraform no es opcional si querés escalabilidad, seguridad, y auditoría seria. La realidad de hoy es que una clave compartida expone el equipo a liability que aumenta con cada hire, cada salida, cada audit. El setup de SSO + OIDC toma ~1-2 horas. No hay downtime. Terraform soporta SSO nativamente. GitHub Actions soporta OIDC. AWS compliance mejora automáticamente. Si trabajás en infraestructura web (hosting, servidores, multi-region), ya sabés que separar entornos es crítico. SSO fuerza esa separación a nivel de credenciales. María en dev no puede tocar prod ni por error, porque su sesión SSO solo le asume el rol dev. Lo que hacer ahora: habilitá Identity Center si no lo tenés. Creá Permission Sets. Migrá uno o dos developers a SSO (local). Ajustá. Luego GitHub Actions con OIDC. Finalmente, eliminá las claves viejas.sso_session en el profile, pero Terraform sigue pidiendo credenciales, check que tenés aws-cli/v2. La v1 no soporta sso_sessionMigración en arquitectura multi-cuenta
AWS SSO con CI/CD: GitHub Actions sin secrets estáticos
aws configure sso en un workflow.https://token.actions.githubusercontent.com, Audience: sts.amazonaws.com.aws-actions/configure-aws-credentials con role-to-assume.name: Terraform Apply on: push: branches: [main] jobs: terraform: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v4 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::111111111111:role/github-actions-terraform aws-region: us-east-1 - name: Terraform init run: terraform init - name: Terraform apply run: terraform apply -auto-approveErrores comunes en la migración
[profile dev] sso_account_id = 111111111111 sso_role_name = Admin sso_region = us-east-1 sso_start_url = https://d-xxxxxxxx.awsapps.com/start[sso-session dev] sso_start_url = https://d-xxxxxxxx.awsapps.com/start sso_region = us-east-1 [profile development] sso_session = dev sso_account_id = 111111111111 sso_role_name = Admin~/.aws/sso (caché de sesiones) y rehacé la config desde cero con aws configure sso. Esto se conecta con lo que analizamos en elegir tu plataforma de CI/CD.Preguntas Frecuentes
¿Cómo configuro Terraform para usar AWS SSO en lugar de claves IAM?
aws configure sso en terminal (proporciona SSO URL, región, nombre de sesión). Luego, en tu provider de Terraform, usá profile = "profile-name" y assume_role { role_arn = "..." }. Terraform automáticamente genera credenciales temporales cuando las necesita.¿Cuáles son los riesgos de usar credenciales compartidas en Terraform?
¿Cómo elimino claves de acceso compartidas y migro a SSO en multi-cuenta?
¿Cómo configuro GitHub Actions con Terraform y AWS SSO de forma segura?
aws-actions/configure-aws-credentials@v4 con role-to-assume. Sin almacenar secrets en GitHub, sin credenciales estáticas.¿Qué diferencia hay entre AWS SSO e IAM Identity Center para Terraform?
~/.aws/config y permisos IAM es el mismo.Conclusión
Fuentes






