

Esta es la guía para desarrolladores de AWS CDK v2. La primera versión del CDK pasó a la etapa de mantenimiento el 1.° de junio de 2022 y no cuenta con soporte desde el 1.° de junio de 2023.

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Implementar aplicaciones de AWS CDK
<a name="deploy"></a>

Una implementación de AWS Cloud Development Kit (AWS CDK) es el proceso de aprovisionamiento de la infraestructura de AWS.

## Funcionamiento de las implementaciones de AWS CDK
<a name="deploy-how"></a>

El AWS CDK utiliza el servicio de AWS CloudFormation para realizar implementaciones. Antes de la implementación, se sintetizan las pilas de CDK. Esto crea una plantilla de CloudFormation y artefactos de implementación para cada pila de CDK de la aplicación. Las implementaciones se inician desde una máquina de desarrollo local o desde un entorno de *integración y entrega continuas (CI/CD)*. Durante la implementación, los activos se cargan en los recursos de inicio y la plantilla de CloudFormation se envía a CloudFormation para aprovisionar los recursos de AWS.

Para que la implementación se realice correctamente, se requiere lo siguiente:
+ La interfaz de línea de comandos de AWS CDK (CLI de AWS CDK) debe contar con permisos válidos.
+ El entorno de AWS debe estar iniciado.
+ El AWS CDK debe conocer los recursos de inicio en los que cargar los activos.

## Requisitos previos para las implementaciones de CDK
<a name="deploy-prerequisites"></a>

Antes de poder implementar una aplicación de AWS CDK, debe ejecutar los siguientes pasos:
+ Configure las credenciales de seguridad para la CLI de CDK.
+ Inicie su entorno de AWS.
+ Configure un entorno de AWS para cada una de sus pilas de CDK.
+ Desarrolle su aplicación de CDK.<a name="deploy-prerequisites-creds"></a>

 **Configuración de credenciales de seguridad**   
Para utilizar la CLI del CDK a la hora de interactuar con AWS, debe configurar las credenciales de seguridad en su máquina local. Consulte [Configurar las credenciales de seguridad para la CLI de AWS CDK](configure-access.md) para obtener instrucciones.<a name="deploy-prerequisites-bootstrap"></a>

 **Arranque su entorno de AWS**   
Una implementación siempre está asociada a uno o más [entornos](environments.md) de AWS. Antes de poder realizar la implementación, primero se debe [iniciar](bootstrapping.md) el entorno. El inicio aprovisiona recursos en su entorno que el CDK utiliza para realizar y gestionar las implementaciones. Estos recursos incluyen un bucket de Amazon Simple Storage Service (Amazon S3) y un repositorio de Amazon Elastic Container Registry (Amazon ECR) para almacenar y administrar los [activos](assets.md). Estos recursos también incluyen roles de AWS Identity and Access Management (IAM) que se utilizan para proporcionar permisos durante el desarrollo y la implementación.  
Le recomendamos que utilice el comando de la AWSinterfaz de línea de comandos del `cdk bootstrap` CDK (la CLI de AWS CDK) para iniciar el entorno. Si es necesario, puede personalizar el inicio o crear estos recursos manualmente en su entorno. Para obtener instrucciones, consulte [Arranque su entorno para utilizarlo con el AWS CDK](bootstrapping-env.md).<a name="deploy-prerequisites-env"></a>

 **Configure los entornos de AWS**   
Cada pila del CDK debe estar asociada a un entorno para determinar dónde se implementa la pila. Para obtener instrucciones, consulte [Configurar entornos para usarlos con el AWS CDK](configure-env.md).<a name="deploy-prerequisites-develop"></a>

 **Desarrolle su aplicación del CDK**   
Dentro de un [proyecto](projects.md) de CDK, usted crea y desarrolla su aplicación de CDK. Dentro de la aplicación, se crean una o más [pilas](stacks.md) de CDK. Dentro de sus pilas, puede importar y usar [constructos](constructs.md) de la Biblioteca de constructos de AWS para definir su infraestructura. Antes de poder implementarla, la aplicación de CDK debe contener al menos una pila.

## Síntesis de aplicaciones del CDK
<a name="deploy-how-synth"></a>

Para realizar la síntesis, le recomendamos que utilice el comando `cdk synth` de la CLI del CDK. El comando `cdk deploy` también realizará una síntesis antes de iniciar la implementación. Sin embargo, usando `cdk synth`, puede validar su aplicación de CDK y detectar errores antes de iniciar la implementación.

