TL;DR
Las políticas IAM mal configuradas son responsables del 74% de las brechas de seguridad en la nube, según el Verizon Data Breach Investigations Report 2024. Los roles excesivamente permisivos crean rutas de escalada de privilegios que los atacantes explotan. Probar políticas IAM requiere un enfoque sistemático: verificar cada permiso contra el principio de mínimo privilegio, comprobar comodines en acciones sensibles y probar escenarios de escalada como la combinación “iam:CreateRole + iam:AttachRolePolicy”. Según las AWS Security Best Practices, los equipos con testing automatizado de IAM detectan el 85% de configuraciones incorrectas de permisos en CI/CD. Esta guía cubre la estrategia completa de testing de políticas IAM para AWS, Azure y GCP.
Enfoques Asistidos por IA
Las herramientas de IA destacan analizando políticas IAM complejas y generando suites de tests comprehensivas.
Analizando políticas IAM por permisos excesivos:
Analiza esta política IAM de AWS por problemas de seguridad:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["iam:PassRole"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["ec2:*"],
"Resource": "*",
"Condition": {
"StringEquals": {"ec2:Region": "us-east-1"}
}
}
]
}
Identifica: Riesgos de escalación de privilegios, permisos excesivamente amplios,
condiciones faltantes, y proporciona una alternativa de mínimo privilegio para
un rol de pipeline CI/CD.
Generando casos de test de políticas IAM:
Genera casos de test pytest para validar políticas IAM de AWS usando boto3:
1. Verificar que ninguna política permite iam:* o iam:PassRole a Resource "*"
2. Verificar que políticas S3 requieren condiciones de encriptación
3. Asegurar que ninguna política permite assume-role a cuentas externas sin condiciones
4. Validar que políticas admin solo están adjuntas a roles break-glass
Incluye setup apropiado de sesión AWS, parsing de documentos de política y
assertions claras.
Creando checks personalizados de Checkov:
Escribe un check personalizado de Checkov en Python que valide:
1. Las políticas IAM no deben permitir acciones terminando en "*" (ej., s3:*, ec2:*)
2. Todas las declaraciones iam:PassRole deben tener ARNs de Resource explícitos
3. Políticas con acciones administrativas deben tener condiciones MFA
4. Políticas de trust cross-account deben especificar IDs de cuenta explícitos
Incluye la clase del check, lógica de evaluación y tipos de recursos soportados.
Cuándo Usar Diferentes Enfoques de Testing
Framework de Decisión de Estrategia de Testing
| Tipo de Test | Herramienta | Cuándo Ejecutar | Qué Detecta |
|---|---|---|---|
| Validación gramatical | IAM Access Analyzer | Pre-commit, CI | Errores de sintaxis, elementos deprecados |
| Mejores prácticas | Access Analyzer ValidatePolicy | Pipeline CI | Acciones excesivamente permisivas, condiciones faltantes |
| Análisis estático | Checkov, cfn-nag | Pre-commit, CI | Patrones malos conocidos (Resource: “*”) |
| Simulación de políticas | IAM Policy Simulator | Pre-deploy | Comportamiento real de permisos |
| Análisis de acceso | Hallazgos Access Analyzer | Continuo | Acceso externo, permisos no usados |
| Reglas personalizadas | OPA/Rego | Pipeline CI | Requisitos específicos de organización |
Checks Críticos de Políticas IAM
| Check ID | Descripción | Nivel de Riesgo |
|---|---|---|
| CKV_AWS_1 | Políticas IAM no deben permitir privilegios administrativos completos “*” | Crítico |
| CKV_AWS_49 | Políticas IAM no deben permitir PassRole a “*” | Crítico |
| CKV_AWS_40 | Políticas IAM no deben permitir escalación de privilegios | Crítico |
| CKV_AWS_62 | Políticas IAM no deben tener SID vacío | Bajo |
| CKV_AWS_109 | Políticas IAM no deben permitir exposición de credenciales | Alto |
| CKV_AWS_110 | Políticas IAM no deben permitir gestión de permisos sin restricciones | Alto |
Testing de Políticas IAM en AWS
Validación de Políticas con IAM Access Analyzer
# Instalar el validador de políticas IAM para Terraform
pip install tf-policy-validator
# Validar template Terraform
tf-policy-validator validate \
--template-path ./terraform \
--region us-east-1
# Ejecutar checks específicos
tf-policy-validator validate \
--template-path ./terraform \
--region us-east-1 \
--check-type VALIDATE_POLICY \
--check-type CHECK_NO_NEW_ACCESS
Integración con GitHub Actions
name: Validación de Políticas IAM
on:
pull_request:
paths:
- 'terraform/**/*.tf'
- 'cloudformation/**/*.yaml'
jobs:
validate-iam-policies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Validar Políticas IAM Terraform
uses: aws-actions/terraform-aws-iam-policy-validator@v1
with:
template-path: terraform/
region: us-east-1
check-no-new-access: true
check-access-not-granted: true
check-no-public-access: true
- name: Ejecutar Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/
check: CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110
framework: terraform
Checkov para Políticas IAM
# Instalar Checkov
pip install checkov
# Escanear por problemas específicos de IAM
checkov -d ./terraform --check CKV_AWS_1,CKV_AWS_40,CKV_AWS_49
# Output como JUnit para CI
checkov -d ./terraform --framework terraform \
--check CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110 \
--output junitxml > iam-checkov-results.xml
Check Personalizado de Checkov
# custom_checks/iam_no_passrole_star.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
import json
class IAMNoPassRoleStar(BaseResourceCheck):
def __init__(self):
name = "Asegurar que políticas IAM no permiten PassRole a todos los recursos"
id = "CKV_CUSTOM_IAM_1"
supported_resources = ['aws_iam_policy', 'aws_iam_role_policy']
categories = [CheckCategories.IAM]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
policy = conf.get('policy', [None])[0]
if not policy:
return CheckResult.UNKNOWN
# Manejar formatos string y dict
if isinstance(policy, str):
try:
policy = json.loads(policy)
except json.JSONDecodeError:
return CheckResult.UNKNOWN
statements = policy.get('Statement', [])
for statement in statements:
if statement.get('Effect') != 'Allow':
continue
actions = statement.get('Action', [])
if isinstance(actions, str):
actions = [actions]
resources = statement.get('Resource', [])
if isinstance(resources, str):
resources = [resources]
# Verificar PassRole con recurso *
has_passrole = any('PassRole' in action for action in actions)
has_star_resource = '*' in resources
if has_passrole and has_star_resource:
return CheckResult.FAILED
return CheckResult.PASSED
check = IAMNoPassRoleStar()
Testing de Políticas con boto3 en Python
import boto3
import json
import pytest
class TestIAMPolicies:
@pytest.fixture
def iam_client(self):
return boto3.client('iam')
@pytest.fixture
def access_analyzer_client(self):
return boto3.client('accessanalyzer')
def test_no_admin_star_policies(self, iam_client):
"""Verificar que ninguna política otorga acceso admin completo."""
paginator = iam_client.get_paginator('list_policies')
for page in paginator.paginate(Scope='Local'):
for policy in page['Policies']:
version = iam_client.get_policy_version(
PolicyArn=policy['Arn'],
VersionId=policy['DefaultVersionId']
)
document = version['PolicyVersion']['Document']
statements = document.get('Statement', [])
for stmt in statements:
if stmt.get('Effect') != 'Allow':
continue
actions = stmt.get('Action', [])
if isinstance(actions, str):
actions = [actions]
resources = stmt.get('Resource', [])
if isinstance(resources, str):
resources = [resources]
# Fallar si Action: "*" y Resource: "*"
assert not (
'*' in actions and '*' in resources
), f"Política {policy['PolicyName']} tiene privilegios admin"
def test_validate_policy_with_access_analyzer(self, access_analyzer_client):
"""Usar Access Analyzer para validar política."""
policy_document = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
response = access_analyzer_client.validate_policy(
policyDocument=json.dumps(policy_document),
policyType='IDENTITY_POLICY'
)
# Verificar errores y advertencias de seguridad
findings = response.get('findings', [])
errors = [f for f in findings if f['findingType'] == 'ERROR']
security_warnings = [f for f in findings
if f['findingType'] == 'SECURITY_WARNING']
assert len(errors) == 0, f"Errores de validación: {errors}"
assert len(security_warnings) == 0, f"Advertencias de seguridad: {security_warnings}"
Testing con IAM Policy Simulator
def test_policy_denies_unauthorized_actions(iam_client):
"""Simular política para verificar acciones denegadas."""
# Probar que rol de desarrollador no puede acceder a producción
response = iam_client.simulate_principal_policy(
PolicySourceArn='arn:aws:iam::123456789012:role/DeveloperRole',
ActionNames=[
'ec2:TerminateInstances',
's3:DeleteBucket',
'iam:CreateUser'
],
ResourceArns=[
'arn:aws:ec2:us-east-1:123456789012:instance/*',
'arn:aws:s3:::production-*',
'arn:aws:iam::123456789012:user/*'
]
)
for result in response['EvaluationResults']:
assert result['EvalDecision'] == 'implicitDeny', \
f"Rol desarrollador no debería tener permiso {result['EvalActionName']}"
def test_policy_allows_required_actions(iam_client):
"""Verificar que rol tiene permisos requeridos."""
response = iam_client.simulate_principal_policy(
PolicySourceArn='arn:aws:iam::123456789012:role/CICDRole',
ActionNames=[
's3:PutObject',
'ecr:PushImage',
'ecs:UpdateService'
],
ResourceArns=[
'arn:aws:s3:::deployment-artifacts/*',
'arn:aws:ecr:us-east-1:123456789012:repository/my-app',
'arn:aws:ecs:us-east-1:123456789012:service/my-cluster/my-service'
]
)
for result in response['EvaluationResults']:
assert result['EvalDecision'] == 'allowed', \
f"Rol CICD sin permiso requerido: {result['EvalActionName']}"
Testing IAM en Azure
Azure Policy para Validación de RBAC
# Listar definiciones de roles personalizados
az role definition list --custom-role-only true --output table
# Verificar asignaciones de roles
az role assignment list --scope /subscriptions/<sub-id> --output table
# Validar con Azure Policy
az policy assignment list --query "[?policyDefinitionId contains 'rbac']"
InSpec para Azure RBAC
control 'azure-no-owner-custom-roles' do
impact 1.0
title 'Roles personalizados no deben tener permisos equivalentes a Owner'
azure_role_definitions.where(role_type: 'CustomRole').ids.each do |role_id|
describe azure_role_definition(name: role_id) do
its('permissions.first.actions') { should_not include '*' }
its('permissions.first.not_actions') { should_not be_empty }
end
end
end
control 'azure-no-subscription-owner-assignments' do
impact 1.0
title 'Rol Owner no debe asignarse a nivel de suscripción'
describe azure_role_assignments.where(
scope: "/subscriptions/#{input('subscription_id')}",
role_name: 'Owner'
) do
its('count') { should be <= 2 } # Solo permitir cuentas break-glass
end
end
Testing IAM en GCP
GCP Policy Analyzer
# Analizar política IAM de un proyecto
gcloud policy-intelligence analyze-iam-policy \
--project=my-project \
--full-resource-name="//cloudresourcemanager.googleapis.com/projects/my-project"
# Verificar bindings excesivamente permisivos
gcloud projects get-iam-policy my-project --format=json | \
jq '.bindings[] | select(.members[] | contains("allUsers") or contains("allAuthenticatedUsers"))'
Validación Terraform para GCP IAM
# variables.tf - Definir roles permitidos
variable "allowed_project_roles" {
type = list(string)
default = [
"roles/viewer",
"roles/editor",
# Listar explícitamente roles permitidos
]
}
# Validación en recurso
resource "google_project_iam_binding" "binding" {
project = var.project_id
role = var.role
members = var.members
lifecycle {
precondition {
condition = contains(var.allowed_project_roles, var.role)
error_message = "Rol ${var.role} no está en la lista de roles permitidos."
}
precondition {
condition = !contains(var.members, "allUsers") && !contains(var.members, "allAuthenticatedUsers")
error_message = "Bindings IAM públicos (allUsers/allAuthenticatedUsers) no están permitidos."
}
}
}
Integración en Pipeline CI/CD
Workflow Completo de GitHub Actions
name: Seguridad de Políticas IAM
on:
pull_request:
paths:
- 'terraform/iam/**'
- 'policies/**'
jobs:
static-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Ejecutar checks IAM de Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/iam/
check: CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110
output_format: sarif
output_file_path: checkov-iam.sarif
- name: Subir SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: checkov-iam.sarif
access-analyzer:
runs-on: ubuntu-latest
needs: static-analysis
steps:
- uses: actions/checkout@v4
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init
working-directory: terraform/iam/
- name: Validar con Access Analyzer
uses: aws-actions/terraform-aws-iam-policy-validator@v1
with:
template-path: terraform/iam/
region: us-east-1
check-no-new-access: true
policy-simulation:
runs-on: ubuntu-latest
needs: access-analyzer
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v4
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Instalar dependencias
run: pip install boto3 pytest
- name: Ejecutar tests de simulación de políticas
run: pytest tests/iam/ -v --tb=short
Midiendo el Éxito
| Métrica | Antes del Testing | Después del Testing | Cómo Rastrear |
|---|---|---|---|
| Políticas excesivamente permisivas | Encontradas en auditorías | 0 en producción | Reportes Checkov |
| Paths de escalación de privilegios | Desconocidos | 0 detectados | Hallazgos Access Analyzer |
| Tiempo de validación de políticas | Revisión manual (horas) | Automatizado (minutos) | Métricas CI/CD |
| Permisos no usados | Acumulados con el tiempo | Limpieza trimestral | Access Analyzer |
Señales de que tu testing IAM no funciona:
- Checkov pasa pero hallazgos de Access Analyzer en producción
- Cambios de política de “emergencia” evadiendo CI/CD
- Roles acumulando permisos con el tiempo
- Cuentas de servicio con privilegios admin
Conclusión
El testing efectivo de políticas IAM requiere múltiples capas de validación:
- Análisis estático (Checkov) detecta patrones malos conocidos en código
- Validación gramatical (Access Analyzer ValidatePolicy) asegura sintaxis y estructura de políticas
- Simulación de políticas (IAM Policy Simulator) verifica comportamiento real de permisos
- Análisis continuo (hallazgos de Access Analyzer) detecta drift y permisos no usados
La idea clave: las políticas IAM son demasiado críticas para revisión manual solamente. Testing automatizado en pipelines CI/CD detecta problemas antes de llegar a producción, mientras el monitoreo continuo detecta drift de políticas con el tiempo.
Ver También
- Testing de Policy as Code - OPA y Sentinel para reglas IAM personalizadas
- Testing de Security Groups - Testing de control de acceso a nivel de red
- Testing de Compliance para IaC - Cumpliendo requisitos IAM regulatorios
- Estrategias de Testing de Terraform - Pirámide completa de testing IaC
- Testing de Infraestructura AWS - Estrategias más amplias de testing AWS
Recursos Oficiales
“El testing de políticas IAM es el trabajo de seguridad que nadie quiere hacer pero todos necesitan. La buena noticia es que herramientas como IAM Access Analyzer permiten detectar políticas excesivamente permisivas automáticamente — la parte difícil es construir una cultura donde la revisión de políticas sea tan normal como la revisión de código.” — Yuri Kan, Senior QA Lead
FAQ
¿Qué es el testing de políticas IAM?
Validar que las políticas IAM aplican mínimo privilegio. Tests verifican sin comodines en acciones sensibles, sin rutas de escalada (iam:CreateRole + iam:AttachRolePolicy), y todas las identidades con solo los permisos necesarios.
¿Cómo probar políticas AWS IAM?
IAM Policy Simulator para testing interactivo. aws iam simulate-principal-policy en CI/CD. IAM Access Analyzer para análisis automático. Parliament para validación de sintaxis y detección de antipatrones.
¿Principio de mínimo privilegio en testing IAM?
Cada identidad tiene solo los permisos necesarios. Enumera todos los permisos, verifica comodines en acciones sensibles y simula rutas de escalada de auto-concesión.
¿Herramientas para automatizar testing IAM?
AWS: IAM Access Analyzer, Prowler, Cloudsploit. Azure: Policy Compliance. GCP: Config Validator. Multi-nube: Steampipe. Para IaC: Parliament, cfn-policy-validator.
