Use Cases (Actualizado: 3/6/2026)

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.

Claude Code con AWS CloudFormation y CDK: guía práctica para revisar IaC

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:

Define el límite de Claude Code

TrabajoClaude Code ayuda conEl humano aprueba
RequisitosRecursos, entornos y dependenciasSi el recurso hace falta
BorradorPlantillas CloudFormation/CDKNombres, eliminación, coste
IAMAcciones y recursos candidatosMínimo privilegio real
DiffResumen de cdk diff o change setEliminaciones y reemplazos
IncidentesLectura de eventos y posibles arreglosPlan 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.

#claude-code #aws #cloudformation #cdk #iac #typescript
Gratis

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.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.