El comportamiento de la síntesis está determinado por el [sintetizador de pila](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.html#stack-synthesizers) que configure para la pila del CDK. Si no configura un sintetizador, se utilizará ` [DefaultStackSynthesizer](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.DefaultStackSynthesizer.html) `. También puede configurar y personalizar la síntesis para que se adapte a sus necesidades. Consulte [Configurar y realizar la síntesis de pilas de CDK](configure-synth.md) para obtener instrucciones.

Para que la plantilla sintetizada de CloudFormation se implemente correctamente en su entorno, debe ser compatible con la forma en que se inició su entorno. Por ejemplo, la plantilla de CloudFormation debe especificar el bucket de Amazon S3 correcto en el que implementar los activos. Si utiliza el método predeterminado para iniciar su entorno, el sintetizador de pilas predeterminado funcionará. Si personaliza el comportamiento del CDK, por ejemplo, si personaliza el inicio o la síntesis, el comportamiento de implementación del CDK puede variar.<a name="deploy-how-synth-app"></a>

 **El ciclo de vida de la aplicación**   
Al realizar la síntesis, la aplicación del CDK pasa por las siguientes fases, conocidas como el *ciclo de vida de la aplicación*:    
 **Construcción (o inicialización)**   
El código crea instancias de todos los constructos definidos y, a continuación, los vincula entre sí. En esta etapa, se crean instancias de todos los constructos (aplicación, pilas y constructos secundarios) y se ejecuta la cadena de constructos. La mayor parte del código de la aplicación se ejecuta en esta etapa.  
 **Preparación**   
Todos los constructos que han implementado el método `prepare` participan en una ronda final de modificaciones para configurar su estado final. La fase de preparación se produce automáticamente. Como usuario, no ve ningún comentario de esta fase. Es poco frecuente que necesite usar el enlace de “prepare” y, por lo general, no se recomienda. Tenga mucho cuidado al mutar el árbol de constructos durante esta fase, ya que el orden de las operaciones podría afectar al comportamiento.  
Durante esta fase, una vez que se haya creado el árbol de constructos, también se aplicarán todos los [aspectos](aspects.md) que haya configurado.  
 **Validación**   
Todos los constructos que han implementado el método `validate` pueden validarse a sí mismos para garantizar que se encuentren en un estado que permita su correcta implementación. Se le notificará de cualquier error de validación que se produzca durante esta fase. Por lo general, le recomendamos que realice la validación lo antes posible (normalmente tan pronto como reciba información) y que descarte las excepciones lo antes posible. Realizar la validación de forma temprana mejora la fiabilidad, ya que los seguimientos de las pilas son más precisos y garantizan que el código pueda seguir ejecutándose de forma segura.  
 **Síntesis**   
Esta es la etapa final de la ejecución de la aplicación de CDK. Se activa con una llamada a `app.synth()`, recorre el árbol de constructos e invoca el método `synthesize` en todos los constructos. Los constructos que implementan `synthesize` pueden participar en la síntesis y producir artefactos de implementación para el montaje en la nube resultante. Estos artefactos incluyen plantillas de CloudFormation, paquetes de aplicaciones de AWS Lambda, activos de archivos e imágenes de Docket y otros artefactos de implementación. En la mayoría de los casos, no necesitará implementar el método `synthesize`.<a name="deploy-how-synth-run"></a>

 **Ejecute una aplicación**   
La CLI del CDK necesita saber cómo ejecutar su aplicación de CDK. Si creó el proyecto a partir de una plantilla mediante el comando `cdk init`, el archivo `cdk.json` de su aplicación incluye una clave de `app`. Esta clave especifica el comando necesario para el lenguaje en el que está escrita la aplicación. Si su lenguaje requiere compilación, la línea de comandos realiza este paso antes de ejecutar la aplicación automáticamente.  

**Example**  

```
{
  "app": "npx ts-node --prefer-ts-exts bin/my-app.ts"
}
```

```
{
  "app": "node bin/my-app.js"
}
```

```
{
    "app": "python app.py"
}
```

```
{
  "app": "mvn -e -q compile exec:java"
}
```

```
{
  "app": "dotnet run -p src/MyApp/MyApp.csproj"
}
```

```
{
  "app": "go mod download && go run my-app.go"
}
```
Si no creó su proyecto con la CLI de CDK o si desea anular la línea de comandos incluida en `cdk.json`, puede proporcionar la opción ` --app ` al ejecutar el comando `cdk`.

```
$ cdk --app '<executable>' <cdk-command> ...
```

La parte `<executable>` del comando indica el comando que debe ejecutarse para ejecutar la aplicación de CDK. Use las comillas como se muestra, ya que estos comandos contienen espacios. `<cdk-command>` es un subcomando similar a `synth` o `deploy` que le indica a la CLI del CDK lo que quiere hacer con su aplicación. Siga esto con cualquier opción adicional necesaria para ese subcomando.

La CLI de CDK también puede interactuar directamente con un montaje en la nube ya sintetizado. Para ello, pase el directorio en el que está almacenado el montaje en la nube en `--app`. En el siguiente ejemplo, se enumeran las pilas definidas en el montaje en la nube almacenado en `./my-cloud-assembly`.

```
$ cdk --app <./my-cloud-assembly> ls
```<a name="deploy-how-synth-assemblies"></a>

 **Montajes en la nube**   
La llamada a `app.synth()` es lo que le indica al AWS CDK que hay que sintetizar un montaje en la nube a partir de una aplicación. Por lo general, no se interactúa directamente con los montajes en la nube. Son archivos que incluyen todo lo necesario para implementar la aplicación en un entorno de nube. Por ejemplo, incluye una plantilla de AWS CloudFormation para cada pila de la aplicación. También incluye una copia de cualquier archivo, activo o imagen de Docker a los que haga referencia en su aplicación.  
Consulte la [especificación del montaje en la nube](https://github.com/aws/aws-cdk/blob/master/design/cloud-assembly.md) para obtener detalles sobre el formato de los montajes en la nube.  
Para interactuar con el montaje en la nube que crea su aplicación de AWS CDK, normalmente usará la CLI de AWS CDK. Sin embargo, se puede usar cualquier herramienta que pueda leer el formato del montaje en la nube para implementar su aplicación.

## Implementar la aplicación
<a name="deploy-how-deploy"></a>

Para implementar la aplicación, le recomendamos que utilice el comando `cdk deploy` de la CLI del CDK para iniciar las implementaciones o configurar las implementaciones automatizadas.

Cuando ejecuta `cdk deploy`, la CLI del CDK inicia `cdk synth` para prepararse para la implementación. En el siguiente diagrama, se ilustra el ciclo de vida de una aplicación en el contexto de una implementación:

![\[Diagrama de flujo del ciclo de vida de la aplicación de <shared id="AWS"/> CDK.\]](http://docs.aws.amazon.com/es_es/cdk/v2/guide/images/app-lifecycle_cdk-flowchart.png)


Durante la implementación, la CLI de CDK toma el montaje en la nube producido por la síntesis y lo implementa en un entorno de AWS. Los activos se cargan en Amazon S3 y Amazon ECR y la plantilla de CloudFormation se envía a AWS CloudFormation para su implementación.

Cuando comience la fase de implementación de AWS CloudFormation, su aplicación de CDK ya habrá terminado de ejecutarse y se habrá cerrado. Esto tiene las siguientes implicaciones:
+ La aplicación del CDK no puede responder a los eventos que se producen durante la implementación, como la creación de un recurso o la finalización de toda la implementación. Para ejecutar el código durante la fase de implementación, debe inyectarlo a la plantilla de AWS CloudFormation como un [recurso personalizado](cfn-layer.md#develop-customize-custom). Para obtener más información sobre cómo agregar un recurso personalizado a su aplicación, consulte el [módulo de AWS CloudFormation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudformation-readme.html) o el ejemplo del [recurso personalizado](https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/custom-resource/). También puede configurar el módulo [Triggers](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.triggers-readme.html) para que ejecute código durante las implementaciones.
+ Es posible que la aplicación del CDK tenga que funcionar con valores que no se pueden conocer al momento en que se ejecuta. Por ejemplo, si la aplicación de AWS CDK define un bucket de Amazon S3 con un nombre generado automáticamente y usted recupera el atributo `bucket.bucketName` (Python: `bucket_name`), ese valor no es el nombre del bucket implementado. En su lugar, se obtiene un valor de `Token`. Para determinar si un valor concreto está disponible, realice una llamada a `cdk.isUnresolved(value)` (Python: `is_unresolved`). Para obtener más información, consulte los [Tokens y el AWS CDK](tokens.md).<a name="deploy-how-deploy-permissions"></a>

 **Permisos de implementación**   
Antes de poder realizar la implementación, se deben establecer los permisos. El siguiente diagrama ilustra los permisos que se utilizan durante una implementación predeterminada, cuando se utiliza el proceso de inicio y el sintetizador de pilas predeterminados:  

![\[Diagrama de flujo del proceso de implementación de <shared id="AWS"/> CDK predeterminado.\]](http://docs.aws.amazon.com/es_es/cdk/v2/guide/images/default-deploy-process_cdk_flowchart.png)
  
 **Actor inicia la implementación**   
Un *actor* inicia las implementaciones mediante la CLI de CDK. Un actor puede ser una persona o un servicio como AWS CodePipeline.  
Si es necesario, la CLI de CDK ejecuta `cdk synth` cuando usted ejecute `cdk deploy`. Durante la síntesis, la identidad de AWS asume el rol `LookupRole` para realizar búsquedas de contexto en el entorno de AWS.  
 **Los permisos están establecidos**   
En primer lugar, las credenciales de seguridad del actor se utilizan para autenticarse con AWS y obtener la primera identidad de IAM del proceso. Para actores humanos, la forma en que configure las credenciales de seguridad depende de la forma en que usted o su organización administren los usuarios. Para obtener más información, [Configure las credenciales de seguridad para la CLI de AWS CDK](configure-access.md). Para los actores de servicio, como CodePipeline, se asume y utiliza un rol de ejecución de IAM.  
A continuación, los roles de IAM creados en el entorno de AWS durante el inicio se utilizan para establecer los permisos necesarios para realizar las acciones necesarias para la implementación. Para obtener más información acerca de los roles y sus permisos, consulte [Roles de IAM creados durante el arranque](bootstrapping-env.md#bootstrapping-env-roles). Este proceso consta de los pasos siguientes:  
+ La identidad de AWS asume el rol `DeploymentActionRole` y transfiere el rol `CloudFormationExecutionRole` a CloudFormation, lo que garantiza que CloudFormation asuma el rol cuando realice cualquier acción en su entorno de AWS. `DeploymentActionRole` otorga permiso para realizar implementaciones en su entorno y `CloudFormationExecutionRole` determina qué acciones puede realizar CloudFormation.
+ La identidad de AWS asume el rol `FilePublishingRole`, lo que determina las acciones que se pueden realizar en el bucket de Amazon S3 creado durante el inicio.
+ La identidad de AWS asume el rol `ImagePublishingRole`, lo que determina las acciones que se pueden realizar en el repositorio de Amazon ECR creado durante el inicio.
+ Durante la síntesis, la identidad de AWS asume el rol `LookupRole` para realizar búsquedas de contexto en el entorno de AWS. Esta acción también se puede realizar durante la síntesis de plantillas.  
 **Se realiza la implementación**   
Durante la implementación, la CLI de CDK lee el parámetro de la versión de inicio para confirmar el número de versión de inicio. AWS CloudFormation también lee este parámetro al momento de la implementación para confirmarlo. Si los permisos en todo el flujo de trabajo de implementación son válidos, se realiza la implementación. Los activos se cargan en los recursos de inicio y la plantilla de CloudFormation producida en la síntesis se implementa mediante el servicio de CloudFormation como una pila de CloudFormation para aprovisionar los recursos.

# Validación de políticas de AWS CDK en el momento de la síntesis
<a name="policy-validation-synthesis"></a>

## Validación de políticas en el momento de la síntesis
<a name="policy-validation"></a>

Si usted o su organización utilizan alguna herramienta de validación de políticas, como [AWS CloudFormation Guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) u [OPA](https://www.openpolicyagent.org/), para definir las restricciones en su plantilla de AWS CloudFormation, puede integrarlas en el AWS CDK en el momento de la síntesis. Al utilizar el complemento de validación de políticas adecuado, puede hacer que la aplicación de AWS CDK compare la plantilla de AWS CloudFormation generada con sus políticas inmediatamente después de la síntesis. Si se produce alguna infracción, la síntesis fallará y se imprimirá un informe en la consola.

La validación realizada por el AWS CDK en el momento de la síntesis valida los controles en un momento del ciclo de vida de la implementación, pero no puede afectar a las acciones que se producen fuera de la síntesis. Entre los ejemplos se incluyen las acciones que se toman directamente en la consola o mediante las API de servicio. No son resistentes a la alteración de las plantillas de AWS CloudFormation después de la síntesis. Algún otro mecanismo para validar el mismo conjunto de reglas con más autoridad debería configurarse de forma independiente, como los [enlaces de AWS CloudFormation](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks.html) o [AWS Config](https://docs.aws.amazon.com/config/latest/developerguide/WhatIsConfig.html). Sin embargo, la capacidad del AWS CDK de evaluar el conjunto de reglas durante el desarrollo sigue siendo útil, ya que mejorará la velocidad de detección y la productividad de los desarrolladores.

El objetivo de la validación de las políticas de AWS CDK es minimizar la cantidad de configuración necesaria durante el desarrollo y hacerlo lo más fácil posible.

**nota**  
Esta característica se considera experimental y tanto la API del complemento como el formato del informe de validación están sujetos a cambios en el futuro.

## Para desarrolladores de aplicaciones
<a name="for-application-developers"></a>

Para usar uno o más complementos de validación en su aplicación, use la propiedad `policyValidationBeta1` de `Stage`:

```
import { CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';
const app = new App({
  policyValidationBeta1: [
    new CfnGuardValidator()
  ],
});
// only apply to a particular stage
const prodStage = new Stage(app, 'ProdStage', {
  policyValidationBeta1: [...],
});
```

Inmediatamente después de la síntesis, se invocarán todos los complementos registrados de esta manera para validar todas las plantillas generadas en el ámbito que haya definido. En concreto, si registra las plantillas en el objeto `App`, todas las plantillas estarán sujetas a validación.

**aviso**  
Además de modificar el ensamblaje de la nube, los complementos pueden hacer cualquier cosa que pueda hacer su aplicación de AWS CDK. Pueden leer datos del sistema de archivos, acceder a la red, etc. Como consumidor de un complemento, es su responsabilidad comprobar que su uso es seguro.

### Complemento de AWS CloudFormation Guard
<a name="cfnguard-plugin"></a>

El uso del complemento [https://github.com/cdklabs/cdk-validator-cfnguard](https://github.com/cdklabs/cdk-validator-cfnguard) le permite usar [AWS CloudFormation Guard](https://github.com/aws-cloudformation/cloudformation-guard) para realizar validaciones de políticas. El complemento `CfnGuardValidator` viene con un conjunto selecto de [controles AWS Control Tower proactivos](https://docs.aws.amazon.com/controltower/latest/userguide/proactive-controls.html) integrados. El conjunto de reglas actual se encuentra en la [documentación del proyecto](https://github.com/cdklabs/cdk-validator-cfnguard/blob/main/README.md). Como se mencionó en [Validación de políticas al momento de la síntesis](#policy-validation), recomendamos que las organizaciones establezcan un método de validación más fiable mediante [enlaces de AWS CloudFormation](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks.html).

Para los clientes [AWS Control Tower](https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html), estos mismos controles proactivos se pueden implementar en toda la organización. Cuando habilita controles proactivos de AWS Control Tower en su entorno de AWS Control Tower, los controles pueden detener la implementación de los recursos no conformes que se implementen a través de AWS CloudFormation. Para obtener más información sobre los controles proactivos administrados y su funcionamiento, consulte la [documentación de AWS Control Tower](https://docs.aws.amazon.com/controltower/latest/userguide/proactive-controls.html).

Es mejor utilizar estos controles de AWS CDK agrupados y los controles de AWS Control Tower proactivos administrados juntos. En este escenario, puede configurar este complemento de validación con los mismos controles proactivos que están activos en su entorno de nube de AWS Control Tower. De este modo, podrá confiar rápidamente en que su aplicación de AWS CDK superará los controles de AWS Control Tower ejecutando `cdk synth` de manera local.

### Informe de validación
<a name="validation-report"></a>

Al sintetizar la aplicación de AWS CDK, se llamarán los complementos de validación y se imprimirán los resultados. A continuación, se muestra un ejemplo de informe.

```
Validation Report (CfnGuardValidator)
-------------------------------------
(Summary)
╔═══════════╤════════════════════════╗
║ Status    │ failure                ║
╟───────────┼────────────────────────╢
║ Plugin    │ CfnGuardValidator      ║
╚═══════════╧════════════════════════╝
(Violations)
Ensure S3 Buckets are encrypted with a KMS CMK (1 occurrences)
Severity: medium
  Occurrences:

    - Construct Path: MyStack/MyCustomL3Construct/Bucket
    - Stack Template Path: ./cdk.out/MyStack.template.json
    - Creation Stack:
        └──  MyStack (MyStack)
             │ Library: aws-cdk-lib.Stack
             │ Library Version: 2.50.0
             │ Location: Object.<anonymous> (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:25:20)
             └──  MyCustomL3Construct (MyStack/MyCustomL3Construct)
                  │ Library: N/A - (Local Construct)
                  │ Library Version: N/A
                  │ Location: new MyStack (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:15:20)
                  └──  Bucket (MyStack/MyCustomL3Construct/Bucket)
                       │ Library: aws-cdk-lib/aws-s3.Bucket
                       │ Library Version: 2.50.0
                       │ Location: new MyCustomL3Construct (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:9:20)
    - Resource Name: amzn-s3-demo-bucket
    - Locations:
      > BucketEncryption/ServerSideEncryptionConfiguration/0/ServerSideEncryptionByDefault/SSEAlgorithm
  Recommendation: Missing value for key `SSEAlgorithm` - must specify `aws:kms`
  How to fix:
    > Add to construct properties for `cdk-app/MyStack/Bucket`
      `encryption: BucketEncryption.KMS`

Validation failed. See above reports for details
```

De forma predeterminada, el informe se imprimirá en un formato legible para las personas. Si desea un informe en formato JSON, habilítelo mediante `@aws-cdk/core:validationReportJson` a través de la CLI o pasándolo directamente a la aplicación:

```
const app = new App({
  context: { '@aws-cdk/core:validationReportJson': true },
});
```

Como alternativa, puede establecer este par clave-valor del contexto mediante los archivos `cdk.json` o `cdk.context.json` del directorio de su proyecto (consulte [Valores de contexto y el AWS CDK](context.md)).

Si elige el formato JSON, el AWS CDK imprimirá el informe de validación de políticas en un archivo llamado `policy-validation-report.json` en el directorio de ensamblaje de la nube. En el formato predeterminado, legible por humanos, el informe se imprimirá en la salida estándar.

## Para los autores de complementos
<a name="plugin-authors"></a>

### Complementos
<a name="plugins"></a>

El marco principal del AWS CDK es responsable de registrar e invocar los complementos y, a continuación, mostrar el informe de validación formateado. La responsabilidad del complemento es actuar como capa de traducción entre el marco del AWS CDK y la herramienta de validación de políticas. Se puede crear un complemento en cualquier idioma compatible con AWS CDK. Si va a crear un complemento que se pueda utilizar en varios lenguajes, le recomendamos que lo cree el complemento en `TypeScript`; así puede usar JSII para publicarlo en cada lenguaje del AWS CDK.

### Creación de complementos
<a name="creating-plugins"></a>

La interfaz `IPolicyValidationPluginBeta1` define el protocolo de comunicación entre el módulo principal del AWS CDK y la herramienta de políticas. Para crear un nuevo complemento, debe escribir una clase que implemente esta interfaz. Hay dos cosas que debe implementar: el nombre del complemento (anulando la propiedad `name`) y el método `validate()`.

El marco llamará a `validate()` y pasará un objeto `IValidationContextBeta1`. `templatePaths` da la ubicación de las plantillas a validar. El complemento debería devolver una instancia de `ValidationPluginReportBeta1`. Este objeto representa el informe que recibirá el usuario al final de la síntesis.

```
validate(context: IPolicyValidationContextBeta1): PolicyValidationReportBeta1 {
  // First read the templates using context.templatePaths...
  // ...then perform the validation, and then compose and return the report.
  // Using hard-coded values here for better clarity:
  return {
    success: false,
    violations: [{
      ruleName: 'CKV_AWS_117',
      description: 'Ensure that AWS Lambda function is configured inside a VPC',
      fix: 'https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1',
      violatingResources: [{
        resourceName: 'MyFunction3BAA72D1',
        templatePath: '/home/johndoe/myapp/cdk.out/MyService.template.json',
        locations: 'Properties/VpcConfig',
      }],
    }],
  };
}
```

Tenga en cuenta que los complementos no pueden modificar nada en el ensamblaje de la nube. Cualquier intento de hacerlo provocará un fallo en la síntesis.

Si su complemento depende de una herramienta externa, tenga en cuenta que es posible que algunos desarrolladores aún no tengan esa herramienta instalada en sus estaciones de trabajo. Para minimizar la fricción, le recomendamos que proporcione algún script de instalación junto con su paquete de complementos, para automatizar todo el proceso. Mejor aún, ejecute ese script como parte de la instalación de su paquete. Con `npm`, por ejemplo, puede agregarlo al [script](https://docs.npmjs.com/cli/v9/using-npm/scripts) `postinstall` del archivo `package.json`.

### Tratamiento de excepciones
<a name="handling-exemptions"></a>

Si su organización tiene un mecanismo para administrar las exenciones, puede implementarlo como parte del complemento de validación.

Un ejemplo de escenario para ilustrar un posible mecanismo de exención:
+ Una organización tiene una norma según la cual no se permiten los buckets públicos de Amazon S3, *excepto* en determinadas situaciones.
+ Un desarrollador está creando un bucket de Amazon S3 que se encuadra en uno de esos escenarios y solicita una exención (por ejemplo, crear un ticket).
+ Las herramientas de seguridad saben cómo leer el sistema interno que registra las exenciones

En este escenario, el desarrollador solicitaría una excepción en el sistema interno y luego necesitaría alguna forma de “registrar” esa excepción. Si agregamos el ejemplo del complemento guard, podría crear un complemento que administre las exenciones filtrando las infracciones que cuenten con una exención equivalente en un sistema interno de venta de entradas.

Consulte los complementos existentes para ver ejemplos de implementaciones.
+  [@cdklabs /cdk-validator-cfnguard](https://github.com/cdklabs/cdk-validator-cfnguard) 

# Integración y entrega continuas (CI/CD) con CDK Pipelines
<a name="cdk-pipeline"></a>

Utilice el módulo [CDK Pipelines](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html) de la Biblioteca de constructos de AWS para configurar la entrega continua de aplicaciones del AWS CDK. Al publicar el código fuente de la aplicación de CDK en AWS CodeCommit, GitHub o AWS CodeStar, CDK Pipelines puede crear, probar e implementar automáticamente la nueva versión.

CDK Pipelines se actualiza automáticamente. Si agrega etapas o pilas de aplicaciones, la canalización se reconfigura automáticamente para implementar esas nuevas etapas o pilas.

**nota**  
CDK Pipelines admite dos API. Una es la API original que estaba disponible en la versión preliminar para desarrolladores de CDK Pipelines. La otra es una API moderna que incorpora los comentarios de los clientes de CDK recibidos durante la fase preliminar. En los ejemplos de este tema, se utiliza la API moderna. Para obtener más información sobre las diferencias entre las dos API compatibles, consulte [API original de CDK Pipelines](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/pipelines/ORIGINAL_API.md) en el *repositorio aws-cdk de GitHub*.

## Inicie sus entornos de AWS
<a name="cdk-pipeline-bootstrap"></a>

Antes de poder utilizar CDK Pipelines, debe iniciar el [entorno](environments.md) de AWS en el que implementará sus pilas.

Una canalización de CDK incluye al menos dos entornos. El primer entorno es donde se aprovisiona la canalización. El segundo entorno es donde desea implementar las pilas o etapas de la aplicación (las etapas son grupos de pilas relacionadas). Estos entornos pueden ser los mismos, pero una práctica recomendada es aislar las etapas entre sí en entornos diferentes.

**nota**  
Consulte [Arranque de AWS CDK](bootstrapping.md) para obtener más información sobre los tipos de recursos que se crean mediante el inicio y sobre cómo personalizar la pila de arranque.

La implementación continua con CDK Pipelines requiere que se incluya lo siguiente en la pila de CDK Toolkit:
+ Un bucket de Amazon Simple Storage Service (Amazon S3)
+ Un repositorio de Amazon ECR.
+ Los roles de IAM se utilizan para otorgar a las distintas partes de una canalización los permisos que necesitan.

El Kit de herramientas de CDK actualizará su pila de arranque existente o creará una nueva si es necesario.

Para iniciar un entorno que pueda aprovisionar una canalización de AWS CDK, invoque `cdk bootstrap` como se muestra en el siguiente ejemplo. Si se invoca el Kit de herramientas de AWS CDK mediante el comando `npx`, se instala temporalmente si es necesario. También utilizará la versión del Kit de herramientas instalada en el proyecto actual, si la hay.

 `--cloudformation-execution-policies` especifica el ARN de una política según la cual se ejecutarán las implementaciones de CDK Pipelines en el futuro. La política predeterminada de `AdministratorAccess` garantiza que su canalización pueda implementar todos los tipos de recursos de AWS. Si utiliza esta política, asegúrese de confiar en todo el código y las dependencias que compongan su aplicación de AWS CDK.

La mayoría de las organizaciones exigen controles más estrictos sobre los tipos de recursos que se pueden implementar mediante la automatización. Consulte con el departamento correspondiente de su organización para determinar la política que debe utilizar su canalización.

Puede omitir la opción `--profile` si su perfil predeterminado de AWS contiene la configuración de autenticación y la región de AWS necesarias.

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER></REGION> --profile< ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

Para iniciar entornos adicionales en los que la canalización implementará las aplicaciones del AWS CDK, utilice los siguientes comandos en su lugar. La opción `--trust` indica qué otra cuenta debe tener permisos para implementar aplicaciones del AWS CDK en este entorno. Para esta opción, especifique el nombre de usuario de la cuenta de AWS de la canalización.

Una vez más, puede omitir la opción `--profile` si su perfil predeterminado de AWS contiene la configuración de autenticación y la región de AWS necesarias.

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess ^
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

**sugerencia**  
Utilice las credenciales administrativas únicamente para iniciar y aprovisionar la canalización inicial. Después, utilice la propia canalización, no su máquina local, para implementar los cambios.

Si va a actualizar un entorno de arranque heredado, el bucket anterior de Amazon S3 quedará huérfano cuando se cree el nuevo bucket. Elimínelo con la consola de Amazon S3 de manera manual.

### Proteja su pila de arranque para que no se elimine
<a name="cdk-pipeline-protect"></a>

Si se elimina una pila de arranque, también se eliminarán los recursos de AWS que se aprovisionaron originalmente en el entorno para respaldar las implementaciones del CDK. Esto hará que la canalización deje de funcionar. Si esto sucede, no existe una solución general para la recuperación.

Una vez que se arranque el entorno, no elimine ni vuelva a crear la pila de arranque del entorno. En su lugar, intente actualizar la pila de arranque a una nueva versión ejecutando el comando `cdk bootstrap` de nuevo.

Para evitar que se elimine accidentalmente la pila de arranque, le recomendamos que proporcione la opción `--termination-protection` junto con el comando `cdk bootstrap` para habilitar la protección contra la terminación. Puede habilitar la protección contra la terminación en pilas de arranque nuevas o existentes. Para obtener más información sobre esta opción, consulte ` --termination-protection `.

Tras activar la protección contra la terminación, puede utilizar la AWS CLI o la consola de CloudFormation para realizar la verificación.

1. Ejecute el siguiente comando para habilitar la protección de terminación en una pila de arranque nueva o existente:

   ```
   $ cdk bootstrap --termination-protection
   ```

1. Utilice la AWS CLI o la consola de CloudFormation verificarlo. A continuación se muestra un ejemplo del uso de la AWS CLI. Si modificó el nombre de la pila de arranque, sustituya `CDKToolkit` por el nombre de la pila:

   ```
   $ aws cloudformation describe-stacks --stack-name <CDKToolkit> --query "Stacks[0].EnableTerminationProtection"
   true
   ```

## Inicie un proyecto
<a name="cdk-pipeline-init"></a>

Cree un proyecto nuevo y vacío de GitHub y clónelo en su estación de trabajo en el directorio de `my-pipeline`. (Nuestros ejemplos de código en este tema usan GitHub. También puede usar AWS CodeStar o AWS CodeCommit).

```
git clone <GITHUB-CLONE-URL> my-pipeline
cd my-pipeline
```

**nota**  
Puede utilizar un nombre que no sea `my-pipeline` para el directorio principal de la aplicación. Sin embargo, si lo hace, tendrá que modificar los nombres de los archivos y las clases más adelante en este tema. Esto se debe a que el Kit de herramientas de AWS CDK basa algunos nombres de archivos y clases en el nombre del directorio principal.

Después de la clonación, inicialice el proyecto normalmente.

**Example**  

```
$ cdk init app --language typescript
```

```
$ cdk init app --language javascript
```

```
$ cdk init app --language python
```
Una vez creada la aplicación, ingrese también los siguientes dos comandos. Estos activan el entorno virtual de Python de la aplicación e instalan las dependencias principales de AWS CDK.  

```
$ source .venv/bin/activate # On Windows, run `.\venv\Scripts\activate` instead
$ python -m pip install -r requirements.txt
```

```
$ cdk init app --language java
```
Si utiliza un IDE, ahora puede abrir o importar el proyecto. Por ejemplo, en Eclipse, elija **Archivo** > **Importar** > **Maven** > **Proyectos de Maven existentes**. Asegúrese de que la configuración del proyecto esté configurada para utilizar Java 8 (1.8).

```
$ cdk init app --language csharp
```
Si utiliza Visual Studio, abra el archivo de la solución en el directorio `src`.

```
$ cdk init app --language go
```
Una vez creada la aplicación, introduzca también el siguiente comando para instalar los módulos de la Biblioteca de constructos de AWS que requiere la aplicación.  

```
$ go get
```

**importante**  
Asegúrese de asignar sus archivos `cdk.json` y `cdk.context.json` al control de código fuente. La información de contexto (como las marcas de características y los valores en caché recuperados de su cuenta de AWS) forma parte del estado de su proyecto. Los valores pueden ser diferentes en otro entorno, lo que puede provocar cambios inesperados en los resultados. Para obtener más información, consulte [Valores de contexto y AWS CDK](context.md).

## Defina una canalización
<a name="cdk-pipeline-define"></a>

Su aplicación de CDK Pipelines incluirá al menos dos pilas: una que represente la propia canalización y una o más pilas que representen la aplicación implementada a través de ella. Las pilas también se pueden agrupar en *etapas*, que puede utilizar para implementar copias de las pilas de infraestructura en diferentes entornos. Por ahora, consideraremos la canalización y, más adelante, profundizaremos en la aplicación que se implementará.

El constructo ` [CodePipeline](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html) ` es el constructo que representa canalización de CDK que utiliza AWS Pipeline como motor de implementación. Al crear una instancia de `CodePipeline` en una pila, define la ubicación de origen de la canalización (por ejemplo, un repositorio de GitHub). También define los comandos para crear la aplicación.

Por ejemplo, lo siguiente define una canalización cuyo origen se almacena en un repositorio de GitHub. También incluye un paso de compilación para una aplicación de CDK de TypeScript. Rellena la información sobre su repositorio de GitHub donde se indica.

**nota**  
De forma predeterminada, la canalización se autentica en GitHub mediante un token de acceso personal almacenado en Secrets Manager con el nombre `github-token`.

También tendrá que actualizar la creación de instancias de la pila de canalizaciones para especificar la cuenta de AWS y la región.

**Example**  
En `lib/my-pipeline-stack.ts` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}
```
En `bin/my-pipeline.ts` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyPipelineStack } from '../lib/my-pipeline-stack';

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
En `lib/my-pipeline-stack.js` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}

module.exports = { MyPipelineStack }
```
En `bin/my-pipeline.js` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
#!/usr/bin/env node

const cdk = require('aws-cdk-lib');
const { MyPipelineStack } = require('../lib/my-pipeline-stack');

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
En `my-pipeline/my-pipeline-stack.py` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]
                        )
                    )
```
En `app.py`:  

```
#!/usr/bin/env python3
import aws_cdk as cdk
from my_pipeline.my_pipeline_stack import MyPipelineStack

app = cdk.App()
MyPipelineStack(app, "MyPipelineStack",
    env=cdk.Environment(account="111111111111", region="eu-west-1")
)

app.synth()
```
En `src/main/java/com/myorg/MyPipelineStack.java` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
             .pipelineName("MyPipeline")
             .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
             .build();
    }
}
```
En `src/main/java/com/myorg/MyPipelineApp.java` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.StackProps;

public class MyPipelineApp {
    public static void main(final String[] args) {
        App app = new App();

        new MyPipelineStack(app, "PipelineStack", StackProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build());

        app.synth();
    }
}
```
En `src/MyPipeline/MyPipelineStack.cs` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
using Amazon.CDK;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });
        }
    }
}
```
En `src/MyPipeline/Program.cs` (puede variar si la carpeta de su proyecto no se llama `my-pipeline`):  

```
using Amazon.CDK;

namespace MyPipeline
{
    sealed class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();
            new MyPipelineStack(app, "MyPipelineStack", new StackProps
            {
                Env = new Amazon.CDK.Environment {
                    Account = "111111111111", Region = "eu-west-1" }
            });

            app.Synth();
        }
    }
}
```

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	codebuild "github.com/aws/aws-cdk-go/awscdk/v2/awscodebuild"
	ssm "github.com/aws/aws-cdk-go/awscdk/v2/awsssm"
	pipeline "github.com/aws/aws-cdk-go/awscdk/v2/pipelines"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
	"os"
)

// my CDK Stack with resources
func NewCdkStack(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// create an example ssm parameter
	_ = ssm.NewStringParameter(stack, jsii.String("ssm-test-param"), &ssm.StringParameterProps{
		ParameterName: jsii.String("/testparam"),
		Description:   jsii.String("ssm parameter for demo"),
		StringValue:   jsii.String("my test param"),
	})

	return stack
}

// my CDK Application
func NewCdkApplication(scope constructs.Construct, id *string, props *awscdk.StageProps) awscdk.Stage {
	stage := awscdk.NewStage(scope, id, props)

	_ = NewCdkStack(stage, jsii.String("cdk-stack"), &awscdk.StackProps{Env: props.Env})

	return stage
}

// my CDK Pipeline
func NewCdkPipeline(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// GitHub repo with owner and repository name
	githubRepo := pipeline.CodePipelineSource_GitHub(jsii.String("owner/repo"), jsii.String("main"), &pipeline.GitHubSourceOptions{
		Authentication: awscdk.SecretValue_SecretsManager(jsii.String("my-github-token"), nil),
	})

	// self mutating pipeline
	myPipeline := pipeline.NewCodePipeline(stack, jsii.String("cdkPipeline"), &pipeline.CodePipelineProps{
		PipelineName: jsii.String("CdkPipeline"),
		// self mutation true - pipeline changes itself before application deployment
		SelfMutation: jsii.Bool(true),
		CodeBuildDefaults: &pipeline.CodeBuildOptions{
			BuildEnvironment: &codebuild.BuildEnvironment{
				// image version 6.0 recommended for newer go version
				BuildImage: codebuild.LinuxBuildImage_FromCodeBuildImageId(jsii.String("aws/codebuild/standard:6.0")),
			},
		},
		Synth: pipeline.NewCodeBuildStep(jsii.String("Synth"), &pipeline.CodeBuildStepProps{
			Input: githubRepo,
			Commands: &[]*string{
				jsii.String("npm install -g aws-cdk"),
				jsii.String("cdk synth"),
			},
		}),
	})

	// deployment of actual CDK application
	myPipeline.AddStage(NewCdkApplication(stack, jsii.String("MyApplication"), &awscdk.StageProps{
		Env: targetAccountEnv(),
	}), &pipeline.AddStageOpts{
		Post: &[]pipeline.Step{
			pipeline.NewCodeBuildStep(jsii.String("Manual Steps"), &pipeline.CodeBuildStepProps{
				Commands: &[]*string{
					jsii.String("echo \"My CDK App deployed, manual steps go here ... \""),
				},
			}),
		},
	})

	return stack
}

// main app
func main() {
	defer jsii.Close()

	app := awscdk.NewApp(nil)

	// call CDK Pipeline
	NewCdkPipeline(app, jsii.String("CdkPipelineStack"), &awscdk.StackProps{
		Env: pipelineEnv(),
	})

	app.Synth(nil)
}

// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func pipelineEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}

func targetAccountEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}
```

Debe implementar una canalización manualmente una vez. Después de eso, la canalización se mantiene actualizada desde el repositorio del código fuente. Así que asegúrese de que el código del repositorio sea el código que desee implementar. Revise sus cambios y envíelos a GitHub, luego implemente:

```
git add --all
git commit -m "initial commit"
git push
cdk deploy
```

**sugerencia**  
Ahora que has realizado la implementación inicial, su cuenta local de AWS ya no necesita acceso administrativo. Esto se debe a que todos los cambios en su aplicación se implementarán a través de la canalización. Todo lo que necesita hacer es enviar a GitHub.

## Etapas de aplicación
<a name="cdk-pipeline-stages"></a>

Para definir una aplicación de AWS de varias pilas que se pueda agregar a la canalización de una sola vez, defina una subclase de ` [Stage](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html) `. (Esta es diferente a la de `CdkStage` en el módulo de CDK Pipelines).

La etapa contiene las pilas que componen la aplicación. Si hay dependencias entre las pilas, las pilas se agregan automáticamente a la canalización en el orden correcto. Las pilas que no dependen unas de otras se implementan en paralelo. Puede agregar una relación de dependencia entre las pilas mediante una llamada a `stack1.addDependency(stack2)`

Las etapas aceptan un argumento predeterminado de `env`, que se convierte en el entorno predeterminado para las pilas que contiene. (Las pilas aún pueden tener su propio entorno especificado).

Para agregar una aplicación a la canalización, se hace una llamada ` [addStage()](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html#addwbrstagestage-optionss) ` con instancias de [Stage](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html). Se puede crear una instancia de una etapa y agregarla a la canalización varias veces para definir las distintas etapas de la canalización de aplicaciones de DTAP o multirregional.

Crearemos una pila que contenga una función de Lambda simple y la colocaremos en una etapa. A continuación, agregaremos la etapa a la canalización para que se pueda implementar.

**Example**  
Cree el nuevo archivo `lib/my-pipeline-lambda-stack.ts` para almacenar la pila de nuestra aplicación que contiene una función de Lambda.  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Function, InlineCode, Runtime } from 'aws-cdk-lib/aws-lambda';

export class MyLambdaStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}
```
Cree el nuevo archivo `lib/my-pipeline-app-stage.ts` para alojar nuestra etapa.  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from "constructs";
import { MyLambdaStack } from './my-pipeline-lambda-stack';

export class MyPipelineAppStage extends cdk.Stage {

    constructor(scope: Construct, id: string, props?: cdk.StageProps) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}
```
Edite `lib/my-pipeline-stack.ts` para agregar la etapa a nuestra canalización.  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { MyPipelineAppStage } from './my-pipeline-app-stage';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));
  }
}
```
Cree el nuevo archivo `lib/my-pipeline-lambda-stack.js` para almacenar la pila de nuestra aplicación que contiene una función de Lambda.  

```
const cdk = require('aws-cdk-lib');
const { Function, InlineCode, Runtime } = require('aws-cdk-lib/aws-lambda');

class MyLambdaStack extends cdk.Stack {
    constructor(scope, id, props) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}

module.exports = { MyLambdaStack }
```
Cree el nuevo archivo `lib/my-pipeline-app-stage.js` para alojar nuestra etapa.  

```
const cdk = require('aws-cdk-lib');
const { MyLambdaStack } = require('./my-pipeline-lambda-stack');

class MyPipelineAppStage extends cdk.Stage {

    constructor(scope, id, props) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}

module.exports = { MyPipelineAppStage };
```
Edite `lib/my-pipeline-stack.ts` para agregar la etapa a nuestra canalización.  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');
const { MyPipelineAppStage } = require('./my-pipeline-app-stage');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));

  }
}

module.exports = { MyPipelineStack }
```
Cree el nuevo archivo `my_pipeline/my_pipeline_lambda_stack.py` para almacenar la pila de nuestra aplicación que contiene una función de Lambda.  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.aws_lambda import Function, InlineCode, Runtime

class MyLambdaStack(cdk.Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        Function(self, "LambdaFunction",
            runtime=Runtime.NODEJS_18_X,
            handler="index.handler",
            code=InlineCode("exports.handler = _ => 'Hello, CDK';")
        )
```
Cree el nuevo archivo `my_pipeline/my_pipeline_app_stage.py` para alojar nuestra etapa.  

```
import aws_cdk as cdk
from constructs import Construct
from my_pipeline.my_pipeline_lambda_stack import MyLambdaStack

class MyPipelineAppStage(cdk.Stage):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        lambdaStack = MyLambdaStack(self, "LambdaStack")
```
Edite `my_pipeline/my-pipeline-stack.py` para agregar la etapa a nuestra canalización.  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep
from my_pipeline.my_pipeline_app_stage import MyPipelineAppStage

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]))

        pipeline.add_stage(MyPipelineAppStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))
```
Cree el nuevo archivo `src/main/java/com.myorg/MyPipelineLambdaStack.java` para almacenar la pila de nuestra aplicación que contiene una función de Lambda.  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.InlineCode;

public class MyPipelineLambdaStack extends Stack {
    public MyPipelineLambdaStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineLambdaStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Function.Builder.create(this, "LambdaFunction")
          .runtime(Runtime.NODEJS_18_X)
          .handler("index.handler")
          .code(new InlineCode("exports.handler = _ => 'Hello, CDK';"))
          .build();

    }

}
```
Cree el nuevo archivo `src/main/java/com.myorg/MyPipelineAppStage.java` para alojar nuestra etapa.  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.Stage;
import software.amazon.awscdk.StageProps;

public class MyPipelineAppStage extends Stage {
    public MyPipelineAppStage(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineAppStage(final Construct scope, final String id, final StageProps props) {
        super(scope, id, props);

        Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
    }

}
```
Edite `src/main/java/com.myorg/MyPipelineStack.java` para agregar la etapa a nuestra canalización.  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.StageProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
            .pipelineName("MyPipeline")
            .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
            .build();

        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build()));
    }
}
```
Cree el nuevo archivo `src/MyPipeline/MyPipelineLambdaStack.cs` para almacenar la pila de nuestra aplicación que contiene una función de Lambda.  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.Lambda;

namespace MyPipeline
{
    class MyPipelineLambdaStack : Stack
    {
        public MyPipelineLambdaStack(Construct scope, string id, StackProps props=null) : base(scope, id, props)
        {
            new Function(this, "LambdaFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_18_X,
                Handler = "index.handler",
                Code = new InlineCode("exports.handler = _ => 'Hello, CDK';")
            });
        }
    }
}
```
Cree el nuevo archivo `src/MyPipeline/MyPipelineAppStage.cs` para alojar nuestra etapa.  

