Deploy na AWS com Claude Code: CDK, GitHub Actions, IAM, logs e rollback
Publique uma API pequena na AWS com Claude Code, CDK, OIDC, IAM mínimo, logs, rollback e controle de custos.
O jeito arriscado de usar Claude Code para deploy na AWS é pedir “crie uma arquitetura AWS” e aceitar a primeira resposta. Deploy pronto para operar não é só diagrama. Ele precisa de IaC executável, IAM com permissões limitadas, gestão de segredos, logs, rollback e limites de custo.
Neste guia vamos implementar um caminho seguro para uma aplicação web pequena ou API: API Gateway + Lambda + AWS CDK + GitHub Actions. CDK é Infrastructure as Code: recursos AWS descritos em código, em vez de cliques manuais no console. IAM é o sistema de permissões que define quem pode fazer cada ação. OIDC permite que o GitHub Actions assuma uma role da AWS com credenciais temporárias, sem guardar AWS keys permanentes.
Claude Code ajuda porque lê o repositório, edita vários arquivos, roda cdk synth e cdk diff, explica erros de deploy e transforma o processo em documentação. Para o produto, use a documentação oficial do Claude Code. Para AWS, consulte AWS CDK NodejsFunction, API Gateway Lambda proxy integration, variáveis de ambiente do Lambda, CloudWatch Logs para Lambda e boas práticas de IAM.
Escolha o alvo AWS antes de codar
Se o alvo ficar vago, Claude Code tende a montar uma solução maior do que o necessário.
| Opção | Quando usar | Vantagem | Atenção |
|---|---|---|---|
| Lambda + API Gateway | APIs pequenas, formulários, webhooks, backends leves | Pouca administração de servidor e bom começo para baixo tráfego | Não é ideal para tarefas longas, conexões persistentes ou grandes contêineres |
| ECS/Fargate + ALB | APIs Docker, serviços sempre ativos, API com workers | Mais liberdade para contêineres e migração de apps existentes | Exige VPC, ALB, task definitions, scaling e build de imagem |
| Amplify ou S3 + CloudFront | Sites estáticos, SPAs, apps focadas em frontend | Entrega rápida via CDN e operação simples | API, autenticação e jobs precisam de desenho separado |
Aqui escolhemos Lambda + API Gateway porque é um caso comum em consultoria: publicar uma API pequena de forma segura sem criar uma plataforma complexa. Para continuar, veja Claude Code AWS Lambda, Claude Code AWS IAM, Claude Code API Gateway e boas práticas de segurança com Claude Code.
flowchart LR
User[Usuário] --> Api[API Gateway]
Api --> Fn[Lambda Node.js API]
Fn --> Secret[Secrets Manager]
Fn --> Logs[CloudWatch Logs]
GitHub[GitHub Actions OIDC] --> CDK[AWS CDK deploy]
CDK --> Api
CDK --> Fn
Casos de uso práticos
O primeiro caso é formulário de contato ou captura de leads. O frontend pode continuar no site atual, e apenas o endpoint de envio fica em API Gateway + Lambda. Throttling, API key e CloudWatch Logs ajudam a investigar spam e falhas.
O segundo caso é uma API MVP para SaaS. Comece pequeno, com rotas como /v1/health, /v1/contact e /v1/webhook. Diga ao Claude Code que VPC, RDS, filas e contêineres só devem aparecer quando houver uma necessidade real.
O terceiro caso é webhook interno: alertas no Slack, callbacks de CMS, aprovações ou pequenas ações administrativas. Lambda funciona bem quando cada requisição termina rápido. Se precisar de retry, processamento longo ou fan-out, adicione SQS ou Step Functions de propósito.
O quarto caso é migrar deploy manual para CI/CD. Muitas equipes ainda deployam do notebook ou alteram recursos no console AWS. Claude Code pode levar esse fluxo para CDK e GitHub Actions, mas aprovação de produção, rollback e risco continuam sendo decisões humanas.
Defina regras para Claude Code
Crie um CLAUDE.md na raiz do repositório para evitar que uma API pequena vire uma arquitetura cara.
# AWS deployment rules
- Use AWS CDK v2 and TypeScript.
- Target region: sa-east-1 unless explicitly changed.
- Do not create VPC resources for this small API unless required.
- Prefer API Gateway + Lambda for the first release.
- Runtime secrets must come from AWS Secrets Manager, not plaintext env vars.
- Use IAM grants such as secret.grantRead(handler) instead of wildcard policies.
- Add CloudWatch log retention and reserved concurrency.
- Before deploy, run npm test, npx cdk synth, and npx cdk diff.
- Never paste AWS access keys into files or GitHub Secrets.
Depois peça uma implementação com escopo claro:
Adicione um SmallApiStack CDK v2 neste repositório.
Crie uma API REST no API Gateway e uma Lambda Node.js 20 com /v1/health e /v1/contact.
Leia a configuração de runtime do Secrets Manager: prod/claude-code-demo/api.
Mantenha a role de execução da Lambda com mínimo privilégio e adicione retenção de logs, reserved concurrency e throttling no API Gateway.
O workflow do GitHub Actions deve usar apenas OIDC. Não use AWS keys permanentes.
Depois da edição, rode npm test, npx cdk synth e npx cdk diff, e explique o resultado.
Crie o projeto CDK
Você precisa de Node.js, AWS CLI v2, AWS CDK CLI e um perfil AWS autenticado. Os comandos abaixo são Bash; no Windows, use WSL ou Git Bash.
mkdir claude-code-aws-api
cd claude-code-aws-api
npx cdk init app --language typescript
npm install @aws-sdk/client-secrets-manager
npm install --save-dev esbuild @types/aws-lambda
mkdir -p lambda
aws sts get-caller-identity
Crie a configuração de runtime uma vez. API keys reais, senhas e tokens não devem ir para Git nem para variáveis de ambiente em texto puro.
aws secretsmanager create-secret \
--name prod/claude-code-demo/api \
--secret-string '{"supportQueue":"aws-consulting"}' \
--region sa-east-1
Implemente a Lambda
Crie lambda/handler.ts. O código registra apenas metadados operacionais, sem imprimir corpo completo da requisição nem segredos.
import type {
APIGatewayProxyEvent,
APIGatewayProxyResult,
} from "aws-lambda";
import {
GetSecretValueCommand,
SecretsManagerClient,
} from "@aws-sdk/client-secrets-manager";
const secrets = new SecretsManagerClient({});
let cachedConfig: Record<string, string> | undefined;
async function loadConfig(): Promise<Record<string, string>> {
if (cachedConfig) return cachedConfig;
const secretArn = process.env.SECRET_ARN;
if (!secretArn) throw new Error("SECRET_ARN is not configured");
const result = await secrets.send(
new GetSecretValueCommand({ SecretId: secretArn }),
);
cachedConfig = JSON.parse(result.SecretString ?? "{}");
return cachedConfig;
}
function json(statusCode: number, body: unknown): APIGatewayProxyResult {
return {
statusCode,
headers: {
"content-type": "application/json",
"cache-control": "no-store",
},
body: JSON.stringify(body),
};
}
export async function handler(
event: APIGatewayProxyEvent,
): Promise<APIGatewayProxyResult> {
try {
if (event.httpMethod === "GET" && event.path.endsWith("/v1/health")) {
return json(200, {
ok: true,
stage: process.env.STAGE ?? "dev",
});
}
if (event.httpMethod === "POST" && event.path.endsWith("/v1/contact")) {
const body = JSON.parse(event.body ?? "{}") as {
email?: string;
message?: string;
};
if (!body.email || !body.message) {
return json(400, { ok: false, message: "email and message required" });
}
const config = await loadConfig();
const emailDomain = body.email.split("@")[1] ?? "unknown";
console.log(
JSON.stringify({
event: "contact_received",
emailDomain,
messageLength: body.message.length,
}),
);
return json(202, {
ok: true,
routedTo: config.supportQueue ?? "manual",
});
}
return json(404, { ok: false, message: "not found" });
} catch (error) {
console.error("handler_error", error);
return json(500, { ok: false, message: "internal error" });
}
}
Implemente o stack CDK
Substitua lib/small-api-stack.ts. Os pontos críticos são appSecret.grantRead(handler), retenção de logs, reserved concurrency, throttling e dataTraceEnabled: false para não registrar corpos de requisição em produção.
import * as cdk from "aws-cdk-lib";
import * as apigateway from "aws-cdk-lib/aws-apigateway";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as nodejs from "aws-cdk-lib/aws-lambda-nodejs";
import * as logs from "aws-cdk-lib/aws-logs";
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
import { Construct } from "constructs";
import * as path from "path";
export class SmallApiStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const appSecret = secretsmanager.Secret.fromSecretNameV2(
this,
"AppSecret",
"prod/claude-code-demo/api",
);
const handler = new nodejs.NodejsFunction(this, "ApiHandler", {
functionName: "claude-code-small-api-prod",
entry: path.join(__dirname, "../lambda/handler.ts"),
handler: "handler",
runtime: lambda.Runtime.NODEJS_20_X,
architecture: lambda.Architecture.ARM_64,
memorySize: 256,
timeout: cdk.Duration.seconds(10),
logRetention: logs.RetentionDays.ONE_MONTH,
reservedConcurrentExecutions: 20,
environment: {
STAGE: "prod",
SECRET_ARN: appSecret.secretArn,
},
bundling: {
minify: true,
sourceMap: true,
externalModules: ["@aws-sdk/*"],
},
});
appSecret.grantRead(handler);
handler.addToRolePolicy(
new iam.PolicyStatement({
actions: ["cloudwatch:PutMetricData"],
resources: ["*"],
conditions: {
StringEquals: {
"cloudwatch:namespace": "ClaudeCodeLab/SmallApi",
},
},
}),
);
const api = new apigateway.RestApi(this, "SmallApi", {
restApiName: "claude-code-small-api",
cloudWatchRole: true,
deployOptions: {
stageName: "prod",
metricsEnabled: true,
loggingLevel: apigateway.MethodLoggingLevel.INFO,
dataTraceEnabled: false,
throttlingRateLimit: 20,
throttlingBurstLimit: 40,
},
});
const v1 = api.root.addResource("v1");
v1.addResource("health").addMethod(
"GET",
new apigateway.LambdaIntegration(handler),
);
v1.addResource("contact").addMethod(
"POST",
new apigateway.LambdaIntegration(handler),
{ apiKeyRequired: true },
);
const apiKey = api.addApiKey("ClientApiKey", {
apiKeyName: "claude-code-small-api-prod-client",
});
const usagePlan = api.addUsagePlan("BasicUsagePlan", {
throttle: { rateLimit: 10, burstLimit: 20 },
quota: { limit: 1000, period: apigateway.Period.MONTH },
});
usagePlan.addApiKey(apiKey);
usagePlan.addApiStage({ stage: api.deploymentStage });
new cdk.CfnOutput(this, "ApiUrl", { value: api.url });
}
}
Atualize também o arquivo de entrada em bin/.
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib";
import { SmallApiStack } from "../lib/small-api-stack";
const app = new cdk.App();
new SmallApiStack(app, "SmallApiProdStack", {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION ?? "sa-east-1",
},
});
Revise o diff antes do deploy
O bootstrap do CDK é necessário na primeira vez em uma conta e região.
export AWS_REGION=sa-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
npx cdk bootstrap "aws://${AWS_ACCOUNT_ID}/${AWS_REGION}"
npm test
npx cdk synth
npx cdk diff SmallApiProdStack
npx cdk deploy SmallApiProdStack --require-approval never
Peça ao Claude Code para explicar o cdk diff, principalmente mudanças de IAM. Se uma permissão não tiver justificativa clara, ela não deve ir para produção sem revisão humana.
Teste a API e leia logs
Pegue a URL no output do CloudFormation e teste as rotas.
API_URL=$(aws cloudformation describe-stacks \
--stack-name SmallApiProdStack \
--query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
--output text)
curl "${API_URL}v1/health"
KEY_ID=$(aws apigateway get-api-keys \
--name-query claude-code-small-api-prod-client \
--query "items[0].id" \
--output text)
API_KEY=$(aws apigateway get-api-key \
--api-key "$KEY_ID" \
--include-value \
--query "value" \
--output text)
curl -X POST "${API_URL}v1/contact" \
-H "content-type: application/json" \
-H "x-api-key: ${API_KEY}" \
-d '{"email":"[email protected]","message":"AWS deployment consultation"}'
Acompanhe os logs da Lambda:
aws logs tail "/aws/lambda/claude-code-small-api-prod" \
--since 1h \
--follow
CloudWatch Logs pode demorar alguns minutos. Um pequeno atraso não significa que o deploy falhou.
Deploy com GitHub Actions e OIDC
Não salve AWS Access Keys no GitHub Secrets. Crie um OIDC provider e uma role de deploy na AWS, limitando o trust policy ao repositório e branch corretos.
{
"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:your-org/your-repo:ref:refs/heads/main"
}
}
}
]
}
.github/workflows/deploy-aws.yml:
name: deploy-aws-cdk
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
id-token: write
contents: read
concurrency:
group: prod-aws-cdk
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-cdk-deploy-prod
aws-region: sa-east-1
- run: npm ci
- run: npm test
- run: npx cdk synth
- run: npx cdk diff SmallApiProdStack
- run: npx cdk deploy SmallApiProdStack --require-approval never
A policy da role de deploy depende do modelo de CDK bootstrap, da role de execução do CloudFormation e das regras da organização. Evite AdministratorAccess em produção. O caminho prático é restringir o OIDC, usar permission boundaries quando necessário e reduzir permissões com IAM Access Analyzer.
Adicione guardrails de custo
Uma API serverless pequena também gera custo se entrar em loop, receber spam ou escrever logs demais. O stack inclui throttling, usage plan e reserved concurrency. Adicione AWS Budgets antes da produção.
{
"BudgetName": "small-api-monthly-guardrail",
"BudgetLimit": {
"Amount": "20",
"Unit": "USD"
},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}
[
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80,
"ThresholdType": "PERCENTAGE"
},
"Subscribers": [
{
"SubscriptionType": "EMAIL",
"Address": "[email protected]"
}
]
}
]
aws budgets create-budget \
--account-id "$AWS_ACCOUNT_ID" \
--budget file://budget.json \
--notifications-with-subscribers file://notifications-with-subscribers.json
Budgets e notificações podem não aparecer imediatamente. Configure antes do lançamento.
Rollback e falhas comuns
Para o primeiro serviço Lambda + API Gateway, o rollback mais simples costuma ser reverter o commit ruim e redeployar.
git revert <bad-commit-sha>
git push origin main
Depois confira API, eventos do CloudFormation e logs.
curl "${API_URL}v1/health"
aws cloudformation describe-stack-events \
--stack-name SmallApiProdStack \
--max-items 20
aws logs tail "/aws/lambda/claude-code-small-api-prod" --since 30m
Três falhas aparecem com frequência: alguém muda recursos no console depois do CDK, segredos aparecem em env vars ou logs, ou API Gateway registra corpos de requisição em produção. O stack usa dataTraceEnabled: false, mas o hábito de revisão continua obrigatório.
Peça uma revisão pré-deploy
Use Claude Code como revisor, exigindo evidência.
Faça uma revisão pré-deploy de AWS.
Verifique:
- Se o CDK diff adiciona wildcards IAM excessivos
- Se Lambda lê segredos apenas do Secrets Manager
- Se API Gateway tem throttling, usage plan e logging
- Se CloudWatch Logs pode expor dados pessoais ou bodies completos
- Se passos de rollback estão documentados
- Se npm test, cdk synth e cdk diff passaram
Retorne uma tabela com severity, file, line e fix.
Claude Code não é o aprovador final de produção. Fronteiras de conta, custo e exceções de segurança continuam com humanos. Ele serve para tornar a revisão repetível.
Resumo
O valor de Claude Code em deploy AWS não é apenas escrever CDK mais rápido. É conectar arquitetura, IaC, CI/CD, IAM, segredos, logs, rollback e custo em um fluxo que a equipe consegue repetir.
Para uma API pequena, Lambda + API Gateway + CDK geralmente basta. Use ECS/Fargate quando realmente precisar de contêiner sempre ativo. Use S3 + CloudFront ou Amplify quando o workload for principalmente frontend estático. O primeiro limite deve ser pequeno, revisável e reversível.
Se sua equipe quer adaptar regras de Claude Code, CDK, GitHub Actions OIDC, IAM mínimo e checks operacionais a um repositório real, agende uma consultoria de Claude Code. Masa pode revisar o repositório e o histórico de deploys AWS para transformar isso em um plano implementável.
Na prática, uma API de captura de leads como esta pode ficar deployável em meio dia a um dia se a conta AWS já estiver pronta. O ponto sensível não é o código Lambda, mas IAM, segredos, rollback e visibilidade de custos. Deixe Claude Code acelerar a implementação; mantenha a responsabilidade humana sobre o risco de produção.
Artigos relacionados
Guia prático de AWS Lambda com Claude Code: Node.js, IAM e API Gateway
Crie uma Lambda Node.js com Claude Code: testes locais, IAM mínimo, variáveis, API Gateway e logs CloudWatch.
Desenvolver ferramentas CLI com Claude Code: Node.js, TypeScript, testes e releases seguros
Crie uma CLI Node.js/TypeScript com Claude Code: argumentos, config, stdin/stdout, exit codes, testes, CI e segredos.
GitHub Actions avançado com Claude Code: permissões, OIDC, cache e matrix CI
Desenhe GitHub Actions mais seguros com Claude Code: permissões, OIDC, cache, matrix e YAML pronto.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.