Use Cases

Claude Code × AWS CloudFormation/CDK Guía Completa | Genera Infraestructura como Código Automáticamente

Acelera la infraestructura AWS como código con Claude Code. Código funcional para plantillas CloudFormation, stacks CDK TypeScript y diseño multi-stack, basado en la experiencia real de producción de Masa.

“Odio tener que hacer clic en la consola de AWS cada vez que quiero configurar infraestructura” — si alguna vez te has sentido así, no estás solo. CloudFormation y CDK hacen que la infraestructura sea reproducible mediante código, pero escribir esas plantillas consume tiempo.

Yo gestiono la infraestructura de este sitio (Cloudflare Pages + Workers + D1) con Claude Code, y para la infraestructura de AWS en producción también dejo que Claude Code genere las plantillas de CloudFormation/CDK. Las plantillas que antes tardaban horas ahora se terminan en 1/5 del tiempo.


CloudFormation vs CDK: ¿Cuál elegir?

CloudFormation: Servicio nativo de AWS que describe infraestructura en JSON/YAML
CDK (Cloud Development Kit): Framework que describe infraestructura en TypeScript/Python
                              y la sintetiza a CloudFormation
ComparaciónCloudFormationCDK
LenguajeJSON / YAMLTypeScript, Python, Java, etc.
Seguridad de tiposNingunaExcelente (totalmente type-safe con TypeScript)
ReutilizaciónBaja (copiar-pegar)Alta (abstraída con clases y funciones)
Curva de aprendizajeBajaMedia
Compatibilidad con Claude CodeExcelenteSobresaliente

Para nuevos proyectos, se recomienda ampliamente CDK TypeScript. Tiene una compatibilidad sobresaliente con Claude Code y, combinado con el autocompletado de tipos, produce código de alta calidad.


Paso 1: Convertir recursos AWS existentes a CloudFormation

Un patrón para cuando quieres codificar un entorno AWS existente después del hecho.

claude -p "
Convierte la siguiente configuración AWS en una plantilla CloudFormation (YAML).

[Configuración actual]
- VPC: 10.0.0.0/16, 2 subredes públicas, 2 subredes privadas
- EC2: t3.medium, Amazon Linux 2023, en subred pública
- RDS: MySQL 8.0, db.t3.micro, en subred privada
- ALB: HTTPS (certificado ACM), reenvío a EC2
- Grupos de seguridad: permitir 443 desde ALB, permitir 3306 desde EC2 a RDS

[Requisitos]
- Entorno (dev/staging/prod) conmutable mediante parámetro
- Anteponer el nombre del entorno a los nombres de los recursos
- Mostrar el nombre DNS del ALB en los Outputs de CloudFormation
"

Plantilla CloudFormation generada (extracto):

AWSTemplateFormatVersion: "2010-09-09"
Description: "Web Application Infrastructure"

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, prod]
    Default: dev
  DBPassword:
    Type: String
    NoEcho: true  # Ocultar la contraseña

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub "${Environment}-vpc"

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub "${Environment}-public-1"

  # Grupo de seguridad del ALB
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ALB Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

Outputs:
  ALBDnsName:
    Value: !GetAtt ApplicationLoadBalancer.DNSName
    Export:
      Name: !Sub "${Environment}-alb-dns"

Paso 2: Construir un stack serverless con CDK

Con CDK se escribe en TypeScript, lo que facilita la reutilización de lógica.

# Inicializar proyecto CDK
mkdir my-infra && cd my-infra
npx cdk init app --language typescript

claude -p "
Implementa la siguiente configuración serverless en CDK TypeScript en lib/my-infra-stack.ts.

[Configuración]
- API Gateway (REST API) + Lambda (Node.js 20)
- Tabla DynamoDB (PAY_PER_REQUEST)
- Bucket S3 (privado, versionado habilitado)
- CloudFront (origen S3, soporte de dominio personalizado)
- Pasar nombre de tabla DynamoDB y nombre de bucket S3 como variables de entorno a Lambda
- Adjuntar automáticamente rol IAM de mínimo privilegio a Lambda

Etiquetar todos los recursos apropiadamente,
y habilitar protección contra eliminación en producción (NODE_ENV=production).
"

Código CDK generado:

// lib/my-infra-stack.ts
import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as apigateway from "aws-cdk-lib/aws-apigateway";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";

export class MyInfraStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const isProd = process.env.NODE_ENV === "production";

    // Tabla DynamoDB
    const table = new dynamodb.Table(this, "AppTable", {
      partitionKey: { name: "PK", type: dynamodb.AttributeType.STRING },
      sortKey: { name: "SK", type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      pointInTimeRecovery: true,
      deletionProtection: isProd,
      removalPolicy: isProd ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
    });

    // Bucket S3
    const bucket = new s3.Bucket(this, "AssetsBucket", {
      versioned: true,
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.S3_MANAGED,
      deletionProtection: isProd,
      removalPolicy: isProd ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
    });

    // Función Lambda
    const apiLambda = new lambda.Function(this, "ApiLambda", {
      runtime: lambda.Runtime.NODEJS_20_X,
      handler: "index.handler",
      code: lambda.Code.fromAsset("src/lambda"),
      environment: {
        TABLE_NAME: table.tableName,
        BUCKET_NAME: bucket.bucketName,
        NODE_ENV: process.env.NODE_ENV ?? "development",
      },
      timeout: cdk.Duration.seconds(30),
      memorySize: 512,
    });

    // Otorgar permisos de mínimo privilegio a Lambda
    table.grantReadWriteData(apiLambda);
    bucket.grantReadWrite(apiLambda);

    // API Gateway
    const api = new apigateway.RestApi(this, "AppApi", {
      restApiName: "MyApp API",
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS,
        allowMethods: apigateway.Cors.ALL_METHODS,
      },
    });

    api.root.addProxy({
      defaultIntegration: new apigateway.LambdaIntegration(apiLambda),
    });

    // CloudFront
    const distribution = new cloudfront.Distribution(this, "Distribution", {
      defaultBehavior: {
        origin: new origins.S3Origin(bucket),
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
    });

    // Salida
    new cdk.CfnOutput(this, "ApiUrl", { value: api.url });
    new cdk.CfnOutput(this, "CloudFrontUrl", { value: distribution.distributionDomainName });
  }
}

