# 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. Configuración aplicada (resumen de esta sesión) Los siguientes recursos OIDC ya fueron configurados manualmente en la consola AWS durante abril de 2026: | Cuenta | OIDC Provider | Rol IAM | Permisos | |--------|---------------|---------|----------| | **DEV** (`668889063715`) | `api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc` | `BitbucketProyectosaccCICDRoleDev` | `AdministratorAccess` (temporal) | | **PROD** (`523761210517`) | `api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc` | `BitbucketProyectosaccCICDRoleProd` | `AdministratorAccess` (temporal) | **Audience configurada:** `sts.amazonaws.com` **Repository UUID usado en trust policies:** `{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}` > **Nota de seguridad:** `AdministratorAccess` fue adjunta solo como punto de partida para desbloquear el pipeline. En una iteración posterior debe reemplazarse por la política mínima de `docs/iam-policy-ci-cd-proyectosacc.json`. --- ## 4. Pre-requisitos Antes de empezar, asegúrate de tener: 1. **Acceso administrativo a AWS** (consola o CLI) en ambas cuentas: - DEV: `668889063715` - PROD: `523761210517` 2. **Permiso para crear** `iam:CreateOpenIDConnectProvider` y `iam:CreateRole`. 3. El **Repository UUID** de `ccsoft1/proyectosacc`: - `{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}` (incluye las llaves `{}`) - Lo encuentras en: Bitbucket > Repository settings > OpenID Connect > **Repository UUID** --- ## 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 Provider` y los `IAM Roles` manualmente o ejecutando Terraform desde su laptop con credenciales de admin. ### Opción A: Aplicar con Terraform local (recomendado) 1. Clona el repo en tu máquina: ```bash git clone https://bitbucket.org/ccsoft1/proyectosacc.git cd proyectosacc/terraform ``` 2. Verifica que `terraform/oidc-bitbucket.tf` tenga el UUID correcto: ```hcl bitbucket_repo_uuid = "{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}" ``` 3. Configura tus credenciales de admin para la cuenta **DEV**: ```bash export AWS_ACCESS_KEY_ID="AKIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_DEFAULT_REGION="mx-central-1" ``` 4. Inicializa y aplica: ```bash 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 ``` 5. Repite para la cuenta **PROD** cambiando el backend: ```bash 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**: 1. Ve a **IAM > Identity Providers > Add Provider**. 2. Selecciona **OpenID Connect**. 3. **Provider URL**: `https://api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc` 4. Haz clic en **Get thumbprint** (AWS lo obtendrá automáticamente). 5. **Audience**: `sts.amazonaws.com` 6. Guarda con el nombre sugerido: `bitbucket-pipelines-oidc` #### Paso 2: Crear el Rol IAM para DEV 1. Ve a **IAM > Roles > Create Role**. 2. Tipo de entidad confiable: **Web Identity**. 3. Selecciona el provider creado en el paso anterior. 4. **Audience**: `sts.amazonaws.com`. 5. En **Conditions**, agrega una condición personalizada (avanzado) o edita el trust policy después de crearlo. 6. Nombre del rol: `BitbucketProyectosaccCICDRoleDev` 7. Adjunta la política `AdministratorAccess` (solo como punto de partida). 8. Edita el **Trust Policy** para que quede exactamente así: ```json { "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": "{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}:*" } } } ] } ``` #### 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 ```yaml 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`: ```yaml - step: name: 03_terraform oidc: true script: - source scripts/aws-oidc-setup.sh dev - ... ``` En `proyectosacc`, los steps con OIDC son: - `03_terraform` - `05_publish` - `07_deploy` ### 5.3 Script helper `aws-oidc-setup.sh` Este script: 1. Lee `BITBUCKET_STEP_OIDC_TOKEN` (lo inyecta Bitbucket automáticamente). 2. Lo guarda en un archivo temporal. 3. Exporta `AWS_WEB_IDENTITY_TOKEN_FILE` y `AWS_ROLE_ARN`. 4. 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: ```bash echo "$BITBUCKET_STEP_OIDC_TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool ``` Deberías ver algo como: ```json { "sub": "{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}:{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`: ```bash source scripts/aws-oidc-setup.sh dev aws sts get-caller-identity ``` Debería devolver el ARN del rol asumido: ```json { "UserId": "AROA...:bot/session", "Account": "668889063715", "Arn": "arn:aws:sts::668889063715:assumed-role/BitbucketProyectosaccCICDRoleDev/bot/session" } ``` ### Prueba 3: Pipeline completo en DEV 1. Haz push a la rama `developer`. 2. Ve a Bitbucket > Pipelines. 3. Verifica que `03_terraform`, `05_publish` y `07_deploy` terminen en verde. 4. 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: ```yaml 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**: 1. Verifica que `bitbucket-pipelines.yml` tenga: ```yaml options: oidc: audiences: - sts.amazonaws.com ``` 2. Verifica que el OIDC Provider en AWS tenga `sts.amazonaws.com` en `client_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**: 1. Obtén el `sub` real del token (ver Prueba 1). 2. Ajusta el trust policy. Si usas `StringLike`, asegúrate de que el patrón termine en `:*`: ```json "StringLike": { "api.bitbucket.org/2.0/workspaces/ccsoft1/pipelines-config/identity/oidc:sub": "{REPO_UUID}:*" } ``` 3. El UUID configurado es `{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}`. Si el pipeline sigue fallando, verifica que el `sub` claim del token real coincida con este UUID. Solo en casos de emergencia 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**: 1. Confirma que `scripts/aws-oidc-setup.sh` se ejecutó antes de cualquier comando `aws` o `terraform`. 2. Verifica que `AWS_WEB_IDENTITY_TOKEN_FILE` y `AWS_ROLE_ARN` estén exportadas. 3. 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:ListBucket` en el bucket de estado - `dynamodb:GetItem`, `dynamodb:PutItem`, `dynamodb:DeleteItem` en 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](https://support.atlassian.com/bitbucket-cloud/docs/deploy-on-aws-using-bitbucket-pipelines-openid-connect/) - [AWS Docs: Creating OpenID Connect identity providers](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) - [docs/12-credenciales-aws-ci-cd.md](12-credenciales-aws-ci-cd.md) — Contexto anterior de credenciales estáticas. - [docs/iam-policy-ci-cd-proyectosacc.json](iam-policy-ci-cd-proyectosacc.json) — Política mínima de referencia. --- *Área de Tecnología y Desarrollo — CCsoft — Abril 2026*