Este é o Guia do Desenvolvedor do AWS CDK v2. O CDK v1 antigo entrou em manutenção em 1º de junho de 2022 e encerrou o suporte em 1º de junho de 2023.
Recursos e o AWS CDK
Recursos são o que você configura para usar Serviços da AWS em seus aplicativos. Os recursos são um atributo do AWS CloudFormation. Ao configurar recursos e suas propriedades em um modelo AWS CloudFormation, você pode implantar para o AWS CloudFormation para provisionar seus recursos. Com o AWS Cloud Development Kit (AWS CDK), você pode configurar recursos por meio de constructos. Em seguida, você implanta seu aplicativo CDK, o que envolve sintetizar um modelo AWS CloudFormation e implantá-lo no AWS CloudFormation para provisionar seus recursos.
Conforme descrito em Constructos do AWS CDK, o AWS CDK fornece uma rica biblioteca de classes de constructos, chamada constructos da AWS, que representam todos os recursos da AWS.
Para criar uma instância de um recurso usando seu constructo correspondente, passe o escopo como o primeiro argumento, o ID lógico do constructo e um conjunto de propriedades de configuração (props). Por exemplo, veja como criar uma fila do Amazon SQS com criptografia AWS KMS usando o constructo sqs.Queue da Biblioteca de Constructos da AWS.
- TypeScript
-
import * as sqs from '@aws-cdk/aws-sqs';
new sqs.Queue(this, 'MyQueue', {
encryption: sqs.QueueEncryption.KMS_MANAGED
});
- JavaScript
-
const sqs = require('@aws-cdk/aws-sqs');
new sqs.Queue(this, 'MyQueue', {
encryption: sqs.QueueEncryption.KMS_MANAGED
});
- Python
-
import aws_cdk.aws_sqs as sqs
sqs.Queue(self, "MyQueue", encryption=sqs.QueueEncryption.KMS_MANAGED)
- Java
-
import software.amazon.awscdk.services.sqs.*;
Queue.Builder.create(this, "MyQueue").encryption(
QueueEncryption.KMS_MANAGED).build();
- C#
-
using Amazon.CDK.AWS.SQS;
new Queue(this, "MyQueue", new QueueProps
{
Encryption = QueueEncryption.KMS_MANAGED
});
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs"
)
sqs.NewQueue(stack, jsii.String("MyQueue"), &sqs.QueueProps{
Encryption: sqs.QueueEncryption_KMS_MANAGED,
})
Alguns props de configuração são opcionais e, em muitos casos, têm valores padrão. Em alguns casos, todos os props são opcionais e o último argumento pode ser totalmente omitido.
Atributos de recursos
A maioria dos recursos na Biblioteca de Constructos AWS expõe atributos, que são resolvidos no momento da implantação pelo AWS CloudFormation. Os atributos são expostos na forma de propriedades nas classes de recursos com o nome do tipo como prefixo. O exemplo a seguir mostra como obter o URL de uma fila do Amazon SQS usando a propriedade queueUrl
(Python: queue_url
).
- TypeScript
-
import * as sqs from '@aws-cdk/aws-sqs';
const queue = new sqs.Queue(this, 'MyQueue');
const url = queue.queueUrl; // => A string representing a deploy-time value
- JavaScript
-
const sqs = require('@aws-cdk/aws-sqs');
const queue = new sqs.Queue(this, 'MyQueue');
const url = queue.queueUrl; // => A string representing a deploy-time value
- Python
-
import aws_cdk.aws_sqs as sqs
queue = sqs.Queue(self, "MyQueue")
url = queue.queue_url # => A string representing a deploy-time value
- Java
-
Queue queue = new Queue(this, "MyQueue");
String url = queue.getQueueUrl(); // => A string representing a deploy-time value
- C#
-
var queue = new Queue(this, "MyQueue");
var url = queue.QueueUrl; // => A string representing a deploy-time value
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs"
)
queue := sqs.NewQueue(stack, jsii.String("MyQueue"), &sqs.QueueProps{})
url := queue.QueueUrl() // => A string representing a deploy-time value
Consulte Tokens e o AWS CDK para obter informações sobre como o AWS CDK codifica atributos de tempo de implantação como strings.
Fazer referência a recursos
Ao configurar recursos, muitas vezes você precisará referenciar propriedades de outro recurso. Veja os exemplos a seguir:
-
Um recurso do Amazon Elastic Container Service (Amazon ECS) requer uma referência ao cluster no qual é executado.
-
Uma distribuição do Amazon CloudFront requer uma referência ao bucket do Amazon Simple Storage Service (Amazon S3) contendo o código-fonte.
É possível fazer referência a recursos de qualquer uma das formas a seguir:
-
Ao passar um recurso definido em seu aplicativo CDK, na mesma pilha ou em uma diferente
-
Ao passar um objeto proxy referenciando um recurso definido em sua conta AWS, criado a partir de um identificador exclusivo do recurso (como um ARN)
Se a propriedade de um constructo representa um constructo para outro recurso, seu tipo é o tipo de interface de constructo. Por exemplo, o constructo do Amazon ECS assume uma propriedade cluster
do tipo ecs.ICluster
. Outro exemplo é o constructo de distribuição do CloudFront que usa uma propriedade sourceBucket
(Python: source_bucket
) do tipo s3.IBucket
.
Você pode transmitir diretamente qualquer objeto de recurso do tipo adequado definido no mesmo aplicativo AWS CDK. O exemplo a seguir define um cluster do Amazon ECS e o usa para definir um serviço do Amazon ECS.
- TypeScript
-
const cluster = new ecs.Cluster(this, 'Cluster', { /*...*/ });
const service = new ecs.Ec2Service(this, 'Service', { cluster: cluster });
- JavaScript
-
const cluster = new ecs.Cluster(this, 'Cluster', { /*...*/ });
const service = new ecs.Ec2Service(this, 'Service', { cluster: cluster });
- Python
-
cluster = ecs.Cluster(self, "Cluster")
service = ecs.Ec2Service(self, "Service", cluster=cluster)
- Java
-
Cluster cluster = new Cluster(this, "Cluster");
Ec2Service service = new Ec2Service(this, "Service",
new Ec2ServiceProps.Builder().cluster(cluster).build());
- C#
-
var cluster = new Cluster(this, "Cluster");
var service = new Ec2Service(this, "Service", new Ec2ServiceProps { Cluster = cluster });
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
ecs "github.com/aws/aws-cdk-go/awscdk/v2/awsecs"
)
cluster := ecs.NewCluster(stack, jsii.String("MyCluster"), &ecs.ClusterProps{})
service := ecs.NewEc2Service(stack, jsii.String("MyService"), &ecs.Ec2ServiceProps{
Cluster: cluster,
})
Como fazer referência a recursos em uma pilha diferente
Você pode se referir aos recursos em uma pilha diferente, desde que estejam definidos no mesmo aplicativo e no mesmo ambiente AWS. O seguinte padrão é geralmente usado:
-
Armazene uma referência ao constructo como um atributo da pilha que produz o recurso. (Para obter uma referência à pilha do constructo atual, use Stack.of(this)
.)
-
Passe essa referência ao construtor da pilha que consome o recurso como parâmetro ou propriedade. A pilha consumidora então a passa como uma propriedade para qualquer constructo que precise dela.
O exemplo a seguir define uma pilha stack1
. Essa pilha define um bucket do Amazon S3 e armazena uma referência ao constructo do bucket como um atributo da pilha. Em seguida, o aplicativo define uma segunda pilha, stack2
, que aceita um bucket na instanciação. O stack2
pode, por exemplo, definir uma tabela AWS Glue que usa o bucket para armazenamento de dados.
- TypeScript
-
const prod = { account: '123456789012', region: 'us-east-1' };
const stack1 = new StackThatProvidesABucket(app, 'Stack1', { env: prod });
// stack2 will take a property { bucket: IBucket }
const stack2 = new StackThatExpectsABucket(app, 'Stack2', {
bucket: stack1.bucket,
env: prod
});
- JavaScript
-
const prod = { account: '123456789012', region: 'us-east-1' };
const stack1 = new StackThatProvidesABucket(app, 'Stack1', { env: prod });
// stack2 will take a property { bucket: IBucket }
const stack2 = new StackThatExpectsABucket(app, 'Stack2', {
bucket: stack1.bucket,
env: prod
});
- Python
-
prod = core.Environment(account="123456789012", region="us-east-1")
stack1 = StackThatProvidesABucket(app, "Stack1", env=prod)
# stack2 will take a property "bucket"
stack2 = StackThatExpectsABucket(app, "Stack2", bucket=stack1.bucket, env=prod)
- Java
-
// Helper method to build an environment
static Environment makeEnv(String account, String region) {
return Environment.builder().account(account).region(region)
.build();
}
App app = new App();
Environment prod = makeEnv("123456789012", "us-east-1");
StackThatProvidesABucket stack1 = new StackThatProvidesABucket(app, "Stack1",
StackProps.builder().env(prod).build());
// stack2 will take an argument "bucket"
StackThatExpectsABucket stack2 = new StackThatExpectsABucket(app, "Stack,",
StackProps.builder().env(prod).build(), stack1.bucket);
- C#
-
Amazon.CDK.Environment makeEnv(string account, string region)
{
return new Amazon.CDK.Environment { Account = account, Region = region };
}
var prod = makeEnv(account: "123456789012", region: "us-east-1");
var stack1 = new StackThatProvidesABucket(app, "Stack1", new StackProps { Env = prod });
// stack2 will take a property "bucket"
var stack2 = new StackThatExpectsABucket(app, "Stack2", new StackProps { Env = prod,
bucket = stack1.Bucket});
Se o AWS CDK determinar que o recurso está no mesmo ambiente, mas em uma pilha diferente, ele sintetiza automaticamente as exportações AWS CloudFormation na pilha de produção e um Fn::ImportValue na pilha consumidora para transferir essas informações de uma pilha para a outra.
Como resolver os deadlocks de dependência
Fazer referência a um recurso de uma pilha em outra pilha cria uma dependência entre as duas pilhas. Isso garante que eles sejam implantados na ordem correta. Depois que as pilhas são implantadas, essa dependência é concreta. Depois disso, remover o uso do recurso compartilhado da pilha consumidora pode causar uma falha inesperada na implantação. Isso acontece se houver outra dependência entre as duas pilhas que as força a serem implantadas na mesma ordem. Isso também pode acontecer sem dependência se a pilha de produção for simplesmente escolhida pelo CDK Toolkit para ser implantada primeiro. A exportação AWS CloudFormation é removida da pilha de produção porque não é mais necessária, mas o recurso exportado ainda está sendo usado na pilha de consumo porque sua atualização ainda não foi implantada. Portanto, a implantação da pilha do produtor falha.
Para resolver esse impasse, remova o uso do recurso compartilhado da pilha de consumo. (Isso remove a exportação automática da pilha de produção.) Em seguida, adicione manualmente a mesma exportação à pilha de produção usando exatamente o mesmo ID lógico da exportação gerado automaticamente. Remova o uso do recurso compartilhado na pilha de consumo e implante as duas pilhas. Em seguida, remova a exportação manual (e o recurso compartilhado, se não for mais necessário) e implante as duas pilhas novamente. O método exportValue()
da pilha é uma maneira conveniente de criar a exportação manual para essa finalidade. (Veja o exemplo na referência do método vinculado.)
Como fazer referência a recursos em sua conta AWS
Suponha que você queira usar um recurso já disponível na sua conta AWS no seu aplicativo AWS CDK. Isso pode ser um recurso definido por meio do console, de um SDK da AWS, diretamente com o AWS CloudFormation ou em um aplicativo AWS CDK diferente. Você pode transformar o ARN do recurso (ou outro atributo de identificação ou grupo de atributos) em um objeto proxy. O objeto proxy serve como referência ao recurso chamando um método estático de fábrica na classe do recurso.
Quando você cria esse proxy, o recurso externo não se torna parte do seu aplicativo AWS CDK. Portanto, as alterações feitas no proxy em seu aplicativo AWS CDK não afetam o recurso implantado. No entanto, o proxy pode ser passado para qualquer método AWS CDK que exija um recurso desse tipo.
O exemplo a seguir mostra como referenciar um bucket baseado em um bucket existente com o ARN arn:aws:s3:::amzn-s3-demo-bucket1 e uma nuvem privada Amazon Virtual com base em uma VPC existente com um ID específico.
- TypeScript
-
// Construct a proxy for a bucket by its name (must be same account)
s3.Bucket.fromBucketName(this, 'amzn-s3-demo-bucket', 'amzn-s3-demo-bucket1');
// Construct a proxy for a bucket by its full ARN (can be another account)
s3.Bucket.fromBucketArn(this, 'amzn-s3-demo-bucket', 'arn:aws:s3:::amzn-s3-demo-bucket1');
// Construct a proxy for an existing VPC from its attribute(s)
ec2.Vpc.fromVpcAttributes(this, 'MyVpc', {
vpcId: 'vpc-1234567890abcde',
});
- JavaScript
-
// Construct a proxy for a bucket by its name (must be same account)
s3.Bucket.fromBucketName(this, 'amzn-s3-demo-bucket', 'amzn-s3-demo-bucket1');
// Construct a proxy for a bucket by its full ARN (can be another account)
s3.Bucket.fromBucketArn(this, 'amzn-s3-demo-bucket', 'arn:aws:s3:::amzn-s3-demo-bucket1');
// Construct a proxy for an existing VPC from its attribute(s)
ec2.Vpc.fromVpcAttributes(this, 'MyVpc', {
vpcId: 'vpc-1234567890abcde'
});
- Python
-
# Construct a proxy for a bucket by its name (must be same account)
s3.Bucket.from_bucket_name(self, "amzn-s3-demo-bucket", "amzn-s3-demo-bucket1")
# Construct a proxy for a bucket by its full ARN (can be another account)
s3.Bucket.from_bucket_arn(self, "amzn-s3-demo-bucket", "arn:aws:s3:::amzn-s3-demo-bucket1")
# Construct a proxy for an existing VPC from its attribute(s)
ec2.Vpc.from_vpc_attributes(self, "MyVpc", vpc_id="vpc-1234567890abcdef")
- Java
-
// Construct a proxy for a bucket by its name (must be same account)
Bucket.fromBucketName(this, "amzn-s3-demo-bucket", "amzn-s3-demo-bucket1");
// Construct a proxy for a bucket by its full ARN (can be another account)
Bucket.fromBucketArn(this, "amzn-s3-demo-bucket",
"arn:aws:s3:::amzn-s3-demo-bucket1");
// Construct a proxy for an existing VPC from its attribute(s)
Vpc.fromVpcAttributes(this, "MyVpc", VpcAttributes.builder()
.vpcId("vpc-1234567890abcdef").build());
- C#
-
// Construct a proxy for a bucket by its name (must be same account)
Bucket.FromBucketName(this, "amzn-s3-demo-bucket", "amzn-s3-demo-bucket1");
// Construct a proxy for a bucket by its full ARN (can be another account)
Bucket.FromBucketArn(this, "amzn-s3-demo-bucket", "arn:aws:s3:::amzn-s3-demo-bucket1");
// Construct a proxy for an existing VPC from its attribute(s)
Vpc.FromVpcAttributes(this, "MyVpc", new VpcAttributes
{
VpcId = "vpc-1234567890abcdef"
});
- Go
-
// Define a proxy for a bucket by its name (must be same account)
s3.Bucket_FromBucketName(stack, jsii.String("amzn-s3-demo-bucket"), jsii.String("amzn-s3-demo-bucket1"))
// Define a proxy for a bucket by its full ARN (can be another account)
s3.Bucket_FromBucketArn(stack, jsii.String("amzn-s3-demo-bucket"), jsii.String("arn:aws:s3:::amzn-s3-demo-bucket1"))
// Define a proxy for an existing VPC from its attributes
ec2.Vpc_FromVpcAttributes(stack, jsii.String("MyVpc"), &ec2.VpcAttributes{
VpcId: jsii.String("vpc-1234567890abcde"),
})
Vamos examinar com mais cuidado o método Vpc.fromLookup()
. Como o ec2.Vpc
constructo é complexo, talvez você queira selecionar a VPC de várias maneiras para ser usada com seu aplicativo CDK. Para resolver isso, o constructo da VPC tem um método estático fromLookup
(Python: from_lookup
) que permite pesquisar a Amazon VPC desejada consultando sua conta AWS no momento da síntese.
Para usar o Vpc.fromLookup()
, o sistema que sintetiza a pilha deve ter acesso à conta proprietária da Amazon VPC. Isso ocorre porque o CDK Toolkit consulta a conta para encontrar a Amazon VPC certa no momento da síntese.
Além disso, o Vpc.fromLookup()
funciona somente em pilhas definidas com uma conta e uma região explícitas (consulte Ambientes para o AWS CDK). Se o AWS CDK tentar pesquisar uma Amazon VPC a partir de uma pilha independente do ambiente, o CDK Toolkit não sabe qual ambiente consultar para encontrar a VPC.
Você deve fornecer atributos Vpc.fromLookup()
suficientes para identificar de forma exclusiva uma VPC em sua conta AWS. Por exemplo, só pode haver uma VPC padrão, então basta especificar a VPC como padrão.
- TypeScript
-
ec2.Vpc.fromLookup(this, 'DefaultVpc', {
isDefault: true
});
- JavaScript
-
ec2.Vpc.fromLookup(this, 'DefaultVpc', {
isDefault: true
});
- Python
-
ec2.Vpc.from_lookup(self, "DefaultVpc", is_default=True)
- Java
-
Vpc.fromLookup(this, "DefaultVpc", VpcLookupOptions.builder()
.isDefault(true).build());
- C#
-
Vpc.FromLookup(this, id = "DefaultVpc", new VpcLookupOptions { IsDefault = true });
- Go
-
ec2.Vpc_FromLookup(this, jsii.String("DefaultVpc"), &ec2.VpcLookupOptions{
IsDefault: jsii.Bool(true),
})
Você também pode usar a propriedade tags
para consultar VPCs por tag. Você pode adicionar tags à Amazon VPC no momento de sua criação usando AWS CloudFormation ou AWS CDK. Você pode editar as tags a qualquer momento após a criação usando o AWS Management Console, o AWS CLI ou um SDK da AWS. Além de todas as tags que você mesmo adiciona, o AWS CDK adiciona automaticamente as seguintes tags a todas as VPCs criadas.
-
Nome – O nome da VPC.
-
aws-cdk:subnet-name – O nome da sub-rede.
-
aws-cdk:subnet-type – O tipo de sub-rede: pública, privada ou isolada.
- TypeScript
-
ec2.Vpc.fromLookup(this, 'PublicVpc',
{tags: {'aws-cdk:subnet-type': "Public"}});
- JavaScript
-
ec2.Vpc.fromLookup(this, 'PublicVpc',
{tags: {'aws-cdk:subnet-type': "Public"}});
- Python
-
ec2.Vpc.from_lookup(self, "PublicVpc",
tags={"aws-cdk:subnet-type": "Public"})
- Java
-
Vpc.fromLookup(this, "PublicVpc", VpcLookupOptions.builder()
.tags(java.util.Map.of("aws-cdk:subnet-type", "Public")) // Java 9 or later
.build());
- C#
-
Vpc.FromLookup(this, id = "PublicVpc", new VpcLookupOptions
{ Tags = new Dictionary<string, string> { ["aws-cdk:subnet-type"] = "Public" });
- Go
-
ec2.Vpc_FromLookup(this, jsii.String("DefaultVpc"), &ec2.VpcLookupOptions{
Tags: &map[string]*string{"aws-cdk:subnet-type": jsii.String("Public")},
})
Os resultados do Vpc.fromLookup()
são armazenados em cache no arquivo cdk.context.json
do projeto. (Consulte Valores de contexto e o AWS CDK.) Confirme esse arquivo com o controle de versão para que seu aplicativo continue se referindo à mesma Amazon VPC. Isso funciona mesmo se você alterar posteriormente os atributos de suas VPCs de uma forma que resultaria na seleção de uma VPC diferente. Isso é particularmente importante se você estiver implantando a pilha em um ambiente que não tem acesso à conta AWS que define a VPC, como o CDK Pipelines.
Embora você possa usar um recurso externo em qualquer lugar em que usaria um recurso semelhante definido no seu aplicativo AWS CDK, não é possível modificá-lo. Por exemplo, chamar addToResourcePolicy
(Python: add_to_resource_policy
) em um s3.Bucket
externo não faz nada.
Nomes físicos de recursos
Os nomes lógicos dos recursos no AWS CloudFormation são diferentes dos nomes dos recursos que são mostrados no AWS Management Console depois de serem implantados pelo AWS CloudFormation. O AWS CDK chama esses nomes finais de nomes físicos.
Por exemplo, o AWS CloudFormation pode criar o bucket do Amazon S3 com o ID lógico Stack2amzn-s3-demo-bucket4DD88B4F
do exemplo anterior com o nome físico stack2amzn-s3-demo-bucket4dd88b4f-iuv1rbv9z3to
.
Você pode especificar um nome físico ao criar constructos que representam recursos usando a propriedade <resourceType>
Name. O exemplo a seguir cria um bucket do Amazon S3 com o nome físico amzn-s3-demo-bucket
.
- TypeScript
-
const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
bucketName: 'amzn-s3-demo-bucket',
});
- JavaScript
-
const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
bucketName: 'amzn-s3-demo-bucket'
});
- Python
-
bucket = s3.Bucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket")
- Java
-
Bucket bucket = Bucket.Builder.create(this, "amzn-s3-demo-bucket")
.bucketName("amzn-s3-demo-bucket").build();
- C#
-
var bucket = new Bucket(this, "amzn-s3-demo-bucket", new BucketProps { BucketName = "amzn-s3-demo-bucket" });
- Go
-
bucket := s3.NewBucket(this, jsii.String("amzn-s3-demo-bucket"), &s3.BucketProps{
BucketName: jsii.String("amzn-s3-demo-bucket"),
})
A atribuição de nomes físicos aos recursos tem algumas desvantagens no AWS CloudFormation. Mais importante ainda, qualquer alteração nos recursos implantados que exija a substituição de um recurso, como alterações nas propriedades de um recurso que são imutáveis após a criação, falhará se um recurso tiver um nome físico atribuído. Se você acabar nesse estado, a única solução é excluir a pilha AWS CloudFormation e implantar o aplicativo AWS CDK novamente. Consulte a Documentação do AWS CloudFormation para obter detalhes.
Em alguns casos, como ao criar um aplicativo AWS CDK com referências entre ambientes, nomes físicos são necessários para que o AWS CDK funcione corretamente. Nesses casos, se você não quiser se preocupar em criar um nome físico, pode deixar o AWS CDK nomear para você. Para isso, use o valor especial PhysicalName.GENERATE_IF_NEEDED
, da forma a seguir.
- TypeScript
-
const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
bucketName: core.PhysicalName.GENERATE_IF_NEEDED,
});
- JavaScript
-
const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
bucketName: core.PhysicalName.GENERATE_IF_NEEDED
});
- Python
-
bucket = s3.Bucket(self, "amzn-s3-demo-bucket",
bucket_name=core.PhysicalName.GENERATE_IF_NEEDED)
- Java
-
Bucket bucket = Bucket.Builder.create(this, "amzn-s3-demo-bucket")
.bucketName(PhysicalName.GENERATE_IF_NEEDED).build();
- C#
-
var bucket = new Bucket(this, "amzn-s3-demo-bucket", new BucketProps
{ BucketName = PhysicalName.GENERATE_IF_NEEDED });
- Go
-
bucket := s3.NewBucket(this, jsii.String("amzn-s3-demo-bucket"), &s3.BucketProps{
BucketName: awscdk.PhysicalName_GENERATE_IF_NEEDED(),
})
Passando identificadores de recursos exclusivos
Sempre que possível, você deve passar os recursos por referência, conforme descrito na seção anterior. No entanto, há casos em que você não tem outra escolha a não ser se referir a um recurso por meio de um de seus atributos. Alguns casos de uso incluem o seguinte:
-
Quando você está usando recursos AWS CloudFormation de baixo nível.
-
Quando você precisa expor recursos aos componentes de runtime de um aplicativo AWS CDK, como ao se referir às funções do Lambda por meio de variáveis de ambiente.
Esses identificadores estão disponíveis como atributos nos recursos, como os seguintes.
- TypeScript
-
bucket.bucketName
lambdaFunc.functionArn
securityGroup.groupArn
- JavaScript
-
bucket.bucketName
lambdaFunc.functionArn
securityGroup.groupArn
- Python
-
bucket.bucket_name
lambda_func.function_arn
security_group_arn
- Java
-
A vinculação Java AWS CDK usa métodos getter para atributos.
bucket.getBucketName()
lambdaFunc.getFunctionArn()
securityGroup.getGroupArn()
- C#
-
bucket.BucketName
lambdaFunc.FunctionArn
securityGroup.GroupArn
- Go
-
bucket.BucketName()
fn.FunctionArn()
O exemplo a seguir mostra como transmitir um nome de bucket gerado a uma função AWS Lambda.
- TypeScript
-
const bucket = new s3.Bucket(this, 'Bucket');
new lambda.Function(this, 'MyLambda', {
// ...
environment: {
BUCKET_NAME: bucket.bucketName,
},
});
- JavaScript
-
const bucket = new s3.Bucket(this, 'Bucket');
new lambda.Function(this, 'MyLambda', {
// ...
environment: {
BUCKET_NAME: bucket.bucketName
}
});
- Python
-
bucket = s3.Bucket(self, "Bucket")
lambda.Function(self, "MyLambda", environment=dict(BUCKET_NAME=bucket.bucket_name))
- Java
-
final Bucket bucket = new Bucket(this, "Bucket");
Function.Builder.create(this, "MyLambda")
.environment(java.util.Map.of( // Java 9 or later
"BUCKET_NAME", bucket.getBucketName()))
.build();
- C#
-
var bucket = new Bucket(this, "Bucket");
new Function(this, "MyLambda", new FunctionProps
{
Environment = new Dictionary<string, string>
{
["BUCKET_NAME"] = bucket.BucketName
}
});
- Go
-
bucket := s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{})
lambda.NewFunction(this, jsii.String("MyLambda"), &lambda.FunctionProps{
Environment: &map[string]*string{"BUCKET_NAME": bucket.BucketName()},
})
Concedendo permissões entre recursos
Constructos de alto nível possibilitam permissões com privilégios mínimos, oferecendo APIs simples e baseadas em intenção para expressar os requisitos de permissão. Por exemplo, muitos constructos de L2 oferecem métodos de concessão que você pode usar para conceder permissão a uma entidade (como um perfil do IAM ou usuário) para trabalhar com o recurso, sem precisar criar manualmente declarações de permissão do IAM.
O exemplo a seguir cria as permissões para permitir que a função de execução de uma função do Lambda leia e grave objetos em um determinado bucket do Amazon S3. Se o bucket do Amazon S3 for criptografado com uma chave AWS KMS, esse método também concederá permissões à função de execução da função do Lambda para decodificar com a chave.
- TypeScript
-
if (bucket.grantReadWrite(func).success) {
// ...
}
- JavaScript
-
if ( bucket.grantReadWrite(func).success) {
// ...
}
- Python
-
if bucket.grant_read_write(func).success:
# ...
- Java
-
if (bucket.grantReadWrite(func).getSuccess()) {
// ...
}
- C#
-
if (bucket.GrantReadWrite(func).Success)
{
// ...
}
- Go
-
if *bucket.GrantReadWrite(function, nil).Success() {
// ...
}
Os métodos de concessão retornam um objeto iam.Grant
. Use o atributo success
do objeto Grant
para determinar se a concessão foi efetivamente aplicada (por exemplo, ela pode não ter sido aplicada em recursos externos). Você também pode usar o método assertSuccess
(Python: assert_success
) do objeto Grant
para garantir que a concessão tenha sido aplicada com sucesso.
Se um método de concessão específico não estiver disponível para o caso de uso específico, você poderá usar um método de concessão genérico para definir uma nova concessão com uma lista específica de ações.
O exemplo a seguir mostra como conceder a uma função do Lambda acesso à ação do Amazon DynamoDB CreateBackup
.
- TypeScript
-
table.grant(func, 'dynamodb:CreateBackup');
- JavaScript
-
table.grant(func, 'dynamodb:CreateBackup');
- Python
-
table.grant(func, "dynamodb:CreateBackup")
- Java
-
table.grant(func, "dynamodb:CreateBackup");
- C#
-
table.Grant(func, "dynamodb:CreateBackup");
- Go
-
table := dynamodb.NewTable(this, jsii.String("MyTable"), &dynamodb.TableProps{})
table.Grant(function, jsii.String("dynamodb:CreateBackup"))
Muitos recursos, como as funções do Lambda, exigem que uma função seja assumida ao executar o código. Uma propriedade de configuração permite que você especifique um iam.IRole
. Se nenhuma função for especificada, a função criará automaticamente uma função específica para esse uso. Em seguida, você pode usar métodos de concessão nos recursos para adicionar declarações ao perfil.
Os métodos de concessão são criados usando APIs de nível inferior para lidar com as políticas do IAM. As políticas são modeladas como objetos PolicyDocument. Adicione declarações diretamente às funções (ou à função anexada de um constructo) usando o método addToRolePolicy
(Python: add_to_role_policy
) ou à política de um recurso (como uma política Bucket
) usando o método addToResourcePolicy
(Python: add_to_resource_policy
).
Métricas de recursos e alarmes
Muitos recursos emitem métricas do CloudWatch que podem ser usadas para configurar painéis de monitoramento e alarmes. Constructos de nível superior têm métodos métricos que permitem acessar as métricas sem procurar o nome correto a ser usado.
O exemplo a seguir mostra como definir um alarme quando o ApproximateNumberOfMessagesNotVisible
de uma fila do Amazon SQS exceder 100.
- TypeScript
-
import * as cw from '@aws-cdk/aws-cloudwatch';
import * as sqs from '@aws-cdk/aws-sqs';
import { Duration } from '@aws-cdk/core';
const queue = new sqs.Queue(this, 'MyQueue');
const metric = queue.metricApproximateNumberOfMessagesNotVisible({
label: 'Messages Visible (Approx)',
period: Duration.minutes(5),
// ...
});
metric.createAlarm(this, 'TooManyMessagesAlarm', {
comparisonOperator: cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
threshold: 100,
// ...
});
- JavaScript
-
const cw = require('@aws-cdk/aws-cloudwatch');
const sqs = require('@aws-cdk/aws-sqs');
const { Duration } = require('@aws-cdk/core');
const queue = new sqs.Queue(this, 'MyQueue');
const metric = queue.metricApproximateNumberOfMessagesNotVisible({
label: 'Messages Visible (Approx)',
period: Duration.minutes(5)
// ...
});
metric.createAlarm(this, 'TooManyMessagesAlarm', {
comparisonOperator: cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
threshold: 100
// ...
});
- Python
-
import aws_cdk.aws_cloudwatch as cw
import aws_cdk.aws_sqs as sqs
from aws_cdk.core import Duration
queue = sqs.Queue(self, "MyQueue")
metric = queue.metric_approximate_number_of_messages_not_visible(
label="Messages Visible (Approx)",
period=Duration.minutes(5),
# ...
)
metric.create_alarm(self, "TooManyMessagesAlarm",
comparison_operator=cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
threshold=100,
# ...
)
- Java
-
import software.amazon.awscdk.core.Duration;
import software.amazon.awscdk.services.sqs.Queue;
import software.amazon.awscdk.services.cloudwatch.Metric;
import software.amazon.awscdk.services.cloudwatch.MetricOptions;
import software.amazon.awscdk.services.cloudwatch.CreateAlarmOptions;
import software.amazon.awscdk.services.cloudwatch.ComparisonOperator;
Queue queue = new Queue(this, "MyQueue");
Metric metric = queue
.metricApproximateNumberOfMessagesNotVisible(MetricOptions.builder()
.label("Messages Visible (Approx)")
.period(Duration.minutes(5)).build());
metric.createAlarm(this, "TooManyMessagesAlarm", CreateAlarmOptions.builder()
.comparisonOperator(ComparisonOperator.GREATER_THAN_THRESHOLD)
.threshold(100)
// ...
.build());
- C#
-
using cdk = Amazon.CDK;
using cw = Amazon.CDK.AWS.CloudWatch;
using sqs = Amazon.CDK.AWS.SQS;
var queue = new sqs.Queue(this, "MyQueue");
var metric = queue.MetricApproximateNumberOfMessagesNotVisible(new cw.MetricOptions
{
Label = "Messages Visible (Approx)",
Period = cdk.Duration.Minutes(5),
// ...
});
metric.CreateAlarm(this, "TooManyMessagesAlarm", new cw.CreateAlarmOptions
{
ComparisonOperator = cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
Threshold = 100,
// ..
});
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
cw "github.com/aws/aws-cdk-go/awscdk/v2/awscloudwatch"
sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs"
)
queue := sqs.NewQueue(this, jsii.String("MyQueue"), &sqs.QueueProps{})
metric := queue.MetricApproximateNumberOfMessagesNotVisible(&cw.MetricOptions{
Label: jsii.String("Messages Visible (Approx)"),
Period: awscdk.Duration_Minutes(jsii.Number(5)),
})
metric.CreateAlarm(this, jsii.String("TooManyMessagesAlarm"), &cw.CreateAlarmOptions{
ComparisonOperator: cw.ComparisonOperator_GREATER_THAN_THRESHOLD,
Threshold: jsii.Number(100),
})
Se não houver um método para uma métrica específica, você poderá usar o método métrico geral para especificar o nome da métrica manualmente.
Métricas também podem ser adicionadas aos painéis do CloudWatch. Consulte CloudWatch.
Tráfego de rede
Em muitos casos, você deve habilitar permissões em uma rede para que um aplicativo funcione, como quando a infraestrutura computacional precisa acessar a camada de persistência. Recursos que estabelecem ou escutam conexões expõem métodos que permitem fluxos de tráfego, incluindo a definição de regras de grupos de segurança ou ACLs de rede.
Os recursos IConnectable têm uma propriedade connections
que é o gateway para a configuração das regras de tráfego de rede.
Você permite que os dados fluam em um determinado caminho de rede usando métodos allow
. O exemplo a seguir permite conexões HTTPS com a web e conexões de entrada do grupo Amazon EC2 Auto Scaling fleet2
.
- TypeScript
-
import * as asg from '@aws-cdk/aws-autoscaling';
import * as ec2 from '@aws-cdk/aws-ec2';
const fleet1: asg.AutoScalingGroup = asg.AutoScalingGroup(/*...*/);
// Allow surfing the (secure) web
fleet1.connections.allowTo(new ec2.Peer.anyIpv4(), new ec2.Port({ fromPort: 443, toPort: 443 }));
const fleet2: asg.AutoScalingGroup = asg.AutoScalingGroup(/*...*/);
fleet1.connections.allowFrom(fleet2, ec2.Port.AllTraffic());
- JavaScript
-
const asg = require('@aws-cdk/aws-autoscaling');
const ec2 = require('@aws-cdk/aws-ec2');
const fleet1 = asg.AutoScalingGroup();
// Allow surfing the (secure) web
fleet1.connections.allowTo(new ec2.Peer.anyIpv4(), new ec2.Port({ fromPort: 443, toPort: 443 }));
const fleet2 = asg.AutoScalingGroup();
fleet1.connections.allowFrom(fleet2, ec2.Port.AllTraffic());
- Python
-
import aws_cdk.aws_autoscaling as asg
import aws_cdk.aws_ec2 as ec2
fleet1 = asg.AutoScalingGroup( ... )
# Allow surfing the (secure) web
fleet1.connections.allow_to(ec2.Peer.any_ipv4(),
ec2.Port(PortProps(from_port=443, to_port=443)))
fleet2 = asg.AutoScalingGroup( ... )
fleet1.connections.allow_from(fleet2, ec2.Port.all_traffic())
- Java
-
import software.amazon.awscdk.services.autoscaling.AutoScalingGroup;
import software.amazon.awscdk.services.ec2.Peer;
import software.amazon.awscdk.services.ec2.Port;
AutoScalingGroup fleet1 = AutoScalingGroup.Builder.create(this, "MyFleet")
/* ... */.build();
// Allow surfing the (secure) Web
fleet1.getConnections().allowTo(Peer.anyIpv4(),
Port.Builder.create().fromPort(443).toPort(443).build());
AutoScalingGroup fleet2 = AutoScalingGroup.Builder.create(this, "MyFleet2")
/* ... */.build();
fleet1.getConnections().allowFrom(fleet2, Port.allTraffic());
- C#
-
using cdk = Amazon.CDK;
using asg = Amazon.CDK.AWS.AutoScaling;
using ec2 = Amazon.CDK.AWS.EC2;
// Allow surfing the (secure) Web
var fleet1 = new asg.AutoScalingGroup(this, "MyFleet", new asg.AutoScalingGroupProps { /* ... */ });
fleet1.Connections.AllowTo(ec2.Peer.AnyIpv4(), new ec2.Port(new ec2.PortProps
{ FromPort = 443, ToPort = 443 });
var fleet2 = new asg.AutoScalingGroup(this, "MyFleet2", new asg.AutoScalingGroupProps { /* ... */ });
fleet1.Connections.AllowFrom(fleet2, ec2.Port.AllTraffic());
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
autoscaling "github.com/aws/aws-cdk-go/awscdk/v2/awsautoscaling"
ec2 "github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
)
fleet1 := autoscaling.NewAutoScalingGroup(this, jsii.String("MyFleet1"), &autoscaling.AutoScalingGroupProps{})
fleet1.Connections().AllowTo(ec2.Peer_AnyIpv4(),ec2.NewPort(&ec2.PortProps{ FromPort: jsii.Number(443), ToPort: jsii.Number(443) }),jsii.String("secure web"))
fleet2 := autoscaling.NewAutoScalingGroup(this, jsii.String("MyFleet2"), &autoscaling.AutoScalingGroupProps{})
fleet1.Connections().AllowFrom(fleet2, ec2.Port_AllTraffic(),jsii.String("all traffic"))
Alguns recursos têm portas padrão associadas a eles. Os exemplos incluem o receptor de um balanceador de carga na porta pública e as portas nas quais o mecanismo de banco de dados aceita conexões para instâncias de um banco de dados do Amazon RDS. Nesses casos, você pode aplicar um controle rígido da rede sem precisar especificar manualmente a porta. Para fazer isso, use os métodos allowDefaultPortFrom
e allowToDefaultPort
(Python: allow_default_port_from
, allow_to_default_port
).
O exemplo a seguir mostra como habilitar conexões de qualquer endereço IPV4 e uma conexão de um grupo do Auto Scaling para acessar um banco de dados.
- TypeScript
-
listener.connections.allowDefaultPortFromAnyIpv4('Allow public access');
fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database');
- JavaScript
-
listener.connections.allowDefaultPortFromAnyIpv4('Allow public access');
fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database');
- Python
-
listener.connections.allow_default_port_from_any_ipv4("Allow public access")
fleet.connections.allow_to_default_port(rds_database, "Fleet can access database")
- Java
-
listener.getConnections().allowDefaultPortFromAnyIpv4("Allow public access");
fleet.getConnections().AllowToDefaultPort(rdsDatabase, "Fleet can access database");
- C#
-
listener.Connections.AllowDefaultPortFromAnyIpv4("Allow public access");
fleet.Connections.AllowToDefaultPort(rdsDatabase, "Fleet can access database");
- Go
-
listener.Connections().AllowDefaultPortFromAnyIpv4(jsii.String("Allow public Access"))
fleet.Connections().AllowToDefaultPort(rdsDatabase, jsii.String("Fleet can access database"))
Processar eventos
Alguns recursos podem atuar como fontes de eventos. Use o método addEventNotification
(Python: add_event_notification
) para registrar um destino de evento para um determinado tipo de evento emitido pelo recurso. Além disso, os métodos addXxxNotification
oferecem uma maneira simples de registrar um manipulador para tipos de eventos comuns.
O exemplo a seguir mostra como acionar uma função do Lambda quando um objeto é adicionado a um bucket do Amazon S3.
- TypeScript
-
import * as s3nots from '@aws-cdk/aws-s3-notifications';
const handler = new lambda.Function(this, 'Handler', { /*…*/ });
const bucket = new s3.Bucket(this, 'Bucket');
bucket.addObjectCreatedNotification(new s3nots.LambdaDestination(handler));
- JavaScript
-
const s3nots = require('@aws-cdk/aws-s3-notifications');
const handler = new lambda.Function(this, 'Handler', { /*…*/ });
const bucket = new s3.Bucket(this, 'Bucket');
bucket.addObjectCreatedNotification(new s3nots.LambdaDestination(handler));
- Python
-
import aws_cdk.aws_s3_notifications as s3_nots
handler = lambda_.Function(self, "Handler", ...)
bucket = s3.Bucket(self, "Bucket")
bucket.add_object_created_notification(s3_nots.LambdaDestination(handler))
- Java
-
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.s3.notifications.LambdaDestination;
Function handler = Function.Builder.create(this, "Handler")/* ... */.build();
Bucket bucket = new Bucket(this, "Bucket");
bucket.addObjectCreatedNotification(new LambdaDestination(handler));
- C#
-
using lambda = Amazon.CDK.AWS.Lambda;
using s3 = Amazon.CDK.AWS.S3;
using s3Nots = Amazon.CDK.AWS.S3.Notifications;
var handler = new lambda.Function(this, "Handler", new lambda.FunctionProps { .. });
var bucket = new s3.Bucket(this, "Bucket");
bucket.AddObjectCreatedNotification(new s3Nots.LambdaDestination(handler));
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
s3 "github.com/aws/aws-cdk-go/awscdk/v2/awss3"
s3nots "github.com/aws/aws-cdk-go/awscdk/v2/awss3notifications"
)
handler := lambda.NewFunction(this, jsii.String("MyFunction"), &lambda.FunctionProps{})
bucket := s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{})
bucket.AddObjectCreatedNotification(s3nots.NewLambdaDestination(handler), nil)
Políticas de remoção
Recursos que mantêm dados persistentes, como bancos de dados, buckets do Amazon S3 e registros do Amazon ECR, têm uma política de remoção. A política de remoção indica se objetos persistentes devem ser excluídos quando a pilha AWS CDK que os contém for destruída. Os valores que especificam a política de remoção estão disponíveis por meio da enumeração RemovalPolicy
no módulo core
do AWS CDK.
Recursos além daqueles que armazenam dados de forma persistente também podem ter um removalPolicy
que é usado para uma finalidade diferente. Por exemplo, uma versão da função do Lambda usa um atributo removalPolicy
para determinar se uma determinada versão é retida quando uma nova versão é implantada. Eles têm significados e padrões diferentes em comparação com a política de remoção em um bucket do Amazon S3 ou uma tabela do DynamoDB.
Valor |
Significado |
RemovalPolicy.RETAIN
|
Manter o conteúdo do recurso ao destruir a pilha (padrão). O recurso fica órfão da pilha e deve ser excluído manualmente. Se você tentar reimplantar a pilha enquanto o recurso ainda existe, você receberá uma mensagem de erro devido a um conflito de nomes.
|
RemovalPolicy.DESTROY
|
O recurso será destruído junto com a pilha.
|
O AWS CloudFormation não remove buckets do Amazon S3 que contêm arquivos, mesmo que sua política de remoção esteja definida como DESTROY
. Qualquer tentativa de fazer isso gerará um erro AWS CloudFormation. Para que o AWS CDK exclua todos os arquivos do bucket antes de destruí-lo, defina a propriedade autoDeleteObjects
do bucket como true
.
Veja a seguir um exemplo de criação de um bucket do Amazon S3 com RemovalPolicy
de DESTROY
e autoDeleteOjbects
definido como true
.
- TypeScript
-
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
export class CdkTestStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'Bucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true
});
}
}
- JavaScript
-
const cdk = require('@aws-cdk/core');
const s3 = require('@aws-cdk/aws-s3');
class CdkTestStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'Bucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true
});
}
}
module.exports = { CdkTestStack }
- Python
-
import aws_cdk.core as cdk
import aws_cdk.aws_s3 as s3
class CdkTestStack(cdk.stack):
def __init__(self, scope: cdk.Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
bucket = s3.Bucket(self, "Bucket",
removal_policy=cdk.RemovalPolicy.DESTROY,
auto_delete_objects=True)
- Java
-
software.amazon.awscdk.core.*;
import software.amazon.awscdk.services.s3.*;
public class CdkTestStack extends Stack {
public CdkTestStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkTestStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
Bucket.Builder.create(this, "Bucket")
.removalPolicy(RemovalPolicy.DESTROY)
.autoDeleteObjects(true).build();
}
}
- C#
-
using Amazon.CDK;
using Amazon.CDK.AWS.S3;
public CdkTestStack(Construct scope, string id, IStackProps props) : base(scope, id, props)
{
new Bucket(this, "Bucket", new BucketProps {
RemovalPolicy = RemovalPolicy.DESTROY,
AutoDeleteObjects = true
});
}
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/jsii-runtime-go"
s3 "github.com/aws/aws-cdk-go/awscdk/v2/awss3"
)
s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{
RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
AutoDeleteObjects: jsii.Bool(true),
})
Você também pode aplicar uma política de remoção diretamente ao recurso AWS CloudFormation subjacente por meio do método applyRemovalPolicy()
. Esse método está disponível em alguns recursos com estado que não têm uma propriedade removalPolicy
nas propriedades do recurso L2. Os exemplos incluem:
-
Pilhas do AWS CloudFormation
-
Grupos de usuários do Amazon Cognito
-
Instâncias de banco de dados do Amazon DocumentDB
-
Volumes do Amazon EC2
-
Domínios do Amazon OpenSearch Service
-
Sistemas de arquivos do Amazon FSx
-
Filas do Amazon SQS
- TypeScript
-
const resource = bucket.node.findChild('Resource') as cdk.CfnResource;
resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
- JavaScript
-
const resource = bucket.node.findChild('Resource');
resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
- Python
-
resource = bucket.node.find_child('Resource')
resource.apply_removal_policy(cdk.RemovalPolicy.DESTROY);
- Java
-
CfnResource resource = (CfnResource)bucket.node.findChild("Resource");
resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
- C#
-
var resource = (CfnResource)bucket.node.findChild('Resource');
resource.ApplyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
O RemovalPolicy
do AWS CDK se traduz em DeletionPolicy
do AWS CloudFormation. No entanto, o padrão AWS CDK é reter os dados, o que é o oposto do padrão AWS CloudFormation.