Use Cases (Actualizado: 2/6/2026)

Desplegar en AWS con Claude Code: CDK, GitHub Actions, IAM, logs y rollback

Despliega una API pequeña en AWS con Claude Code, CDK, OIDC, IAM mínimo, logs, rollback y control de costes.

Desplegar en AWS con Claude Code: CDK, GitHub Actions, IAM, logs y rollback

El error más común al usar Claude Code para desplegar en AWS es pedir “créame una arquitectura” y aceptar una respuesta bonita pero incompleta. Una arquitectura operable necesita código de infraestructura que se pueda ejecutar, permisos IAM acotados, gestión de secretos, logs, rollback y límites de coste.

En esta guía implementamos una ruta segura para una aplicación web pequeña o una API: API Gateway + Lambda + AWS CDK + GitHub Actions. CDK significa Infrastructure as Code: definir en código los recursos que antes crearías manualmente en la consola de AWS. IAM es el sistema de permisos que decide quién puede hacer qué. OIDC permite que GitHub Actions asuma un rol de AWS con credenciales temporales, sin guardar claves AWS de larga duración.

Claude Code ayuda porque puede leer el repositorio, modificar varios archivos, ejecutar cdk synth y cdk diff, interpretar errores de despliegue y documentar el flujo. Para el producto, consulta la documentación oficial de Claude Code. Para las afirmaciones de AWS, usa las referencias oficiales de AWS CDK NodejsFunction, API Gateway con Lambda proxy, variables de entorno en Lambda, CloudWatch Logs para Lambda y buenas prácticas de IAM.

Elige el destino de AWS antes de escribir código

Si el destino queda ambiguo, Claude Code tenderá a sobreconstruir. Decide primero el tipo de carga.

OpciónCuándo usarlaVentajaRiesgo principal
Lambda + API GatewayAPIs pequeñas, formularios, webhooks, backends ligerosPoca administración de servidores y buen punto de entradaNo encaja bien con tareas largas, conexiones persistentes o contenedores grandes
ECS/Fargate + ALBAPIs Dockerizadas, servicios siempre activos, workersMás libertad para contenedores y migración de apps existentesRequiere VPC, ALB, task definitions, escalado e imágenes
Amplify o S3 + CloudFrontSitios estáticos, SPA, frontend dominanteCDN rápido y operación simpleAPI, autenticación y jobs se diseñan aparte

Aquí elegimos Lambda + API Gateway porque cubre una necesidad frecuente: publicar una API pequeña sin convertir el primer despliegue en una plataforma compleja. Para profundizar, revisa AWS Lambda con Claude Code, IAM en AWS con Claude Code, API Gateway con Claude Code y seguridad con Claude Code.

flowchart LR
  User[Usuario] --> 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 reales

El primer caso es un formulario de contacto o captación de leads. Mantienes el frontend actual y despliegas solo el endpoint de envío. El throttling de API Gateway, una API key y CloudWatch Logs facilitan investigar spam y errores.

El segundo caso es una API MVP para un SaaS. Empieza con rutas pequeñas como /v1/health, /v1/contact y /v1/webhook. Dile explícitamente a Claude Code que no cree VPC, RDS, colas ni contenedores hasta que exista una necesidad real.

El tercer caso es un webhook interno: alertas de Slack, callbacks de CMS, aprobaciones o pequeñas tareas de administración. Lambda funciona bien cuando cada petición termina rápido. Si necesitas reintentos, trabajos largos o fan-out, añade SQS o Step Functions de forma consciente.

El cuarto caso es migrar un despliegue manual a CI/CD. Muchos equipos siguen desplegando desde un portátil o tocando la consola de AWS. Claude Code puede mover ese proceso a CDK y GitHub Actions, pero las decisiones de producción, aprobación y rollback siguen siendo humanas.

Dale reglas de despliegue a Claude Code

Escribe un CLAUDE.md en la raíz del repositorio. Este archivo funciona como contrato para que Claude Code no convierta una API pequeña en una arquitectura cara.

# AWS deployment rules

- Use AWS CDK v2 and TypeScript.
- Target region: eu-west-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.

Después pide el trabajo con límites claros:

Añade un SmallApiStack de CDK v2 a este repositorio.
Crea una API REST de API Gateway y una Lambda Node.js 20 con /v1/health y /v1/contact.
Lee la configuración de runtime desde Secrets Manager: prod/claude-code-demo/api.
Mantén el rol de ejecución de Lambda con mínimo privilegio y añade retención de logs, reserved concurrency y throttling de API Gateway.
El workflow de GitHub Actions debe usar solo OIDC. No uses claves AWS de larga duración.
Después de editar, ejecuta npm test, npx cdk synth y npx cdk diff, y explica el resultado.

Crea el proyecto CDK

Necesitas Node.js, AWS CLI v2, AWS CDK CLI y un perfil AWS autenticado. Los comandos son Bash; en Windows usa WSL o 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

Crea la configuración de runtime una vez. Las claves de API, contraseñas de base de datos y tokens externos no deben ir al repositorio ni a variables de entorno en texto plano.