```
using Amazon.CDK;
using Constructs;

namespace MyPipeline
{
    class MyPipelineAppStage : Stage
    {
        public MyPipelineAppStage(Construct scope, string id, StageProps props=null) : base(scope, id, props)
        {
            Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
        }
    }
}
```
Edite `src/MyPipeline/MyPipelineStack.cs` para agregar la etapa a nuestra canalización.  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });

            pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
            {
                Env = new Environment
                {
                    Account = "111111111111", Region = "eu-west-1"
                }
            }));
        }
    }
}
```

Cada etapa de la aplicación que agregue con `addStage()` implica la adición de una etapa de canalización correspondiente, representada por una instancia de ` [StageDeployment](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.StageDeployment.html) ` devuelta por la llamada `addStage()`. Puede añadir acciones previas o posteriores a la implementación a la etapa mediante una llamada a su método `addPre()` o `addPost()`.

**Example**  

```
// import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

    testingStage.addPost(new ManualApprovalStep('approval'));
```

```
// const { ManualApprovalStep } = require('aws-cdk-lib/pipelines');

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

testingStage.addPost(new ManualApprovalStep('approval'));
```

```
# from aws_cdk.pipelines import ManualApprovalStep

testing_stage = pipeline.add_stage(MyPipelineAppStage(self, "testing",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))

