Use Cases

Claude Code × AWS CloudFormation/CDK 完整指南 | 自动生成基础设施即代码

用 Claude Code 加速 AWS 基础设施即代码。CloudFormation 模板、CDK TypeScript Stack 和多 Stack 设计的可运行代码 — 基于 Masa 的真实生产经验。

“每次都要在 AWS 控制台点来点去配置基础设施,真的很烦” — 如果你有过这种感受,你并不孤单。CloudFormation 和 CDK 让基础设施可以通过代码重现,但编写这些模板需要时间。

我用 Claude Code 管理本站的基础设施(Cloudflare Pages + Workers + D1),在 AWS 业务基础设施设计中也让 Claude Code 来生成 CloudFormation/CDK 模板。原来需要数小时的模板,现在 1/5 的时间就能完成。


CloudFormation vs CDK:如何选择?

CloudFormation: 用 JSON/YAML 描述基础设施的 AWS 原生服务
CDK (Cloud Development Kit): 用 TypeScript/Python 等描述基础设施,
                              并转换为 CloudFormation 的框架
对比项CloudFormationCDK
语言JSON / YAMLTypeScript、Python、Java 等
类型安全优秀(TypeScript 完全类型安全)
可复用性低(复制粘贴)高(用类和函数抽象)
学习成本
Claude Code 兼容性优秀出色

新项目强烈推荐 CDK TypeScript。它与 Claude Code 的配合出色,结合类型补全能生成高质量代码。


Step 1:将现有 AWS 资源转为 CloudFormation

适合想要将已有 AWS 环境事后进行代码化的场景。

claude -p "
将以下 AWS 配置转为 CloudFormation 模板(YAML)。

【当前配置】
- VPC: 10.0.0.0/16,公有子网 x2,私有子网 x2
- EC2: t3.medium,Amazon Linux 2023,部署在公有子网
- RDS: MySQL 8.0,db.t3.micro,部署在私有子网
- ALB: HTTPS(ACM 证书),转发到 EC2
- 安全组:ALB 允许 443,EC2 到 RDS 仅允许 3306

【要求】
- 环境(dev/staging/prod)可通过参数切换
- 资源名称添加环境名前缀
- 在 CloudFormation Output 中输出 ALB 的 DNS 名称
"

生成的 CloudFormation 模板(节选):

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

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, prod]
    Default: dev
  DBPassword:
    Type: String
    NoEcho: true  # 密码脱敏

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"

  # 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"

Step 2:用 CDK 构建 Serverless 架构

CDK 用 TypeScript 编写,逻辑复用非常方便。

# 初始化 CDK 项目
mkdir my-infra && cd my-infra
npx cdk init app --language typescript

claude -p "
在 lib/my-infra-stack.ts 中用 CDK TypeScript 实现以下 Serverless 配置。

【配置】
- API Gateway (REST API) + Lambda (Node.js 20)
- DynamoDB 表(PAY_PER_REQUEST)
- S3 存储桶(私有,启用版本控制)
- CloudFront(S3 源,支持自定义域名)
- 将 DynamoDB 表名和 S3 桶名作为环境变量传给 Lambda
- 自动为 Lambda 附加最小权限 IAM 角色

为所有资源添加适当标签,
在生产环境(NODE_ENV=production)中启用删除保护。
"

生成的 CDK 代码:

// 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";

    // 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,
    });

    // 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,
    });

    // 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,
    });

    // 为 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,
      },
    });

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

Step 3:更新现有 Stack 并确认差异

# 部署前确认差异
npx cdk diff

# 让 Claude Code 解释差异
claude -p "
读取 cdk diff 的输出,用中文说明本次变更内容。
特别是安全组和 IAM 策略的变更请详细说明。

$(npx cdk diff 2>&1)
"

Step 4:设计多 Stack 架构

生产级基础设施通过拆分 Stack 来管理。

claude -p "
用 CDK TypeScript 设计以下多 Stack 配置。

【Stack 拆分方案】
- NetworkStack: VPC、子网、安全组
- DatabaseStack: RDS、ElastiCache(依赖 NetworkStack)
- ApplicationStack: ECS、ALB、AutoScaling(依赖 NetworkStack、DatabaseStack)
- MonitoringStack: CloudWatch 仪表板、告警、SNS 通知

包含 Stack 间的依赖关系以及 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: "ap-northeast-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,
});

Step 5:将 CloudFormation/CDK 调试交给 Claude Code

部署失败时的报错也可以让 Claude Code 来解决。

claude -p "
CDK deploy 因以下错误失败。
请说明原因和修复方法:

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

常见失败模式:

  • ROLLBACK_COMPLETE:上次部署失败导致 Stack 损坏 → 执行 cdk destroy 后重新部署
  • UPDATE_ROLLBACK_FAILED:与手动变更冲突 → 在 AWS 控制台手动处理
  • Resource already exists:与现有资源名称冲突 → 修改资源名称或导入

4 个常见陷阱

1. 用 cdk destroy 绕过删除保护

开发环境中如果不设置 removalPolicy: DESTROYcdk destroy 后资源会残留。生产环境中设置 RETAIN 防止误删。

2. 忽视 CloudFormation 漂移检测

在 AWS 控制台手动变更资源后,CloudFormation 与实际状态会产生偏差(漂移)。每月在 CloudFormation 控制台执行一次漂移检测。

3. 在模板中直接写入密钥

# 危险:密码残留在模板中
DBPassword: "mysecretpassword"

# 安全:从 Secrets Manager 或 Parameter Store 获取
DBPassword: !Sub "{{resolve:secretsmanager:prod/db-password}}"

4. 忽视 CDK 版本锁定

团队内 package.json 中 CDK 版本不统一会产生差异。提交 package-lock.json 来统一版本。


总结

任务Claude Code 的贡献
CloudFormation 生成只需描述需求即可得到完整 YAML
CDK 实现TypeScript 类型安全的基础设施代码
Stack 设计多 Stack 依赖关系架构
差异说明用中文解释 cdk diff 输出
调试从错误日志给出原因和修复方法

基础设施即代码是大家都知道该做却一直拖着的事情。用 Claude Code,只需说**“我需要这样的 AWS 配置”,模板就能完成**,IaC 的导入门槛大幅降低。

相关文章

参考资料

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

让你的 Claude Code 工作流更上一层楼

50 个经过实战检验的提示词模板,现在就能复制粘贴到 Claude Code 中使用。

免费

免费 PDF:5 分钟看懂 Claude Code 速查表

只需留下邮箱,我们就会立即把这份 A4 一页速查表 PDF 发送给你。

我们会严格保护你的个人信息,绝不发送垃圾邮件。

Masa

本文作者

Masa

深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。