Jonatan Matajonmatum.com
conceptosnotasexperimentosensayos
© 2026 Jonatan Mata. All rights reserved.v2.1.1
Conceptos

AWS CDK

Framework de infraestructura como código de AWS que permite definir recursos cloud usando lenguajes de programación como TypeScript, Python o Java, generando CloudFormation.

evergreen#aws#cdk#iac#typescript#cloudformation#devops

¿Qué es?

AWS CDK (Cloud Development Kit) es un framework de infraestructura como código que permite definir recursos AWS usando lenguajes de programación familiares como TypeScript, Python, Java, C# y Go. A diferencia de CloudFormation que usa YAML/JSON, CDK aprovecha las capacidades de los lenguajes de programación para crear abstracciones reutilizables, aplicar lógica condicional y realizar validaciones en tiempo de compilación.

El framework funciona sintetizando el código a plantillas de CloudFormation que luego se despliegan usando el motor nativo de AWS. Esta arquitectura permite mantener la robustez y características de CloudFormation (rollbacks automáticos, drift detection, stack dependencies) mientras se obtienen los beneficios de programación imperativa.

CDK introduce el concepto de «constructs» — componentes reutilizables que encapsulan uno o más recursos AWS con configuraciones predeterminadas sensatas. Estos constructs van desde mapeos directos de recursos CloudFormation hasta patrones arquitectónicos completos que configuran múltiples servicios con las mejores prácticas integradas.

Jerarquía de constructs

CDK organiza los constructs en tres niveles de abstracción que determinan el grado de control versus conveniencia:

NivelNombreDescripciónEjemploCaso de uso
L1CFN ResourcesMapeo 1:1 con CloudFormationCfnBucket, CfnFunctionControl granular, recursos nuevos
L2AWS ConstructsAbstracciones con defaultss3.Bucket, lambda.FunctionDesarrollo productivo
L3PatternsArquitecturas completasLambdaRestApi, ApplicationLoadBalancedFargateServicePatrones comunes

Los constructs L2 son el punto óptimo para la mayoría de casos — proporcionan defaults sensatos (cifrado habilitado, políticas IAM mínimas) mientras mantienen flexibilidad de configuración. Los constructs L3 implementan patrones arquitectónicos completos pero pueden ser demasiado rígidos para casos específicos.

Ejemplo de stack completo

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 { Construct } from 'constructs';
 
export class UserServiceStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
 
    // DynamoDB table con configuración de producción
    const userTable = new dynamodb.Table(this, 'UserTable', {
      tableName: 'users',
      partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      encryption: dynamodb.TableEncryption.AWS_MANAGED,
      pointInTimeRecovery: true,
      removalPolicy: cdk.RemovalPolicy.RETAIN,
    });
 
    // Lambda function con configuración optimizada
    const userHandler = new lambda.Function(this, 'UserHandler', {
      runtime: lambda.Runtime.NODEJS_20_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'),
      environment: {
        TABLE_NAME: userTable.tableName,
      },
      timeout: cdk.Duration.seconds(30),
      memorySize: 512,
      tracing: lambda.Tracing.ACTIVE,
    });
 
    // Permisos granulares para DynamoDB
    userTable.grantReadWriteData(userHandler);
 
    // API Gateway con configuración de producción
    const api = new apigateway.RestApi(this, 'UserApi', {
      restApiName: 'User Service API',
      description: 'API for user management',
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS,
        allowMethods: apigateway.Cors.ALL_METHODS,
      },
      deployOptions: {
        stageName: 'prod',
        throttlingRateLimit: 1000,
        throttlingBurstLimit: 2000,
        loggingLevel: apigateway.MethodLoggingLevel.INFO,
      },
    });
 
    const users = api.root.addResource('users');
    users.addMethod('GET', new apigateway.LambdaIntegration(userHandler));
    users.addMethod('POST', new apigateway.LambdaIntegration(userHandler));
 
    const userById = users.addResource('{userId}');
    userById.addMethod('GET', new apigateway.LambdaIntegration(userHandler));
    userById.addMethod('PUT', new apigateway.LambdaIntegration(userHandler));
    userById.addMethod('DELETE', new apigateway.LambdaIntegration(userHandler));
 
    // Outputs para integración con otros stacks
    new cdk.CfnOutput(this, 'ApiUrl', {
      value: api.url,
      description: 'URL of the User API',
    });
 
    new cdk.CfnOutput(this, 'TableName', {
      value: userTable.tableName,
      description: 'Name of the DynamoDB table',
    });
  }
}

CDK vs Terraform: comparación detallada

AspectoAWS CDKTerraform
LenguajesTypeScript, Python, Java, C#, GoHCL (HashiCorp Configuration Language)
ProveedoresSolo AWS (nativo)Multi-cloud (AWS, Azure, GCP, etc.)
EstadoGestionado por CloudFormationArchivo de estado local/remoto
AbstraccionesConstructs L1/L2/L3 nativosMódulos de comunidad
TestingUnit tests nativos del lenguajeTerratest, kitchen-terraform
IDE SupportIntelliSense completoExtensiones HCL
Curva de aprendizajeFamiliar para desarrolladoresDSL específico
RollbacksAutomáticos via CloudFormationManuales o via CI/CD
Drift detectionNativo en CloudFormationTerraform plan
EcosistemaConstructs Hub, CDK PatternsTerraform Registry