testing_stage.add_post(ManualApprovalStep('approval'))
```

```
// import software.amazon.awscdk.pipelines.StageDeployment;
// import software.amazon.awscdk.pipelines.ManualApprovalStep;

StageDeployment testingStage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

testingStage.addPost(new ManualApprovalStep("approval"));
```

```
var testingStage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

testingStage.AddPost(new ManualApprovalStep("approval"));
```

Puede agregar etapas a una ` [Wave](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.Wave.html) ` para implementarlas en paralelo, por ejemplo, al implementar una etapa en varias cuentas o regiones.

**Example**  

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
wave = pipeline.add_wave("wave")
wave.add_stage(MyApplicationStage(self, "MyAppEU",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))
wave.add_stage(MyApplicationStage(self, "MyAppUS",
    env=cdk.Environment(account="111111111111", region="us-west-1")))
```

```
// import software.amazon.awscdk.pipelines.Wave;
final Wave wave = pipeline.addWave("wave");
wave.addStage(new MyPipelineAppStage(this, "MyAppEU", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
        .build()));
wave.addStage(new MyPipelineAppStage(this, "MyAppUS", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("us-west-1")
                .build())
        .build()));
```

```
var wave = pipeline.AddWave("wave");
wave.AddStage(new MyPipelineAppStage(this, "MyAppEU", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));
wave.AddStage(new MyPipelineAppStage(this, "MyAppUS", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "us-west-1"
    }
}));
```

