Deploy AWS dengan Claude Code: CDK, GitHub Actions, IAM, Log, dan Rollback
Panduan deploy API kecil ke AWS dengan Claude Code, CDK, OIDC, IAM minimum, log, rollback, dan guardrail biaya.
Cara berisiko memakai Claude Code untuk deploy AWS adalah meminta “buatkan arsitektur AWS” lalu menerima output pertama begitu saja. Deployment yang bisa dioperasikan bukan hanya diagram. Ia butuh infrastructure code yang bisa dijalankan, IAM yang dibatasi, pengelolaan secret, log, rollback, dan batas biaya.
Di panduan ini kita implement satu jalur aman untuk web app kecil atau API: API Gateway + Lambda + AWS CDK + GitHub Actions. CDK adalah Infrastructure as Code, yaitu resource AWS ditulis sebagai code, bukan dibuat manual lewat console. IAM adalah sistem permission yang menentukan siapa boleh melakukan apa. OIDC membuat GitHub Actions bisa mengambil role AWS dengan kredensial sementara, jadi kamu tidak perlu menyimpan AWS access key jangka panjang di GitHub Secrets.
Claude Code berguna karena bisa membaca repository, mengubah beberapa file, menjalankan cdk synth dan cdk diff, menjelaskan error deploy, dan mengubah workflow menjadi dokumentasi. Untuk perilaku produk, gunakan dokumentasi Claude Code. Untuk detail AWS, rujuk ke AWS CDK NodejsFunction, API Gateway Lambda proxy integration, environment variables Lambda, CloudWatch Logs untuk Lambda, dan IAM best practices.
Tentukan target AWS sebelum coding
Kalau target tidak jelas, Claude Code mudah membuat arsitektur yang terlalu besar. Tentukan bentuk workload dulu.
| Opsi | Cocok untuk | Kelebihan | Risiko |
|---|---|---|---|
| Lambda + API Gateway | API kecil, form kontak, webhook, admin backend ringan | Minim server management dan mudah mulai dari traffic rendah | Kurang cocok untuk proses panjang, koneksi persisten, atau container besar |
| ECS/Fargate + ALB | API Docker, service always-on, API plus worker | Fleksibel untuk container dan migrasi app existing | Perlu desain VPC, ALB, task definition, scaling, dan image build |
| Amplify atau S3 + CloudFront | Static site, SPA, app yang dominan frontend | CDN cepat dan operasi sederhana | API, auth, dan backend jobs harus didesain terpisah |
Artikel ini memilih Lambda + API Gateway karena ini kasus konsultasi yang sering muncul: API kecil ingin aman di AWS tanpa over-engineering. Untuk topik lanjutan, baca Claude Code AWS Lambda, Claude Code AWS IAM, Claude Code API Gateway, dan Claude Code security best practices.
flowchart LR
User[Pengguna] --> 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
Use case yang realistis
Use case pertama adalah form kontak atau lead capture. Frontend tetap di website yang ada, sementara endpoint submit dipindah ke API Gateway + Lambda. Throttling, API key, dan CloudWatch Logs membantu investigasi spam dan incident.
Use case kedua adalah API MVP untuk SaaS. Mulai dari route kecil seperti /v1/health, /v1/contact, dan /v1/webhook. Beri tahu Claude Code bahwa VPC, RDS, queue, dan container tidak perlu dibuat sampai requirement benar-benar muncul.
Use case ketiga adalah webhook internal: alert Slack, callback CMS, approval flow, atau operasi admin ringan. Lambda cocok jika setiap request selesai cepat. Jika butuh retry, proses panjang, atau fan-out, tambahkan SQS atau Step Functions secara sengaja.
Use case keempat adalah migrasi deploy manual ke CI/CD. Banyak tim masih deploy dari laptop atau klik console AWS. Claude Code bisa memindahkan proses itu ke CDK dan GitHub Actions, tetapi approval production, rollback, dan risk decision tetap milik manusia.
Beri aturan deployment ke Claude Code
Buat CLAUDE.md di root repository. Ini guardrail supaya API kecil tidak berubah menjadi platform mahal.
# AWS deployment rules
- Use AWS CDK v2 and TypeScript.
- Target region: ap-southeast-3 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.
Prompt Claude Code dengan output dan batas yang jelas:
Tambahkan CDK v2 SmallApiStack ke repository ini.
Buat API Gateway REST API dan Lambda Node.js 20 dengan /v1/health dan /v1/contact.
Baca runtime config dari Secrets Manager secret prod/claude-code-demo/api.
Jaga Lambda execution role tetap least privilege, tambahkan CloudWatch log retention, reserved concurrency, dan API Gateway throttling.
Workflow GitHub Actions harus menggunakan OIDC saja. Jangan gunakan AWS key jangka panjang.
Setelah edit, jalankan npm test, npx cdk synth, dan npx cdk diff, lalu jelaskan hasilnya.
Buat project CDK
Kamu butuh Node.js, AWS CLI v2, AWS CDK CLI, dan AWS profile yang sudah login. Command berikut memakai Bash; di Windows gunakan WSL atau 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
Buat runtime config sekali. API key, password database, dan token layanan eksternal tidak boleh masuk Git atau plaintext environment variable.
aws secretsmanager create-secret \
--name prod/claude-code-demo/api \
--secret-string '{"supportQueue":"aws-consulting"}' \
--region ap-southeast-3
Implement Lambda handler
Buat lambda/handler.ts. Code ini hanya menulis metadata operasional, bukan full request body atau secret.
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" });
}
}
Implement CDK stack
Ganti lib/small-api-stack.ts. Poin pentingnya adalah appSecret.grantRead(handler), log retention, reserved concurrency, throttling, dan dataTraceEnabled: false supaya request body tidak masuk production logs.
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 });
}
}
Update entry file di 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 ?? "ap-southeast-3",
},
});
Cek diff sebelum deploy
CDK bootstrap dibutuhkan saat pertama kali deploy ke account dan region tertentu.
export AWS_REGION=ap-southeast-3
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
Minta Claude Code menjelaskan cdk diff, terutama perubahan IAM. Jika sebuah permission tidak bisa dijelaskan, jangan kirim ke production tanpa human review.
Test API dan baca log
Ambil URL dari CloudFormation output dan panggil routes.
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":"masa@example.com","message":"AWS deployment consultation"}'
Tail log Lambda:
aws logs tail "/aws/lambda/claude-code-small-api-prod" \
--since 1h \
--follow
CloudWatch Logs bisa terlambat beberapa menit. Delay singkat bukan berarti deploy gagal.
Deploy dari GitHub Actions dengan OIDC
Jangan simpan AWS Access Key di GitHub Secrets. Buat OIDC provider dan deployment role di AWS, lalu batasi trust policy ke repository dan branch yang benar.
{
"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: ap-southeast-3
- run: npm ci
- run: npm test
- run: npx cdk synth
- run: npx cdk diff SmallApiProdStack
- run: npx cdk deploy SmallApiProdStack --require-approval never
Permission policy untuk deployment role bergantung pada model CDK bootstrap, CloudFormation execution role, dan aturan organisasi. Jangan pakai AdministratorAccess sebagai default production. Praktiknya: sempitkan OIDC trust condition, gunakan permission boundary bila perlu, lalu kurangi permission dengan IAM Access Analyzer.
Tambahkan guardrail biaya
API serverless kecil tetap bisa mahal jika ada loop, spam, atau log berlebihan. Stack ini punya API throttling, usage plan, dan Lambda reserved concurrency. Tambahkan AWS Budgets sebelum production.
{
"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": "owner@example.com"
}
]
}
]
aws budgets create-budget \
--account-id "$AWS_ACCOUNT_ID" \
--budget file://budget.json \
--notifications-with-subscribers file://notifications-with-subscribers.json
Grafik dan notifikasi budget mungkin tidak muncul langsung. Set sebelum launch, bukan setelah bill naik.
Rollback dan failure mode
Untuk service Lambda + API Gateway pertama, rollback paling praktis biasanya revert commit buruk dan redeploy.
git revert <bad-commit-sha>
git push origin main
Lalu cek API, CloudFormation events, dan log.
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
Tiga masalah sering terjadi. Pertama, ada yang edit AWS console setelah CDK deploy sehingga diff membingungkan. Kedua, secret masuk ke env var atau log. Ketiga, API Gateway request body tracing aktif di production dan payload sensitif tersimpan di log. Stack ini memakai dataTraceEnabled: false, tetapi kebiasaan review tetap diperlukan.
Minta pre-deploy review ke Claude Code
Gunakan Claude Code sebagai reviewer, tetapi minta bukti.
Lakukan AWS pre-deployment review.
Cek:
- Apakah CDK diff menambah IAM wildcard berlebihan
- Apakah Lambda membaca secret hanya dari Secrets Manager
- Apakah API Gateway punya throttling, usage plan, dan logging
- Apakah CloudWatch Logs bisa mengekspos data pribadi atau full request body
- Apakah rollback steps terdokumentasi
- Apakah npm test, cdk synth, dan cdk diff lulus
Kembalikan tabel berisi severity, file, line, dan fix.
Claude Code bukan approver production final. Account boundary, risiko biaya, dan pengecualian security tetap tanggung jawab manusia. Nilainya adalah membuat review bisa diulang.
Ringkasan
Nilai Claude Code untuk deploy AWS bukan hanya menulis CDK lebih cepat. Nilainya adalah menghubungkan arsitektur, IaC, CI/CD, IAM, secrets, logs, rollback, dan biaya menjadi workflow yang bisa diulang.
Untuk API kecil, Lambda + API Gateway + CDK sering cukup. Pindah ke ECS/Fargate ketika memang butuh container selalu aktif. Gunakan S3 + CloudFront atau Amplify jika workload lebih banyak static frontend. Batas pertama harus kecil, bisa direview, dan bisa di-rollback.
Jika tim kamu ingin mendesain Claude Code rules, AWS CDK deployment, GitHub Actions OIDC, least-privilege IAM, dan operational checks untuk repository nyata, gunakan Claude Code consulting session. Masa bisa meninjau repository, setup AWS, dan riwayat failure deploy untuk membuat rencana implementasi yang realistis.
Dalam praktik, API lead capture kecil seperti ini bisa dibuat deployable dalam setengah hari sampai satu hari jika account AWS sudah siap. Bagian paling sensitif bukan Lambda code, tetapi IAM, secrets, rollback, dan cost visibility. Biarkan Claude Code mempercepat implementasi, sementara manusia memegang keputusan risiko production.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.