Ruta de migración Terraform → CDK

Para equipos considerando migrar de Terraform a CDK:

  1. Evaluación: Identificar stacks que se beneficiarían de abstracciones programáticas
  2. Piloto: Migrar un stack pequeño y no crítico primero
  3. Coexistencia: Usar CDK para nuevos recursos, mantener Terraform para existentes
  4. Migración gradual: Usar cdk import para importar recursos existentes
  5. Consolidación: Refactorizar usando constructs L2/L3 para reducir boilerplate

Testing con CDK

CDK permite testing unitario real usando frameworks del lenguaje:

import { Template, Match } from 'aws-cdk-lib/assertions';
import { UserServiceStack } from '../lib/user-service-stack';
import { App } from 'aws-cdk-lib';
 
test('DynamoDB table created with correct configuration', () => {
  const app = new App();
  const stack = new UserServiceStack(app, 'TestStack');
  const template = Template.fromStack(stack);
 
  template.hasResourceProperties('AWS::DynamoDB::Table', {
    BillingMode: 'PAY_PER_REQUEST',
    SSESpecification: {
      SSEEnabled: true,
    },
    PointInTimeRecoverySpecification: {
      PointInTimeRecoveryEnabled: true,
    },
  });
});
 
test('Lambda has correct environment variables', () => {
  const app = new App();
  const stack = new UserServiceStack(app, 'TestStack');
  const template = Template.fromStack(stack);
 
  template.hasResourceProperties('AWS::Lambda::Function', {
    Environment: {
      Variables: {
        TABLE_NAME: { Ref: Match.stringLikeRegexp('UserTable') },
      },
    },
  });
});

Patrones avanzados

Cross-stack references

// Stack de base de datos
export class DatabaseStack extends cdk.Stack {
  public readonly userTable: dynamodb.Table;
 
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    this.userTable = new dynamodb.Table(this, 'UserTable', {
      // configuración...
    });
  }
}
 
// Stack de API que consume la base de datos
export class ApiStack extends cdk.Stack {
  constructor(scope: Construct, id: string, 
              databaseStack: DatabaseStack, 
              props?: cdk.StackProps) {
    super(scope, id, props);
 
    const handler = new lambda.Function(this, 'Handler', {
      environment: {
        TABLE_NAME: databaseStack.userTable.tableName,
      },
      // configuración...
    });
 
    databaseStack.userTable.grantReadWriteData(handler);
  }
}

Custom constructs reutilizables

export interface ApiLambdaProps {
  tableName: string;
  timeout?: cdk.Duration;
  memorySize?: number;
}
 
export class ApiLambda extends Construct {
  public readonly function: lambda.Function;
  public readonly api: apigateway.RestApi;
 
  constructor(scope: Construct, id: string, props: ApiLambdaProps) {
    super(scope, id);
 
    this.function = new lambda.Function(this, 'Function', {
      runtime: lambda.Runtime.NODEJS_20_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'),
      environment: { TABLE_NAME: props.tableName },
      timeout: props.timeout ?? cdk.Duration.seconds(30),
      memorySize: props.memorySize ?? 512,
    });
 
    this.api = new apigateway.LambdaRestApi(this, 'Api', {
      handler: this.function,
      proxy: false,
    });
  }
}

¿Por qué importa?

CDK representa un cambio paradigmático en infraestructura como código al eliminar la barrera artificial entre código de aplicación e infraestructura. Para equipos de ingeniería senior, esto significa poder aplicar las mismas prácticas de desarrollo — testing unitario, refactoring, abstracciones, composición — a la definición de infraestructura.

La capacidad de crear constructs reutilizables permite establecer «golden paths» organizacionales que encapsulan mejores prácticas de seguridad, observabilidad y costo. Un construct L3 personalizado puede garantizar que todas las APIs incluyan logging estructurado, métricas CloudWatch, y políticas IAM mínimas sin requerir conocimiento experto de cada desarrollador.

El modelo de testing nativo elimina la necesidad de herramientas externas como Terratest, permitiendo TDD real para infraestructura. Esto es especialmente valioso en organizaciones que priorizan calidad de código y cobertura de testing. La integración con IDEs proporciona autocompletado, detección de errores en tiempo real, y refactoring automático — capacidades imposibles con DSLs como HCL o YAML.

Referencias

  • AWS Cloud Development Kit (AWS CDK) v2 — AWS, 2024. Documentación oficial completa.
  • CDK Best Practices — AWS, 2024. Guía de mejores prácticas oficiales.
  • Construct Hub — AWS, 2024. Repositorio de constructs reutilizables.
  • CDK Patterns — Matt Coulter, 2024. Patrones arquitectónicos con CDK.
  • Test AWS CDK Applications — AWS, 2024. Guía oficial de testing.
  • CDK Workshop — AWS, 2024. Tutorial interactivo oficial.

Contenido relacionado

  • Infrastructure as Code

    Práctica de definir y gestionar infraestructura mediante archivos de configuración versionados en lugar de procesos manuales. Fundamento de la automatización moderna de operaciones.

  • TypeScript

    Superset tipado de JavaScript que añade tipos estáticos opcionales, mejorando la productividad del desarrollador, la detección de errores y la mantenibilidad del código.

  • AWS CloudFormation

    Servicio nativo de AWS para definir y aprovisionar infraestructura como código usando plantillas YAML o JSON, con gestión de estado y rollback automático.

Conceptos