## Cómo probar las implementaciones
<a name="cdk-pipeline-validation"></a>

Puede agregar pasos a una canalización de CDK para validar las implementaciones que está realizando. Por ejemplo, puede utilizar la ` [ShellStep](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.ShellStep.html) ` de la biblioteca de CDK Pipeline para realizar tareas como las siguientes:
+ Intentar acceder a una Amazon API Gateway implementada recientemente y que se encuentra respaldada por una función de Lambda
+ Comprobación de la configuración de un recurso implementado al emitir un comando de la AWS CLI

En su forma más simple, agregar acciones de validación se ve así:

**Example**  

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
# stage was returned by pipeline.add_stage

stage.add_post(ShellStep("validate",
  commands=[''../tests/validate.sh'']
))
```

```
// stage was returned by pipeline.addStage

stage.addPost(ShellStep.Builder.create("validate")
        .commands(Arrays.asList("'../tests/validate.sh'"))
        .build());
```

```
// stage was returned by pipeline.addStage

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Commands = new string[] { "'../tests/validate.sh'" }
}));
```

Muchas implementaciones de AWS CloudFormation dan como resultado la generación de recursos con nombres impredecibles. Por ello, CDK Pipelines proporciona una forma de leer las salidas de AWS CloudFormation después de una implementación. Esto permite pasar (por ejemplo) la URL generada de un equilibrador de carga a una acción de prueba.

Para utilizar las salidas, debe exponer el objeto `CfnOutput` que le interese. A continuación, páselo a la propiedad `envFromCfnOutputs` de un paso para que esté disponible como variable de entorno dentro de ese paso.

**Example**  

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
# given a stack lb_stack that exposes a load balancer construct as load_balancer
self.load_balancer_address = cdk.CfnOutput(lb_stack, "LbAddress",
    value=f"https://{lb_stack.load_balancer.load_balancer_dns_name}/")

# pass the load balancer address to a shell step
stage.add_post(ShellStep("lbaddr",
    env_from_cfn_outputs={"lb_addr": lb_stack.load_balancer_address}
    commands=["echo $lb_addr"]))
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = CfnOutput.Builder.create(lbStack, "LbAddress")
                            .value(String.format("https://%s/",
                                    lbStack.loadBalancer.loadBalancerDnsName))
                            .build();

stage.addPost(ShellStep.Builder.create("lbaddr")
    .envFromCfnOutputs(     // Map.of requires Java 9 or later
        java.util.Map.of("lbAddr", loadBalancerAddress))
    .commands(Arrays.asList("echo $lbAddr"))
    .build());
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = new CfnOutput(lbStack, "LbAddress", new CfnOutputProps
{
    Value = string.Format("https://{0}/", lbStack.loadBalancer.LoadBalancerDnsName)
});

stage.AddPost(new ShellStep("lbaddr", new ShellStepProps
{
    EnvFromCfnOutputs = new Dictionary<string, CfnOutput>
    {
        {  "lbAddr", loadBalancerAddress }
    },
    Commands = new string[] { "echo $lbAddr" }
}));
```