aws secretsmanager create-secret \
  --name prod/claude-code-demo/api \
  --secret-string '{"supportQueue":"aws-consulting"}' \
  --region eu-west-1

Implementa la Lambda

Crea lambda/handler.ts. El código registra metadatos útiles, no el cuerpo completo de la petición ni secretos.

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" });
  }
}

Implementa el stack CDK

Sustituye lib/small-api-stack.ts. Los detalles importantes son appSecret.grantRead(handler), retención de logs, reserved concurrency, throttling y dataTraceEnabled: false para no volcar cuerpos de petición en logs de producción.

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

Actualiza el archivo de entrada en 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 ?? "eu-west-1",
  },
});

Revisa el diff antes de desplegar

CDK necesita bootstrap la primera vez que despliega en una cuenta y región.

export AWS_REGION=eu-west-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

Pide a Claude Code que explique el cdk diff, especialmente los cambios de IAM. Si no puede justificar un permiso, ese permiso no debe llegar a producción sin revisión.

Prueba la API y lee logs

Obtén la URL desde CloudFormation y prueba las rutas.

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"}'

Sigue los logs de Lambda:

aws logs tail "/aws/lambda/claude-code-small-api-prod" \
  --since 1h \
  --follow

CloudWatch Logs puede tardar unos minutos. Un retraso corto no significa que el despliegue haya fallado.

Despliega con GitHub Actions y OIDC

No guardes AWS Access Keys en GitHub Secrets. Crea un proveedor OIDC y un rol de despliegue en AWS, y limita el trust policy al repositorio y rama correctos.

{
  "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: eu-west-1

      - run: npm ci
      - run: npm test
      - run: npx cdk synth
      - run: npx cdk diff SmallApiProdStack
      - run: npx cdk deploy SmallApiProdStack --require-approval never

La política del rol de despliegue depende de tu modelo de bootstrap de CDK, el rol de ejecución de CloudFormation y las reglas de tu organización. Evita AdministratorAccess en producción. Una opción práctica es restringir el trust OIDC, usar permission boundaries si aplica y reducir permisos con IAM Access Analyzer cuando el workload se estabilice.

Añade guardrails de coste

Una API serverless pequeña también puede generar costes por bucles, spam o exceso de logs. El stack incluye throttling, usage plan y reserved concurrency. Añade AWS Budgets antes de producción.

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

Los presupuestos pueden tardar en reflejar gráficos o notificaciones. Configúralos antes del lanzamiento, no después de una sorpresa en la factura.

Rollback y fallos frecuentes

Para el primer servicio Lambda + API Gateway, el rollback más claro suele ser revertir el commit malo y redesplegar.

git revert <bad-commit-sha>
git push origin main

Después verifica API, eventos de CloudFormation y 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

Tres fallos aparecen mucho. Primero, alguien modifica recursos en la consola después de desplegar con CDK y el diff deja de ser fiable. Segundo, se filtran secretos en variables de entorno o logs. Tercero, se activa tracing de cuerpos de petición en API Gateway y se guardan datos sensibles. Este stack usa dataTraceEnabled: false, pero la revisión humana sigue siendo necesaria.

Pide una revisión predespliegue

Claude Code puede revisar, pero pídele evidencia.

Haz una revisión predespliegue de AWS.
Comprueba:
- Si el CDK diff añade wildcards IAM excesivos
- Si Lambda lee secretos solo desde Secrets Manager
- Si API Gateway tiene throttling, usage plan y logging
- Si CloudWatch Logs puede exponer datos personales o cuerpos completos
- Si los pasos de rollback están documentados
- Si npm test, cdk synth y cdk diff pasaron

Devuelve una tabla con severity, file, line y fix.

Claude Code no es el aprobador final de producción. Las fronteras de cuenta, el coste y las excepciones de seguridad son responsabilidad humana. Su utilidad está en hacer repetible la revisión y reducir errores repetidos.

Resumen

El valor de Claude Code en despliegues AWS no es solo generar CDK más rápido. Es convertir arquitectura, IaC, CI/CD, IAM, secretos, logs, rollback y coste en un flujo repetible.

Para una API pequeña, Lambda + API Gateway + CDK suele ser suficiente. Pasa a ECS/Fargate cuando realmente necesites contenedores siempre activos. Usa S3 + CloudFront o Amplify cuando el workload sea principalmente frontend estático. Mantén el primer límite pequeño, revisable y reversible.

Si tu equipo quiere diseñar reglas de Claude Code, despliegue CDK, GitHub Actions OIDC, IAM mínimo y checks operativos para un repositorio real, reserva una sesión de consultoría de Claude Code. Masa puede revisar tu repositorio y el historial de despliegues AWS para convertirlo en un plan implementable.

En la práctica, una API de captación de leads como esta puede quedar lista en medio día o un día si la cuenta AWS ya está preparada. Lo más delicado no es el código Lambda, sino IAM, secretos, rollback y visibilidad de costes. Deja que Claude Code acelere la implementación, pero conserva la responsabilidad humana sobre el riesgo de producción.

#Claude Code #AWS deployment #CDK #Lambda #GitHub Actions #IAM
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.