Paso 3: Actualizar stacks existentes y revisar diferencias

# Revisar diferencias antes del despliegue
npx cdk diff

# Pedir a Claude Code que explique las diferencias
claude -p "
Lee la salida de cdk diff y explica en español qué cambió.
Presta especial atención a los cambios en grupos de seguridad y políticas IAM.

$(npx cdk diff 2>&1)
"

Paso 4: Diseñar una arquitectura multi-stack

La infraestructura a escala de producción se gestiona dividiéndola en múltiples stacks.

claude -p "
Diseña la siguiente configuración multi-stack en CDK TypeScript.

[Estrategia de división de stacks]
- NetworkStack: VPC, subredes, grupos de seguridad
- DatabaseStack: RDS, ElastiCache (depende de NetworkStack)
- ApplicationStack: ECS, ALB, AutoScaling (depende de NetworkStack, DatabaseStack)
- MonitoringStack: Dashboards CloudWatch, alarmas, notificaciones SNS

Incluir dependencias entre stacks y cómo usar CfnOutput / Fn.importValue.
"
// bin/app.ts
import * as cdk from "aws-cdk-lib";
import { NetworkStack } from "../lib/network-stack";
import { DatabaseStack } from "../lib/database-stack";
import { ApplicationStack } from "../lib/application-stack";
import { MonitoringStack } from "../lib/monitoring-stack";

const app = new cdk.App();
const env = { account: process.env.CDK_ACCOUNT, region: "us-east-1" };

const network = new NetworkStack(app, "NetworkStack", { env });
const database = new DatabaseStack(app, "DatabaseStack", { env, vpc: network.vpc });
const application = new ApplicationStack(app, "ApplicationStack", {
  env,
  vpc: network.vpc,
  database: database.cluster,
});
new MonitoringStack(app, "MonitoringStack", {
  env,
  alb: application.alb,
  database: database.cluster,
});

Paso 5: Dejar que Claude Code maneje el debugging de CloudFormation/CDK

Claude Code también puede ayudar a resolver fallos de despliegue.

claude -p "
CDK deploy está fallando con el siguiente error.
Explica la causa y cómo solucionarlo:

$(npx cdk deploy 2>&1 | tail -30)
"

Patrones de fallo comunes:

  • ROLLBACK_COMPLETE: Despliegue anterior falló, dejando el stack roto → ejecutar cdk destroy y volver a desplegar
  • UPDATE_ROLLBACK_FAILED: Conflicto con cambios manuales → resolver manualmente en la consola AWS
  • Resource already exists: Colisión de nombres con un recurso existente → cambiar el nombre del recurso o importarlo

4 errores comunes a evitar

1. Eludir la protección contra eliminación con cdk destroy

En entornos de desarrollo, los recursos permanecerán después de cdk destroy si no se establece removalPolicy: DESTROY. En producción, usar RETAIN para prevenir eliminaciones accidentales.

2. Ignorar la detección de drift en CloudFormation

Cuando cambias recursos manualmente en la consola AWS, CloudFormation queda desincronizado con la realidad (drift). Ejecuta la detección de drift en la consola CloudFormation una vez al mes.

3. Escribir secretos directamente en las plantillas

# Mal: la contraseña queda en la plantilla
DBPassword: "mysecretpassword"

# Bien: obtener de Secrets Manager o Parameter Store
DBPassword: !Sub "{{resolve:secretsmanager:prod/db-password}}"

4. Descuidar el versionado fijo de CDK

Si las versiones de CDK no están alineadas en el equipo en package.json, aparecerán diferencias. Commitear package-lock.json para asegurar que todos usen la misma versión.


Resumen

TareaContribución de Claude Code
Generación de CloudFormationYAML completo solo con describir los requisitos
Implementación CDKCódigo de infraestructura type-safe en TypeScript
Diseño de stacksArquitectura de dependencias multi-stack
Explicación de diffsSalida de cdk diff explicada en español
DebuggingCausa raíz y solución a partir de logs de error

La infraestructura como código es algo que todos sabemos que deberíamos hacer pero seguimos aplazando. Con Claude Code, solo describes “la configuración AWS que necesito” y la plantilla está lista — reduciendo dramáticamente la barrera para adoptar IaC.

Artículos relacionados

Referencias

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

Lleva tu flujo con Claude Code al siguiente nivel

50 plantillas de prompts probadas en producción, listas para copiar y pegar en Claude Code.

Gratis

PDF gratuito: Hoja de trucos de Claude Code en 5 minutos

Solo deja tu correo y te enviaremos al instante la hoja de trucos en una página A4.

Cuidamos tus datos personales y nunca enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero apasionado por Claude Code. Dirige claudecode-lab.com, un medio tecnológico en 10 idiomas con más de 2.000 páginas.