Puede escribir pruebas de validación sencillas directamente en el `ShellStep`, pero este enfoque se vuelve difícil de manejar cuando la prueba consta de más de unas pocas líneas. Para pruebas más complejas, puede incorporar archivos adicionales (como scripts de intérprete de comandos completos o programas en otros lenguajes) al `ShellStep` a través de la propiedad de `inputs`. Las entradas pueden ser cualquier paso que tenga una salida, incluido un origen (como un repositorio de GitHub) u otro `ShellStep`.

Incorporar archivos del repositorio de origen es adecuado si los archivos se pueden usar directamente en la prueba (por ejemplo, si los archivos mismos son ejecutables). En este ejemplo, declaramos nuestro repositorio de GitHub como `source` (en lugar de crearlo como una instancia en línea como parte de `CodePipeline`). Luego, pasamos este conjunto de archivos tanto a la canalización como a la prueba de validación.

**Example**  

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
source   = CodePipelineSource.git_hub("OWNER/REPO", "main")

pipeline =  CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=ShellStep("Synth",
                    input=source,
                    commands=["npm install -g aws-cdk",
                        "python -m pip install -r requirements.txt",
                        "cdk synth"]))

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

stage.add_post(ShellStep("validate", input=source,
    commands=["sh ../tests/validate.sh"],
))
```

```
final CodePipelineSource source = CodePipelineSource.gitHub("OWNER/REPO", "main");

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(ShellStep.Builder.create("Synth")
                .input(source)
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(source)
        .commands(Arrays.asList("sh ../tests/validate.sh"))
        .build());
