- Agrega aws_iam_openid_connect_provider y roles IAM para DEV/PROD - Actualiza bitbucket-pipelines.yml para usar OIDC en steps 03, 05, 07 - Crea script helper scripts/aws-oidc-setup.sh - Agrega provider tls en terraform/provider.tf - Documenta el flujo completo en docs/14-oidc-bitbucket-aws.md Elimina la dependencia de AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY estáticos en el pipeline, permitiendo autenticación sin credenciales de larga vida via AssumeRoleWithWebIdentity. Refs: cuenta DEV 668889063715, PROD 523761210517
13 KiB
14 - Autenticación OIDC entre Bitbucket Pipelines y AWS
Guía paso a paso para eliminar Access Keys estáticas y usar OpenID Connect (OIDC) en el pipeline de
proyectosacc.
1. ¿Por qué OIDC?
En muchos equipos, los pipelines de CI/CD usan IAM Users con Access Keys de larga vida (AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY). Esto tiene varios problemas:
| Problema | Explicación |
|---|---|
| Rotación manual | Las keys deben renovarse periódicamente (cada 90 días recomendado). Si se olvida, el pipeline falla. |
| Fuga de secretos | Si las keys se filtran (logs, commits, etc.), un atacante puede usarlas desde cualquier lugar del mundo. |
| Deny de IAM | En organizaciones maduras, los administradores bloquean iam:CreateUser e iam:CreateAccessKey, haciendo imposible este camino. |
OIDC resuelve todo esto permitiendo que el pipeline de Bitbucket asuma un rol IAM temporal automáticamente, sin guardar credenciales estáticas. Cada ejecución obtiene un token JWT que AWS valida y convierte en credenciales temporales (vencen en 1 hora por defecto).
2. ¿Cómo funciona el flujo?
El proceso es como mostrar una credencial de invitado en la entrada de un edificio:
┌─────────────────┐ 1. Solicita token OIDC ┌─────────────────┐
│ Bitbucket │ ───────────────────────────────▶│ Bitbucket │
│ Pipelines │ OIDC Provider │
│ (runner) │◀────────────────────────────────│ │
└─────────────────┘ 2. Devuelve JWT firmado └─────────────────┘
│
│ 3. Presenta JWT + Role ARN
▼
┌─────────────────┐ 4. Valida JWT contra ┌─────────────────┐
│ AWS STS │ ───────────────────────────────▶│ AWS IAM │
│ (sts:AssumeRole│ OIDC Provider │
│ WithWebIdent.)│◀────────────────────────────────│ │
└─────────────────┘ 5. Confía si aud/sub OK └─────────────────┘
│
│ 6. Devuelve credenciales temporales
▼
┌─────────────────┐
│ Pipeline │ 7. Ejecuta Terraform / aws s3 / cloudfront ...
│ con acceso AWS │
└─────────────────┘
Claims importantes del JWT:
| Claim | Significado | Ejemplo |
|---|---|---|
aud |
Audience (a quién va dirigido el token) | sts.amazonaws.com |
sub |
Subject (quién solicita el token) | {REPO_UUID}:{STEP_UUID} |
iss |
Issuer (quién emitió el token) | https://api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc |
3. Pre-requisitos
Antes de empezar, asegúrate de tener:
- Acceso administrativo a AWS (consola o CLI) en ambas cuentas:
- DEV:
668889063715 - PROD:
523761210517
- DEV:
- Permiso para crear
iam:CreateOpenIDConnectProvideryiam:CreateRole. - El Repository UUID de
ccsoft1/proyectosacc. Lo encuentras en:- Bitbucket > Repository settings > OpenID Connect > Repository UUID
- Formato:
{1de489be-ce6a-42a0-a8c8-eadbf1174ac7}(incluye las llaves{})
4. Bootstrap manual: crear OIDC Provider y Roles
IMPORTANTE: El pipeline NO puede crear su propio rol OIDC porque aún no tiene credenciales. La primera vez, un administrador debe crear el
OIDC Providery losIAM Rolesmanualmente o ejecutando Terraform desde su laptop con credenciales de admin.
Opción A: Aplicar con Terraform local (recomendado)
-
Clona el repo en tu máquina:
git clone https://bitbucket.org/ccsoft1/proyectosacc.git cd proyectosacc/terraform -
Edita
terraform/oidc-bitbucket.tfy reemplaza el placeholder:bitbucket_repo_uuid = "{1de489be-ce6a-42a0-a8c8-eadbf1174ac7}" -
Configura tus credenciales de admin para la cuenta DEV:
export AWS_ACCESS_KEY_ID="AKIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_DEFAULT_REGION="mx-central-1" -
Inicializa y aplica:
terraform init -backend-config=backend.dev.hcl terraform plan -var-file=environments/dev.tfvars -target=aws_iam_openid_connect_provider.bitbucket -target=aws_iam_role.bitbucket_ci_cd terraform apply -var-file=environments/dev.tfvars -target=aws_iam_openid_connect_provider.bitbucket -target=aws_iam_role.bitbucket_ci_cd -
Repite para la cuenta PROD cambiando el backend:
terraform init -backend-config=backend.prod.hcl -reconfigure terraform plan -var-file=environments/prod.tfvars -target=aws_iam_openid_connect_provider.bitbucket -target=aws_iam_role.bitbucket_ci_cd terraform apply -var-file=environments/prod.tfvars -target=aws_iam_openid_connect_provider.bitbucket -target=aws_iam_role.bitbucket_ci_cd
Opción B: Crear desde la Consola AWS (paso a paso)
Paso 1: Crear el OIDC Provider
Repite esto en DEV y PROD:
- Ve a IAM > Identity Providers > Add Provider.
- Selecciona OpenID Connect.
- Provider URL:
https://api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc - Haz clic en Get thumbprint (AWS lo obtendrá automáticamente).
- Audience:
sts.amazonaws.com - Guarda con el nombre sugerido:
bitbucket-pipelines-oidc
Paso 2: Crear el Rol IAM para DEV
- Ve a IAM > Roles > Create Role.
- Tipo de entidad confiable: Web Identity.
- Selecciona el provider creado en el paso anterior.
- Audience:
sts.amazonaws.com. - En Conditions, agrega una condición personalizada (avanzado) o edita el trust policy después de crearlo.
- Nombre del rol:
BitbucketProyectosaccCICDRoleDev - Adjunta la política
AdministratorAccess(solo como punto de partida). - Edita el Trust Policy para que quede así:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::668889063715:oidc-provider/api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc:aud": "sts.amazonaws.com"
},
"StringLike": {
"api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc:sub": "{REPO_UUID}:*"
}
}
}
]
}
Reemplaza {REPO_UUID} por el UUID real del repositorio.
Paso 3: Crear el Rol IAM para PROD
Repite exactamente el paso 2 pero en la cuenta PROD (523761210517) y con el nombre:
BitbucketProyectosaccCICDRoleProd
El ARN del provider federado cambiará a:
arn:aws:iam::523761210517:oidc-provider/api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc
5. Configuración del pipeline
El archivo bitbucket-pipelines.yml ya fue actualizado para usar OIDC. Estos son los cambios clave:
5.1 Audience global
options:
oidc:
audiences:
- sts.amazonaws.com
Esto le dice a Bitbucket que el token OIDC incluya sts.amazonaws.com en el claim aud.
5.2 Activar OIDC en los steps
Cada step que interactúa con AWS debe tener oidc: true:
- step:
name: 03_terraform
oidc: true
script:
- source scripts/aws-oidc-setup.sh dev
- ...
En proyectosacc, los steps con OIDC son:
03_terraform05_publish07_deploy
5.3 Script helper aws-oidc-setup.sh
Este script:
- Lee
BITBUCKET_STEP_OIDC_TOKEN(lo inyecta Bitbucket automáticamente). - Lo guarda en un archivo temporal.
- Exporta
AWS_WEB_IDENTITY_TOKEN_FILEyAWS_ROLE_ARN. - AWS CLI y Terraform usan estas variables para asumir el rol automáticamente.
6. ¿Cómo probar que funciona?
Prueba 1: Verificar el token JWT
Crea un pipeline de prueba temporal o agrega este comando al inicio de un step:
echo "$BITBUCKET_STEP_OIDC_TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool
Deberías ver algo como:
{
"sub": "{1de489be-ce6a-42a0-a8c8-eadbf1174ac7}:{759de0c6-eaee-4eaa-b7a6-c507eec759a7}",
"aud": "sts.amazonaws.com",
"iss": "https://api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc",
...
}
Prueba 2: Verificar AssumeRole desde el pipeline
Agrega temporalmente esto al step 03_terraform:
source scripts/aws-oidc-setup.sh dev
aws sts get-caller-identity
Debería devolver el ARN del rol asumido:
{
"UserId": "AROA...:bot/session",
"Account": "668889063715",
"Arn": "arn:aws:sts::668889063715:assumed-role/BitbucketProyectosaccCICDRoleDev/bot/session"
}
Prueba 3: Pipeline completo en DEV
- Haz push a la rama
developer. - Ve a Bitbucket > Pipelines.
- Verifica que
03_terraform,05_publishy07_deployterminen en verde. - Si falla, revisa la sección de Troubleshooting.
7. Troubleshooting común
Error: BITBUCKET_STEP_OIDC_TOKEN no está definido
Causa: Olvidaste agregar oidc: true al step.
Solución: Verifica que los steps 03_terraform, 05_publish y 07_deploy tengan:
oidc: true
Error: An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation
Causa: El aud del token no coincide con el client_id_list del OIDC Provider.
Solución:
- Verifica que
bitbucket-pipelines.ymltenga:options: oidc: audiences: - sts.amazonaws.com - Verifica que el OIDC Provider en AWS tenga
sts.amazonaws.comenclient_id_list.
Error: AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
Causa: El trust policy del rol no coincide con el claim sub del token.
Solución:
- Obtén el
subreal del token (ver Prueba 1). - Ajusta el trust policy. Si usas
StringLike, asegúrate de que el patrón termine en:*:"StringLike": { "api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc:sub": "{REPO_UUID}:*" } - Si aún no conoces el
REPO_UUID, puedes poner"*"temporalmente solo para pruebas (menos seguro).
Error: Unable to locate credentials
Causa: AWS CLI no encuentra el token o el rol.
Solución:
- Confirma que
scripts/aws-oidc-setup.shse ejecutó antes de cualquier comandoawsoterraform. - Verifica que
AWS_WEB_IDENTITY_TOKEN_FILEyAWS_ROLE_ARNestén exportadas. - Asegúrate de usar una versión reciente de AWS CLI (
aws --version>= 2.x).
Error: terraform init falla por permisos al bucket de estado
Causa: El rol OIDC no tiene permisos para leer/escribir el bucket S3 de estado ni la tabla DynamoDB de locks.
Solución: Como usamos AdministratorAccess como punto de partida, esto no debería pasar. Si en el futuro restringes la política, asegúrate de incluir permisos sobre:
s3:GetObject,s3:PutObject,s3:ListBucketen el bucket de estadodynamodb:GetItem,dynamodb:PutItem,dynamodb:DeleteItemen la tabla de locks
8. Roadmap de hardening
Aunque AdministratorAccess hace que todo funcione inmediatamente, es una mala práctica de seguridad dejarlo así a largo plazo.
| Prioridad | Acción | Justificación |
|---|---|---|
| Alta | Reemplazar AdministratorAccess por una política custom basada en docs/iam-policy-ci-cd-proyectosacc.json. |
Mínimo privilegio. |
| Media | Restringir el sub claim al REPO_UUID exacto. |
Evita que otros repos del workspace asuman el rol. |
| Media | Separar roles: uno para Terraform (infraestructura) y otro para despliegue de aplicación (S3 + CloudFront). | Reduce el blast radius. |
| Baja | Agregar condiciones de IP en el trust policy (si el pipeline siempre corre desde rangos conocidos de Bitbucket). | Capa extra de seguridad. |
Referencias
- Deploy on AWS using Bitbucket Pipelines OpenID Connect – Atlassian
- AWS Docs: Creating OpenID Connect identity providers
- docs/12-credenciales-aws-ci-cd.md — Contexto anterior de credenciales estáticas.
- docs/iam-policy-ci-cd-proyectosacc.json — Política mínima de referencia.
Área de Tecnología y Desarrollo — CCsoft — Abril 2026