Files
proyectosacc-mirror/docs/14-oidc-bitbucket-aws.md
T

14 KiB
Raw Blame History

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:

    git clone https://bitbucket.org/ccsoft1/proyectosacc.git
    cd proyectosacc/terraform
    
  2. Verifica que terraform/oidc-bitbucket.tf tenga el UUID correcto:

    bitbucket_repo_uuid = "{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}"
    
  3. 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"
    
  4. 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
    
  5. 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:

  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í:
{
  "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

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_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:

echo "$BITBUCKET_STEP_OIDC_TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool

Deberías ver algo como:

{
  "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:

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

  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:

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:
    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 :*:
    "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


Área de Tecnología y Desarrollo — CCsoft — Abril 2026