```

```
var source = CodePipelineSource.GitHub("OWNER/REPO", "main");

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = new ShellStep("Synth", new ShellStepProps
    {
        Input = source,
        Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
    })
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = source,
    Commands = new string[] { "sh ../tests/validate.sh" }
}));
```

Obtener los archivos adicionales del paso de síntesis es adecuado si es necesario compilar las pruebas, lo que se hace como parte de la síntesis.

**Example**  

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, "test", {
  env: { account: "111111111111", region: "eu-west-1" }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
synth_step = ShellStep("Synth",
                input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                commands=["npm install -g aws-cdk",
                  "python -m pip install -r requirements.txt",
                  "cdk synth"])

pipeline   = CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=synth_step)

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

# run a script that was compiled during synthesis
stage.add_post(ShellStep("validate",
    input=synth_step,
    commands=["node test/validate.js"],
))
```

```
final ShellStep synth = ShellStep.Builder.create("Synth")
                            .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                            .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                            .build();

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(synth)
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(synth)
        .commands(Arrays.asList("node ./tests/validate.js"))
        .build());
```

```
var synth = new ShellStep("Synth", new ShellStepProps
{
    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
});

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = synth
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = synth,
    Commands = new string[] { "node ./tests/validate.js" }
}));
```

## Notas de seguridad
<a name="cdk-pipeline-security"></a>

