Claude Code y AWS IAM: guía práctica de políticas de mínimo privilegio
Diseña y valida políticas AWS IAM de mínimo privilegio con Claude Code, Access Analyzer y CDK.
AWS IAM decide quién puede hacer qué sobre cada recurso de AWS. Una política parece solo un documento JSON, pero un Action: "*" o Resource: "*" puede dar a una Lambda, a un job de CI o a una cuenta humana mucho más poder del necesario. Claude Code ayuda a redactar y revisar políticas, pero no debe convertirse en un generador de permisos sin control.
La forma segura es trabajar en pasos: describir el caso de uso, pedir un borrador a Claude Code, validar con IAM Access Analyzer, revisar los ARN y límites de negocio, fijar la política con CDK y probar tanto las acciones permitidas como las denegadas. Para empezar: una política es la regla de permisos, un rol es una identidad temporal que asume una carga de trabajo y un principal es el usuario o servicio que usa el permiso.
Masa cambió su proceso después de descubrir que una política S3 amplia, añadida como parche temporal a una Lambda de producción, seguía activa semanas después. No hubo fuga, pero la lección fue clara: Claude Code reduce el tiempo de redacción, no la responsabilidad de revisión.
Usa la documentación oficial como base
Esta guía sigue las recomendaciones actuales de AWS:
- Security best practices in IAM
- IAM JSON policy element reference
- Validate policies with IAM Access Analyzer
- Temporary security credentials in IAM
- Permissions boundaries for IAM entities
El resumen práctico: usa credenciales temporales y roles, aplica mínimo privilegio, valida con Access Analyzer, usa condiciones con cuidado y elimina permisos que ya no se usan.
flowchart LR
A["Escribir caso de uso"] --> B["Borrador con Claude Code"]
B --> C["Revisión humana de ARN"]
C --> D["IAM Access Analyzer"]
D --> E["Implementación con CDK"]
E --> F["Pruebas permitidas y denegadas"]
Empieza por casos de uso concretos
No pidas solo “crea una política IAM”. Incluye actor, recursos, operaciones permitidas y operaciones que deben quedar prohibidas.
| Caso de uso | Principal | Permisos necesarios | Evitar explícitamente |
|---|---|---|---|
| Lambda de miniaturas | Rol de ejecución Lambda | Leer un prefijo S3, escribir un prefijo S3, escribir una tabla DynamoDB, publicar un tema SNS, escribir logs | Borrar S3, leer todos los buckets, operar IAM |
| Ayuda de carga en panel interno | Rol Lambda de API | PutObject en un prefijo S3, GetItem en una tabla DynamoDB | List de todo el bucket, gestión de claves KMS |
| Despliegue desde GitHub Actions | Rol CI con OIDC | Actualizar un stack CloudFormation y una Lambda concreta | AdministratorAccess, operaciones en todas las regiones |
| Rol de investigación de incidentes | Usuario federado | Buscar en CloudWatch Logs, leer X-Ray, GetItem en la tabla relevante | Actualizar, borrar, leer secretos |
La columna de prohibiciones evita que Claude Code rellene información faltante con permisos demasiado amplios.
Política Lambda lista para copiar
Esta política es para una Lambda que lee imágenes desde S3, guarda miniaturas en otro prefijo, escribe metadatos en DynamoDB, publica alertas en SNS y escribe logs. El grupo de logs se crea antes con infraestructura como código, por eso el rol no necesita logs:CreateLogGroup.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadSourceImages",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::user-uploads-prod/incoming/*"
},
{
"Sid": "WriteThumbnails",
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::user-thumbnails-prod/thumbnails/*",
"Condition": {
"StringEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
},
{
"Sid": "WriteMetadata",
"Effect": "Allow",
"Action": ["dynamodb:PutItem", "dynamodb:UpdateItem"],
"Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/image-metadata"
},
{
"Sid": "PublishAlerts",
"Effect": "Allow",
"Action": ["sns:Publish"],
"Resource": "arn:aws:sns:ap-northeast-1:123456789012:alert-topic"
},
{
"Sid": "WriteLambdaLogs",
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/image-worker-prod:*"
}
]
}
Guárdala como policy-lambda-image-worker.json y ejecuta:
aws accessanalyzer validate-policy \
--policy-document file://policy-lambda-image-worker.json \
--policy-type IDENTITY_POLICY \
--query "findings[?findingType!='SUGGESTION']"
Después pide una revisión estructurada:
claude -p "Revisa policy-lambda-image-worker.json como política AWS IAM de mínimo privilegio.
Contexto: Lambda lee S3 incoming/, escribe thumbnails/, escribe DynamoDB image-metadata, publica SNS alert-topic y escribe CloudWatch Logs.
Comprueba: comodines, permisos de borrado, Resource demasiado amplio, Condition correcta y alcance de logs.
Devuelve una tabla con Sid, riesgo, motivo y corrección más segura."
Access Analyzer valida gramática, ARN, acciones, claves de condición y hallazgos de seguridad. No sabe si tu producto necesita realmente esa acción; esa decisión sigue siendo humana.
Implementa el rol con CDK
No dejes permisos revisados solo en la consola. Con TypeScript CDK, el rol, el grupo de logs y las políticas quedan en la misma solicitud de cambios.
import * as cdk from "aws-cdk-lib";
import { Stack, StackProps, aws_iam as iam, aws_logs as logs } from "aws-cdk-lib";
import { Construct } from "constructs";
export class ImageWorkerIamStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const account = Stack.of(this).account;
const region = Stack.of(this).region;
new logs.LogGroup(this, "ImageWorkerLogGroup", {
logGroupName: "/aws/lambda/image-worker-prod",
retention: logs.RetentionDays.ONE_MONTH,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
const role = new iam.Role(this, "ImageWorkerRole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
description: "Execution role for image-worker-prod Lambda",
});
role.addToPolicy(new iam.PolicyStatement({
sid: "ReadSourceImages",
actions: ["s3:GetObject"],
resources: ["arn:aws:s3:::user-uploads-prod/incoming/*"],
}));
role.addToPolicy(new iam.PolicyStatement({
sid: "WriteThumbnails",
actions: ["s3:PutObject"],
resources: ["arn:aws:s3:::user-thumbnails-prod/thumbnails/*"],
conditions: {
StringEquals: {
"s3:x-amz-server-side-encryption": "AES256",
},
},
}));
role.addToPolicy(new iam.PolicyStatement({
sid: "WriteMetadataAndAlerts",
actions: ["dynamodb:PutItem", "dynamodb:UpdateItem", "sns:Publish"],
resources: [
`arn:aws:dynamodb:${region}:${account}:table/image-metadata`,
`arn:aws:sns:${region}:${account}:alert-topic`,
],
}));
role.addToPolicy(new iam.PolicyStatement({
sid: "WriteLambdaLogs",
actions: ["logs:CreateLogStream", "logs:PutLogEvents"],
resources: [
`arn:aws:logs:${region}:${account}:log-group:/aws/lambda/image-worker-prod:*`,
],
}));
}
}
CI con OIDC, no con claves largas
Para CI/CD, evita guardar claves AWS de largo plazo en secretos del repositorio. GitHub Actions puede asumir un rol IAM mediante OIDC y recibir credenciales temporales.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:example-org/example-repo:ref:refs/heads/main"
}
}
}
]
}
Esto es una política de confianza: decide quién puede asumir el rol. La política de permisos decide qué puede hacer después. Revísalas por separado.
Errores habituales
El primero es dejar permisos de administrador temporales. Si una emergencia exige ampliar permisos, registra responsable, fecha de caducidad, revisión de CloudTrail y nueva ejecución de Access Analyzer.
El segundo es mezclar ARN de bucket y de objeto en S3. s3:ListBucket usa arn:aws:s3:::bucket-name; s3:GetObject y s3:PutObject usan arn:aws:s3:::bucket-name/prefix/*.
El tercero es añadir condiciones IP a roles de Lambda sin entender llamadas entre servicios. aws:SourceIp puede tener sentido para humanos o APIs públicas, pero puede romper flujos internos de AWS.
El cuarto es probar solo el éxito. También confirma que s3:DeleteObject, buckets no relacionados, tablas no relacionadas y acciones IAM quedan denegadas.
Lecturas relacionadas y siguiente paso
Para profundizar, lee la guía AWS Lambda, la guía AWS S3, la guía AWS CloudWatch y las buenas prácticas de seguridad con Claude Code.
Si tu equipo quiere estandarizar Claude Code, AWS IAM, CDK y revisión de permisos CI, empieza por la página de formación y consultoría. Para trabajo individual, usa la hoja gratuita y los materiales de la página de productos.
Probé este flujo generando la política con Claude Code, validando el JSON y revisando el CDK contra la misma tabla de casos de uso. La mejora principal fue escribir primero las operaciones prohibidas: los permisos S3 amplios y los comodines de logs innecesarios aparecieron antes del despliegue.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.