Claude Code con AWS CloudFormation y CDK: guía práctica para revisar IaC
Revisa AWS CDK y CloudFormation con Claude Code: IAM mínimo, diffs, drift, rollback y guardrails prácticos.
Hacer clic en la consola de AWS parece rápido hasta que alguien pregunta por qué producción no coincide con staging. CloudFormation y AWS CDK ayudan a dejar la infraestructura como código, pero IaC no elimina el riesgo: una política IAM demasiado amplia, un reemplazo de DynamoDB o un NAT Gateway olvidado pueden convertirse en un problema de seguridad o coste.
Uso Claude Code como compañero de redacción y revisión, no como operador autónomo de despliegue. Le pido que genere un primer borrador, explique cdk diff, detecte permisos ampliados y convierta eventos de CloudFormation en una lista de rollback. La aprobación final sigue siendo humana.
Para principiantes: CloudFormation es el servicio nativo de AWS que aplica plantillas; CDK permite escribir infraestructura en TypeScript y sintetizarla a CloudFormation; un stack es la unidad de despliegue; drift significa que el recurso real ya no coincide con el código.
Este artículo se basa en documentación oficial de AWS consultada el 3 de junio de 2026:
- AWS CDK Developer Guide
- AWS CDK CLI deploy command
- AWS CDK CLI diff command
- CloudFormation change sets
- CloudFormation drift detection
- CloudFormation stack failure options
- IAM security best practices
- AWS CDK security best practices
Define el límite de Claude Code
| Trabajo | Claude Code ayuda con | El humano aprueba |
|---|---|---|
| Requisitos | Recursos, entornos y dependencias | Si el recurso hace falta |
| Borrador | Plantillas CloudFormation/CDK | Nombres, eliminación, coste |
| IAM | Acciones y recursos candidatos | Mínimo privilegio real |
| Diff | Resumen de cdk diff o change set | Eliminaciones y reemplazos |
| Incidentes | Lectura de eventos y posibles arreglos | Plan de rollback |
flowchart LR
A["Escribir requisitos"] --> B["Borrador IaC con Claude Code"]
B --> C["Revisión humana de coste y nombres"]
C --> D["cdk diff o change set"]
D --> E["Claude Code revisa riesgos"]
E --> F["Aprobar y desplegar"]
F --> G["Registrar drift y rollback"]
Caso 1: Pasar una parte pequeña a CloudFormation
Empieza con una porción de bajo riesgo. Esta plantilla crea un bucket S3 privado y un rol IAM asumible por Lambda que solo puede leer ese bucket. Como crea un rol con nombre, requiere CAPABILITY_NAMED_IAM.
mkdir cfn-iac-review-demo
cd cfn-iac-review-demo
# Guarda el siguiente YAML como cfn-safe-iac-demo.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "ClaudeCodeLab safe IaC review demo: private S3 bucket and least-privilege Lambda role"
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
ProjectName:
Type: String
Default: cclab-iac-demo
AllowedPattern: "^[a-z0-9][a-z0-9-]{2,24}$"
Resources:
DemoBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
BucketName: !Sub "${ProjectName}-${Environment}-${AWS::AccountId}-${AWS::Region}"
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
Tags:
- Key: Project
Value: !Ref ProjectName
- Key: Environment
Value: !Ref Environment
DemoReaderRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ProjectName}-${Environment}-reader-${AWS::Region}"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: ReadOnlyDemoBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: ListOnlyThisBucket
Effect: Allow
Action:
- s3:ListBucket
Resource: !GetAtt DemoBucket.Arn
- Sid: ReadObjectsOnly
Effect: Allow
Action:
- s3:GetObject
Resource: !Sub "${DemoBucket.Arn}/*"
Outputs:
BucketName:
Value: !Ref DemoBucket
ReaderRoleArn:
Value: !GetAtt DemoReaderRole.Arn
Pide una revisión estricta:
claude -p "
Revisa cfn-safe-iac-demo.yaml como plantilla CloudFormation.
Devuelve una tabla con:
1. acceso público accidental
2. alcance de IAM Resource
3. riesgo de borrado o reemplazo
4. posible coste mensual
5. qué mirar en un change set de producción
"
Crea y revisa el change set antes de ejecutar:
aws cloudformation create-change-set \
--stack-name cclab-iac-demo-dev \
--change-set-name review-20260603-001 \
--template-body file://cfn-safe-iac-demo.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=Environment,ParameterValue=dev ParameterKey=ProjectName,ParameterValue=cclab-iac-demo
aws cloudformation describe-change-set \
--stack-name cclab-iac-demo-dev \
--change-set-name review-20260603-001
Busca Add, Modify, Remove y Replacement. Replacement en S3, RDS, DynamoDB, KMS o redes debe frenar la aprobación hasta entender el impacto.
Caso 2: Stack mínimo con CDK TypeScript
En proyectos nuevos, CDK TypeScript suele ser más mantenible. Este ejemplo crea DynamoDB, S3 y Lambda sin API Gateway para mantener bajo el coste de prueba.
mkdir cdk-iac-review-demo
cd cdk-iac-review-demo
npm init -y
npm install aws-cdk-lib constructs
npm install --save-dev aws-cdk typescript ts-node @types/node
mkdir bin lib
{
"app": "npx ts-node --prefer-ts-exts bin/app.ts"
}
// bin/app.ts
import * as cdk from "aws-cdk-lib";
import { IacReviewDemoStack } from "../lib/iac-review-demo-stack";
const app = new cdk.App();
new IacReviewDemoStack(app, "IacReviewDemoStack", {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION ?? "us-east-1",
},
});
// lib/iac-review-demo-stack.ts
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as logs from "aws-cdk-lib/aws-logs";
import * as s3 from "aws-cdk-lib/aws-s3";
export class IacReviewDemoStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const stage = this.node.tryGetContext("stage") ?? "dev";
const isProd = stage === "prod";
const table = new dynamodb.Table(this, "AppTable", {
partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
pointInTimeRecovery: isProd,
deletionProtection: isProd,
removalPolicy: isProd ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
});
const bucket = new s3.Bucket(this, "PrivateAssetsBucket", {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
enforceSSL: true,
encryption: s3.BucketEncryption.S3_MANAGED,
versioned: true,
removalPolicy: isProd ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: !isProd,
});
const fn = new lambda.Function(this, "ApiHandler", {
runtime: lambda.Runtime.NODEJS_20_X,
handler: "index.handler",
code: lambda.Code.fromInline(`
exports.handler = async () => ({
statusCode: 200,
body: JSON.stringify({
tableName: process.env.TABLE_NAME,
bucketName: process.env.BUCKET_NAME
})
});
`),
environment: {
TABLE_NAME: table.tableName,
BUCKET_NAME: bucket.bucketName,
STAGE: stage,
},
timeout: cdk.Duration.seconds(10),
memorySize: 256,
logRetention: logs.RetentionDays.ONE_WEEK,
});
table.grantReadWriteData(fn);
bucket.grantPut(fn);
fn.addToRolePolicy(
new iam.PolicyStatement({
sid: "DenyInsecureS3Transport",
effect: iam.Effect.DENY,
actions: ["s3:*"],
resources: [bucket.bucketArn, bucket.arnForObjects("*")],
conditions: { Bool: { "aws:SecureTransport": "false" } },
}),
);
cdk.Tags.of(this).add("Project", "ClaudeCodeLab");
cdk.Tags.of(this).add("Stage", stage);
new cdk.CfnOutput(this, "FunctionName", { value: fn.functionName });
new cdk.CfnOutput(this, "BucketName", { value: bucket.bucketName });
new cdk.CfnOutput(this, "TableName", { value: table.tableName });
}
}
Antes de desplegar:
npx cdk synth -c stage=dev
npx cdk diff -c stage=dev
claude -p "
Revisa este cdk diff.
Solo marca borrados, reemplazos, ampliación IAM, exposición S3, coste DynamoDB y fuga de variables Lambda.
$(npx cdk diff -c stage=dev 2>&1)
"
autoDeleteObjects: !isProd es cómodo en desarrollo, pero peligroso en producción. Ese tipo de guardrail por entorno debe aparecer en la revisión.
Caso 3: Explicar diffs de producción
claude -p "
Resume este cdk diff para una persona de producto que no es especialista AWS.
Usa columnas:
- tipo de cambio
- recurso
- impacto usuario
- impacto seguridad
- impacto coste
- pregunta antes de aprobar
$(npx cdk diff -c stage=prod 2>&1)
"
Los puntos de mayor riesgo son IAM Action/Resource, security groups abiertos a 0.0.0.0/0, falta de deletion protection, S3 público, alta de CloudFront o NAT Gateway y reemplazos de recursos con estado.
Caso 4: Rollback y drift
aws cloudformation describe-stacks --stack-name cclab-iac-demo-dev
aws cloudformation detect-stack-drift --stack-name cclab-iac-demo-dev
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id YOUR_DETECTION_ID
claude -p "
Este stack está en UPDATE_ROLLBACK_FAILED.
Lee los eventos y separa causas probables, recursos que se pueden tocar, recursos que no se deben tocar y pasos a verificar en la documentación AWS.
$(aws cloudformation describe-stack-events --stack-name cclab-iac-demo-dev 2>&1)
"
Errores frecuentes
IAM demasiado amplio. No aceptes Action: "*" ni Resource: "*" porque “funciona”. Acota acciones, ARN y condiciones.
Desplegar sin leer el diff. Producción necesita synth, diff y change set. Si aparece Replacement, se revisa antes de aprobar.
No mirar costes fijos. ALB, NAT Gateway, RDS, OpenSearch y ECS siempre encendido cuestan incluso con poco tráfico.
Dejar cambios manuales como solución permanente. La consola sirve para emergencias, pero el arreglo final debe volver a CloudFormation o CDK.
Escribir secretos en código. Usa Secrets Manager o SSM Parameter Store y pide a Claude Code que no imprima valores secretos.
Prompt de revisión
Eres un revisor estricto de AWS CloudFormation/CDK.
Revisa este diff de IaC antes de producción.
Comprueba:
- IAM Action/Resource/Condition con mínimo privilegio
- exposición accidental por security groups o S3
- borrado o reemplazo de recursos con estado
- coste fijo nuevo como ALB, NAT Gateway, RDS u OpenSearch
- posible CloudFormation drift
- recursos que requieren pasos manuales de rollback
Salida:
1. problemas que corregir ahora
2. preguntas para aprobar
3. comandos antes de deploy
4. comandos después de deploy
Más recursos
Para IAM, lee Claude Code y AWS IAM. Para la capa de ejecución y datos, combina este artículo con AWS Lambda, AWS API Gateway y AWS DynamoDB.
ClaudeCodeLab ofrece productos prácticos y training para equipos para convertir estos prompts en plantillas de Pull Request y checklists de release.
Resumen
Claude Code funciona mejor con CloudFormation/CDK como segundo revisor estricto. Deja que redacte, pero exige que explique IAM, coste, reemplazos, rollback y drift antes de desplegar. El resultado práctico es claro: revisar cdk diff y change sets con Claude Code descubre más riesgos que usarlo solo para generar plantillas.
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
Checklist de permisos antes de que Claude Code edite un sitio de cliente
Guía para agencias que quieren usar IA en landing pages sin tocar zonas sensibles.
Convierte tickets de soporte SaaS en pasos reproducibles con Claude Code
Flujo para transformar reportes vagos en pasos, evidencia y una nota útil para ingeniería.
Convierte tus notas viejas de Obsidian en instrucciones para Claude Code en 10 minutos
Rutina de 10 minutos para separar tus notas de Obsidian en hechos, decisiones y dudas, y darle a Claude Code instrucciones que sí funcionan.