Cualquier forma de entrega continua conlleva riesgos de seguridad inherentes. Según el [modelo de responsabilidad compartida](https://aws.amazon.com/compliance/shared-responsibility-model/) de AWS, usted es responsable de la seguridad de su información en la nube de AWS. La biblioteca de CDK Pipelines le ofrece una ventaja inicial al incorporar valores predeterminados seguros y prácticas recomendadas de modelado.

Sin embargo, por su propia naturaleza, una biblioteca que necesita un alto nivel de acceso para cumplir con el propósito previsto no puede garantizar una seguridad completa. Existen muchos vectores de ataque fuera de AWS y su organización.

En particular, tenga en cuenta los siguientes aspectos:
+ Tenga en cuenta el software del que depende. Examine todo software de terceros que utilice en su canalización, ya que puede cambiar la infraestructura que se implementa.
+ Use el bloqueo de dependencias para evitar actualizaciones accidentales. CDK Pipelines respeta `package-lock.json` y `yarn.lock` para asegurarse de que sus dependencias sean las que usted espera.
+ CDK Pipelines se ejecuta con recursos creados en su propia cuenta, y los desarrolladores que envían el código a través de la canalización controlan la configuración de esos recursos. Por lo tanto, CDK Pipelines por sí solo no puede proteger contra los desarrolladores malintencionados que intentan eludir las comprobaciones de conformidad. Si su modelo de amenazas incluye desarrolladores que escriben código de CDK, debe contar con mecanismos de cumplimiento externos, como [AWS Hooks](https://aws.amazon.com/blogs/mt/proactively-keep-resources-secure-and-compliant-with-aws-cloudformation-hooks/) (preventivo) o [AWS Config](https://aws.amazon.com/config/) (reactivo), que el rol de ejecución de AWS CloudFormation no tenga permiso para deshabilitar.
+ Las credenciales para los entornos de producción deben ser de corta duración. Tras el arranque y el aprovisionamiento inicial, no es necesario que los desarrolladores tengan credenciales de cuenta en absoluto. Los cambios se pueden implementar a través de la canalización. Reduzca la posibilidad de que las credenciales se filtren al no tener necesidad de usarlas en primer lugar.

## Solución de problemas
<a name="cdk-pipeline-troubleshooting"></a>

Los siguientes problemas suelen surgir al empezar a usar CDK Pipelines.

 **Canalización: fallo interno**   

```
CREATE_FAILED  | {aws}::CodePipeline::Pipeline | Pipeline/Pipeline
Internal Failure
```
Compruebe su token de acceso de GitHub. Puede que falte o que no tenga los permisos para acceder al repositorio.

 **La política de claves contiene una declaración con una o varias entidades principales no válidas**   

```
CREATE_FAILED | {aws}::KMS::Key | Pipeline/Pipeline/ArtifactsBucketEncryptionKey
Policy contains a statement with one or more invalid principals.
```
Uno de los entornos de destino no se arrancó con la nueva pila de arranque. Asegúrese de que todos los entornos de destino estén iniciados.

 **La pila está en estado ROLLBACK\$1COMPLETE y no se puede actualizar**   

```
Stack <STACK_NAME> is in ROLLBACK_COMPLETE state and cannot be updated. (Service:
AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request
ID: ...)
```
La pila falló en su implementación anterior y no se puede volver a intentar. Elimine la pila de la consola de AWS CloudFormation y vuelva a intentar la implementación.

# Cree e implemente activos de imagen de contenedores en las aplicaciones de CDK
<a name="build-containers"></a>

Al crear activos de imágenes de contenedores con el AWS Cloud Development Kit (AWS CDK), se utiliza Docker de forma predeterminada para realizar estas acciones. Si quiere usar una herramienta de administración de contenedores diferente, puede reemplazar Docker a través de la variable del entorno `CDK_DOCKER`.

## Ejemplo: cree y publique un activo de imagen de contenedor con el CDK AWS
<a name="build-containers-intro-example"></a>

El siguiente es un ejemplo sencillo de una aplicación de AWS CDK que crea y publica un activo de contenedor en Amazon Elastic Container Registry (Amazon ECR) con Docker de forma predeterminada:

 **Estructura de un proyecto**   

```
my-cdk-app/
├── lib/
│   ├── my-stack.ts
│   └── docker/
│       ├── Dockerfile
│       └── app/
│           └── index.js
├── bin/
│   └── my-cdk-app.ts
├── package.json
├── tsconfig.json
└── cdk.json
```

 **Dockerfile**   

```
FROM public.ecr.aws/lambda/nodejs:16

# Copy application code
COPY app/ /var/task/

# (Optional) Install dependencies
# RUN npm install

# The Lambda Node.js base image looks for index.handler by default
```

 **Código de la aplicación**   
En `lib/docker/app/index.js`:  

```
console.log("Hello from inside the container!");
```

 **Pila de CDK**   

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecr_assets from 'aws-cdk-lib/aws-ecr-assets';

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Define a Docker image asset
    const dockerImageAsset = new ecr_assets.DockerImageAsset(this, 'MyDockerImage', {
      directory: 'lib/docker', // Path to the directory containing the Dockerfile
    });

    // Output the ECR URI
    new cdk.CfnOutput(this, 'ECRImageUri', {
      value: dockerImageAsset.imageUri,
    });
  }
}
```

 **Aplicación de CDK**   

```
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyStack } from '../lib/my-stack';

const app = new cdk.App();
new MyStack(app, 'MyStack');
```

Cuando ejecutamos `cdk deploy`, la interfaz de línea de comandos (CLI) del AWS Cloud Development Kit (AWS CDK) hace lo siguiente:

1.  **Cree la imagen de Docker**: ejecute `docker build` localmente en `Dockerfile` función del directorio especificado (`lib/docker`).

1.  **Etiquete la imagen**: ejecute `docker tag` para etiquetar la imagen creada con un hash único, basado en el contenido de la imagen.

1.  **Publique en Amazon ECR**: ejecute `docker push` para publicar la imagen de contenedor en un repositorio de Amazon ECR. Debe ser un repositorio ya existente. Se crea durante el proceso de arranque predeterminado.

1.  **Generar el URI de la imagen**: después de una implementación correcta, el URI de Amazon ECR de la imagen de contenedor publicada se muestra en su petición de comandos. Este es el URI de nuestra imagen de Docker en Amazon ECR.

## ¿Cómo reemplazar Docker por otra herramienta de administración de contenedores?
<a name="build-container-replace"></a>

Utilice la variable de entorno `CDK_DOCKER` para especificar la ruta al binario de la herramienta de administración de contenedores que la sustituya. El siguiente es un ejemplo de cómo reemplazar Docker con Finch:

```
$ which finch
/usr/local/bin/finch # Locate the path to the binary

$ export CDK_DOCKER='/usr/local/bin/finch' # Set the environment variable

$ cdk deploy # Deploy using the replacement
```

Los alias ni los enlaces no se admiten. Para reemplazar a Docker, debe usar la variable del entorno `CDK_DOCKER`.

## Motores de reemplazo directo compatibles de Docker
<a name="build-container-supported"></a>

 Finch es compatible, aunque es posible que algunas funciones de Docker no estén disponibles o que funcionen de forma diferente a medida que la herramienta evolucione. Para obtener más información sobre Finch, consulte [Ready for Flight: ¡Anunciamos Finch 1.0 GA\$1](https://aws.amazon.com/blogs/opensource/ready-for-flight-announcing-finch-1-0-ga/) en el *blog de AWScódigo abierto*.

Puede que funcionen otras herramientas de administración de contenedores. La CDK no comprueba qué sustituto de Docker está utilizando para determinar si es compatible. Si la herramienta tiene comandos de Docker equivalentes y tiene un funcionamiento similar, debería funcionar.

# Solución de problemas de implementaciones de AWS CDK
<a name="deploy-troubleshoot"></a>

Solucione problemas comunes al implementar aplicaciones del AWS Cloud Development Kit (AWS CDK).

## Creación de entidades principales incorrectas al momento de la implementación
<a name="deploy-troubleshoot-sp"></a>

Cuando se implementan aplicaciones de CDK que contienen roles de AWS Identity and Access Management (IAM) con entidades principales de servicio, se descubre que se están creando dominios incorrectos para las entidades principales de servicio.

El siguiente es un ejemplo básico de creación de un rol de IAM que puede asumir Registros de Amazon CloudWatch al usar su entidad principal de servicio:

```
import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class MyCdkProjectStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create an IAM role for CloudWatch Logs to assume
    const cloudWatchLogsRole = new iam.Role(this, 'CloudWatchLogsRole', {
      assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'), // This is for CloudWatch Logs
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSCloudWatchLogsFullAccess')
      ]
    });

    // You can then use this role in other constructs or configurations where CloudWatch Logs needs to assume a role
  }
}
```

Al implementar esta pila, debe crearse una entidad principal de servicio denominada `logs.amazonaws.com`. En la mayoría de los casos, los servicios de AWS utilizan la siguiente denominación para las entidades principales de servicio: `<service>.amazonaws.com`.

### Causas habituales
<a name="deploy-troubleshoot-sp-causes"></a>

Si está utilizando una versión de AWS CDK anterior a la versión 2.150.0, es posible que encuentre este error. En versiones anteriores de AWS CDK, la nomenclatura de las entidades principales de servicio no estaba estandarizada, lo que podía provocar la creación de entidades principales de servicio con dominios incorrectos.

En la versión 2.51.0 de AWS CDK, se implementó una corrección mediante la estandarización de todas las entidades principales de servicio creadas de manera automática para usar `<service>.amazonaws.com` siempre que sea posible. Esta solución estaba disponible al permitir la marca de característica `@aws-cdk/aws-iam:standardizedServicePrincipals`.

A partir de la versión 2.150.0 de AWS CDK, este se convirtió en el comportamiento predeterminado.

### Resolución
<a name="deploy-troubleshoot-sp-resolution"></a>

Actualice a la versión 2.150.0 de AWS CDK o más reciente.

Si no puede actualizar AWS CDK a la versión 2.150.0 o más reciente, debe actualizar al menos a la versión 2.51.0 o posterior. Luego, habilite la siguiente marca de característica en su archivo `cdk.json`: `@aws-cdk/aws-iam:standardizedServicePrincipals`.