Skip navigation links

Package software.amazon.awscdk.core

AWS Cloud Development Kit Core Library

See: Description

Package software.amazon.awscdk.core Description

AWS Cloud Development Kit Core Library

---

cfn-resources: Stable

cdk-constructs: Stable


This library includes the basic building blocks of the AWS Cloud Development Kit (AWS CDK). It defines the core classes that are used in the rest of the AWS Construct Library.

See the AWS CDK Developer Guide for information of most of the capabilities of this library. The rest of this README will only cover topics not already covered in the Developer Guide.

Stacks and Stages

A Stack is the smallest physical unit of deployment, and maps directly onto a CloudFormation Stack. You define a Stack by defining a subclass of Stack -- let's call it MyStack -- and instantiating the constructs that make up your application in MyStack's constructor. You then instantiate this stack one or more times to define different instances of your application. For example, you can instantiate it once using few and cheap EC2 instances for testing, and once again using more and bigger EC2 instances for production.

When your application grows, you may decide that it makes more sense to split it out across multiple Stack classes. This can happen for a number of reasons:

As soon as your conceptual application starts to encompass multiple stacks, it is convenient to wrap them in another construct that represents your logical application. You can then treat that new unit the same way you used to be able to treat a single stack: by instantiating it multiple times for different instances of your application.

You can define a custom subclass of Construct, holding one or more Stacks, to represent a single logical instance of your application.

As a final note: Stacks are not a unit of reuse. They describe physical deployment layouts, and as such are best left to application builders to organize their deployments with. If you want to vend a reusable construct, define it as a subclasses of Construct: the consumers of your construct will decide where to place it in their own stacks.

Nested Stacks

Nested stacks are stacks created as part of other stacks. You create a nested stack within another stack by using the NestedStack construct.

As your infrastructure grows, common patterns can emerge in which you declare the same components in multiple templates. You can separate out these common components and create dedicated templates for them. Then use the resource in your template to reference other templates, creating nested stacks.

For example, assume that you have a load balancer configuration that you use for most of your stacks. Instead of copying and pasting the same configurations into your templates, you can create a dedicated template for the load balancer. Then, you just use the resource to reference that template from within other templates.

The following example will define a single top-level stack that contains two nested stacks: each one with a single Amazon S3 bucket:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 public class MyNestedStack extends NestedStack {
     public MyNestedStack(Construct scope, String id) {
         this(scope, id, null);
     }
 
     public MyNestedStack(Construct scope, String id, NestedStackProps props) {
         super(scope, id, props);
 
         new Bucket(this, "NestedBucket");
     }
 }
 
 public class MyParentStack extends Stack {
     public MyParentStack(Construct scope, String id) {
         this(scope, id, null);
     }
 
     public MyParentStack(Construct scope, String id, StackProps props) {
         super(scope, id, props);
 
         new MyNestedStack(this, "Nested1");
         new MyNestedStack(this, "Nested2");
     }
 }
 

Resources references across nested/parent boundaries (even with multiple levels of nesting) will be wired by the AWS CDK through CloudFormation parameters and outputs. When a resource from a parent stack is referenced by a nested stack, a CloudFormation parameter will automatically be added to the nested stack and assigned from the parent; when a resource from a nested stack is referenced by a parent stack, a CloudFormation output will be automatically be added to the nested stack and referenced using Fn::GetAtt "Outputs.Xxx" from the parent.

Nested stacks also support the use of Docker image and file assets.

Accessing resources in a different stack

You can access resources in a different stack, as long as they are in the same account and AWS Region. The following example defines the stack stack1, which defines an Amazon S3 bucket. Then it defines a second stack, stack2, which takes the bucket from stack1 as a constructor property.

 // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
 Map<String, String> prod = Map.of("account", "123456789012", "region", "us-east-1");
 
 Object stack1 = StackThatProvidesABucket.Builder.create(app, "Stack1").env(prod).build();
 
 // stack2 will take a property { bucket: IBucket }
 Object stack2 = StackThatExpectsABucket.Builder.create(app, "Stack2")
         .bucket(stack1.getBucket())
         .env(prod)
         .build();
 

If the AWS CDK determines that the resource is in the same account and Region, but in a different stack, it automatically synthesizes AWS CloudFormation Exports in the producing stack and an Fn::ImportValue in the consuming stack to transfer that information from one stack to the other.

Removing automatic cross-stack references

The automatic references created by CDK when you use resources across stacks are convenient, but may block your deployments if you want to remove the resources that are referenced in this way. You will see an error like:

 Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1
 

Let's say there is a Bucket in the stack1, and the stack2 references its bucket.bucketName. You now want to remove the bucket and run into the error above.

It's not safe to remove stack1.bucket while stack2 is still using it, so unblocking yourself from this is a two-step process. This is how it works:

DEPLOYMENT 1: break the relationship

DEPLOYMENT 2: remove the resource

Durations

To make specifications of time intervals unambiguous, a single class called Duration is used throughout the AWS Construct Library by all constructs that that take a time interval as a parameter (be it for a timeout, a rate, or something else).

An instance of Duration is constructed by using one of the static factory methods on it:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Duration.seconds(300);// 5 minutes
 Duration.minutes(5);// 5 minutes
 Duration.hours(1);// 1 hour
 Duration.days(7);// 7 days
 Duration.parse("PT5M");
 

Size (Digital Information Quantity)

To make specification of digital storage quantities unambiguous, a class called Size is available.

An instance of Size is initialized through one of its static factory methods:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Size.kibibytes(200);// 200 KiB
 Size.mebibytes(5);// 5 MiB
 Size.gibibytes(40);// 40 GiB
 Size.tebibytes(200);// 200 TiB
 Size.pebibytes(3);
 

Instances of Size created with one of the units can be converted into others. By default, conversion to a higher unit will fail if the conversion does not produce a whole number. This can be overridden by unsetting integral property.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Size.mebibytes(2).toKibibytes();// yields 2048
 Size.kibibytes(2050).toMebibytes(new SizeConversionOptions().rounding(SizeRoundingBehavior.getFLOOR()));
 

Secrets

To help avoid accidental storage of secrets as plain text, we use the SecretValue type to represent secrets. Any construct that takes a value that should be a secret (such as a password or an access key) will take a parameter of type SecretValue.

The best practice is to store secrets in AWS Secrets Manager and reference them using SecretValue.secretsManager:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 SecretValue secret = SecretValue.secretsManager("secretId", new SecretsManagerSecretOptions()
         .jsonField("password")// optional: key of a JSON field to retrieve (defaults to all content),
         .versionId("id")// optional: id of the version (default AWSCURRENT)
         .versionStage("stage"));
 

Using AWS Secrets Manager is the recommended way to reference secrets in a CDK app. SecretValue also supports the following secret sources:

ARN manipulation

Sometimes you will need to put together or pick apart Amazon Resource Names (ARNs). The functions stack.formatArn() and stack.parseArn() exist for this purpose.

formatArn() can be used to build an ARN from components. It will automatically use the region and account of the stack you're calling it on:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 // Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
 stack.formatArn(new ArnComponents()
         .service("lambda")
         .resource("function")
         .sep(":")
         .resourceName("MyFunction"));
 

parseArn() can be used to get a single component from an ARN. parseArn() will correctly deal with both literal ARNs and deploy-time values (tokens), but in case of a deploy-time value be aware that the result will be another deploy-time value which cannot be inspected in the CDK application.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 // Extracts the function name out of an AWS Lambda Function ARN
 ArnComponents arnComponents = stack.parseArn(arn, ":");
 String functionName = arnComponents.getResourceName();
 

Note that depending on the service, the resource separator can be either : or /, and the resource name can be either the 6th or 7th component in the ARN. When using these functions, you will need to know the format of the ARN you are dealing with.

For an exhaustive list of ARN formats used in AWS, see AWS ARNs and Namespaces in the AWS General Reference.

Dependencies

Construct Dependencies

Sometimes AWS resources depend on other resources, and the creation of one resource must be completed before the next one can be started.

In general, CloudFormation will correctly infer the dependency relationship between resources based on the property values that are used. In the cases where it doesn't, the AWS Construct Library will add the dependency relationship for you.

If you need to add an ordering dependency that is not automatically inferred, you do so by adding a dependency relationship using constructA.node.addDependency(constructB). This will add a dependency relationship between all resources in the scope of constructA and all resources in the scope of constructB.

If you want a single object to represent a set of constructs that are not necessarily in the same scope, you can use a ConcreteDependable. The following creates a single object that represents a dependency on two constructs, constructB and constructC:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 // Declare the dependable object
 ConcreteDependable bAndC = new ConcreteDependable();
 bAndC.add(constructB);
 bAndC.add(constructC);
 
 // Take the dependency
 constructA.node.addDependency(bAndC);
 

Stack Dependencies

Two different stack instances can have a dependency on one another. This happens when an resource from one stack is referenced in another stack. In that case, CDK records the cross-stack referencing of resources, automatically produces the right CloudFormation primitives, and adds a dependency between the two stacks. You can also manually add a dependency between two stacks by using the stackA.addDependency(stackB) method.

A stack dependency has the following implications:

Custom Resources

Custom Resources are CloudFormation resources that are implemented by arbitrary user code. They can do arbitrary lookups or modifications during a CloudFormation deployment.

To define a custom resource, use the CustomResource construct:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CustomResource(this, "MyMagicalResource", new CustomResourceProps()
         .resourceType("Custom::MyCustomResource")// must start with 'Custom::'
 
         // the resource properties
         .properties(Map.of(
                 "Property1", "foo",
                 "Property2", "bar"))
 
         // the ARN of the provider (SNS/Lambda) which handles
         // CREATE, UPDATE or DELETE events for this resource type
         // see next section for details
         .serviceToken("ARN"));
 

Custom Resource Providers

Custom resources are backed by a custom resource provider which can be implemented in one of the following ways. The following table compares the various provider types (ordered from low-level to high-level):

| Provider | Compute Type | Error Handling | Submit to CloudFormation | Max Timeout | Language | Footprint | |----------------------------------------------------------------------|:------------:|:--------------:|:------------------------:|:---------------:|:--------:|:---------:| | sns.Topic | Self-managed | Manual | Manual | Unlimited | Any | Depends | | lambda.Function | AWS Lambda | Manual | Manual | 15min | Any | Small | | core.CustomResourceProvider | Lambda | Auto | Auto | 15min | Node.js | Small | | custom-resources.Provider | Lambda | Auto | Auto | Unlimited Async | Any | Large |

Legend:

A NOTE ABOUT SINGLETONS

When defining resources for a custom resource provider, you will likely want to define them as a stack singleton so that only a single instance of the provider is created in your stack and which is used by all custom resources of that type.

Here is a basic pattern for defining stack singletons in the CDK. The following examples ensures that only a single SNS topic is defined:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 public Topic getOrCreate(Construct scope) {
     Stack stack = Stack.of(scope);
     String uniqueid = "GloballyUniqueIdForSingleton";return (Topic)stack.node.tryFindChild(uniqueid) ?? new Topic(stack, uniqueid)
 }
 

Amazon SNS Topic

Every time a resource event occurs (CREATE/UPDATE/DELETE), an SNS notification is sent to the SNS topic. Users must process these notifications (e.g. through a fleet of worker hosts) and submit success/failure responses to the CloudFormation service.

Set serviceToken to topic.topicArn in order to use this provider:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Topic topic = new Topic(this, "MyProvider");
 
 new CustomResource(this, "MyResource", new CustomResourceProps()
         .serviceToken(topic.getTopicArn()));
 

AWS Lambda Function

An AWS lambda function is called directly by CloudFormation for all resource events. The handler must take care of explicitly submitting a success/failure response to the CloudFormation service and handle various error cases.

Set serviceToken to lambda.functionArn to use this provider:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Function fn = new Function(this, "MyProvider", functionProps);
 
 new CustomResource(this, "MyResource", new CustomResourceProps()
         .serviceToken(fn.getFunctionArn()));
 

The core.CustomResourceProvider class

The class @aws-cdk/core.CustomResourceProvider offers a basic low-level framework designed to implement simple and slim custom resource providers. It currently only supports Node.js-based user handlers, and it does not have support for asynchronous waiting (handler cannot exceed the 15min lambda timeout).

The provider has a built-in singleton method which uses the resource type as a stack-unique identifier and returns the service token:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 String serviceToken = CustomResourceProvider.getOrCreate(this, "Custom::MyCustomResourceType", new CustomResourceProviderProps()
         .codeDirectory(String.format("%s/my-handler", __dirname))
         .runtime(CustomResourceProviderRuntime.getNODEJS_12_X())
         .description("Lambda function created by the custom resource provider"));
 
 new CustomResource(this, "MyResource", new CustomResourceProps()
         .resourceType("Custom::MyCustomResourceType")
         .serviceToken(serviceToken));
 

The directory (my-handler in the above example) must include an index.js file. It cannot import external dependencies or files outside this directory. It must export an async function named handler. This function accepts the CloudFormation resource event object and returns an object with the following structure:

 exports.handler = async function(event) {
   const id = event.PhysicalResourceId; // only for "Update" and "Delete"
   const props = event.ResourceProperties;
   const oldProps = event.OldResourceProperties; // only for "Update"s
 
   switch (event.RequestType) {
     case "Create":
       // ...
 
     case "Update":
       // ...
 
       // if an error is thrown, a FAILED response will be submitted to CFN
       throw new Error('Failed!');
 
     case "Delete":
       // ...
   }
 
   return {
     // (optional) the value resolved from `resource.ref`
     // defaults to "event.PhysicalResourceId" or "event.RequestId"
     PhysicalResourceId: "REF",
 
     // (optional) calling `resource.getAtt("Att1")` on the custom resource in the CDK app
     // will return the value "BAR".
     Data: {
       Att1: "BAR",
       Att2: "BAZ"
     },
 
     // (optional) user-visible message
     Reason: "User-visible message",
 
     // (optional) hides values from the console
     NoEcho: true
   };
 }
 

Here is an complete example of a custom resource that summarizes two numbers:

sum-handler/index.js:

 exports.handler = async (e) => {
   return {
     Data: {
       Result: e.ResourceProperties.lhs + e.ResourceProperties.rhs,
     },
   };
 };
 

sum.ts:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 import software.amazon.awscdk.core.Construct;
 import software.amazon.awscdk.core.CustomResource;
 import software.amazon.awscdk.core.CustomResourceProvider;
 import software.amazon.awscdk.core.CustomResourceProviderRuntime;
 import software.amazon.awscdk.core.Token;
 
 public class SumProps {
     private Number lhs;
     public Number getLhs() {
         return this.lhs;
     }
     public SumProps lhs(Number lhs) {
         this.lhs = lhs;
         return this;
     }
     private Number rhs;
     public Number getRhs() {
         return this.rhs;
     }
     public SumProps rhs(Number rhs) {
         this.rhs = rhs;
         return this;
     }
 }
 
 public class Sum extends Construct {
     public final Number result;
 
     public Sum(Construct scope, String id, SumProps props) {
         super(scope, id);
 
         String resourceType = "Custom::Sum";
         String serviceToken = CustomResourceProvider.getOrCreate(this, resourceType, new CustomResourceProviderProps()
                 .codeDirectory(String.format("%s/sum-handler", __dirname))
                 .runtime(CustomResourceProviderRuntime.getNODEJS_12_X()));
 
         CustomResource resource = new CustomResource(this, "Resource", new CustomResourceProps()
                 .resourceType(resourceType)
                 .serviceToken(serviceToken)
                 .properties(Map.of(
                         "lhs", props.getLhs(),
                         "rhs", props.getRhs())));
 
         this.result = Token.asNumber(resource.getAtt("Result"));
     }
 }
 

Usage will look like this:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Sum sum = new Sum(this, "MySum", new SumProps().lhs(40).rhs(2));
 new CfnOutput(this, "Result", new CfnOutputProps().value(Token.asString(sum.getResult())));
 

To access the ARN of the provider's AWS Lambda function role, use the getOrCreateProvider() built-in singleton method:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CustomResourceProvider provider = CustomResourceProvider.getOrCreateProvider(this, "Custom::MyCustomResourceType", new CustomResourceProviderProps()
         .codeDirectory(String.format("%s/my-handler", __dirname))
         .runtime(CustomResourceProviderRuntime.getNODEJS_12_X()));
 
 String roleArn = provider.getRoleArn();
 

This role ARN can then be used in resource-based IAM policies.

The Custom Resource Provider Framework

The @aws-cdk/custom-resources module includes an advanced framework for implementing custom resource providers.

Handlers are implemented as AWS Lambda functions, which means that they can be implemented in any Lambda-supported runtime. Furthermore, this provider has an asynchronous mode, which means that users can provide an isComplete lambda function which is called periodically until the operation is complete. This allows implementing providers that can take up to two hours to stabilize.

Set serviceToken to provider.serviceToken to use this type of provider:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Provider provider = new Provider(this, "MyProvider", new ProviderProps()
         .onEventHandler(onEventHandler)
         .isCompleteHandler(isCompleteHandler));
 
 new CustomResource(this, "MyResource", new CustomResourceProps()
         .serviceToken(provider.getServiceToken()));
 

See the documentation for more details.

AWS CloudFormation features

A CDK stack synthesizes to an AWS CloudFormation Template. This section explains how this module allows users to access low-level CloudFormation features when needed.

Stack Outputs

CloudFormation stack outputs and exports are created using the CfnOutput class:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CfnOutput(this, "OutputName", new CfnOutputProps()
         .value(myBucket.getBucketName())
         .description("The name of an S3 bucket")// Optional
         .exportName("TheAwesomeBucket"));
 

Parameters

CloudFormation templates support the use of Parameters to customize a template. They enable CloudFormation users to input custom values to a template each time a stack is created or updated. While the CDK design philosophy favors using build-time parameterization, users may need to use CloudFormation in a number of cases (for example, when migrating an existing stack to the AWS CDK).

Template parameters can be added to a stack by using the CfnParameter class:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CfnParameter(this, "MyParameter", new CfnParameterProps()
         .type("Number")
         .default(1337));
 

The value of parameters can then be obtained using one of the value methods. As parameters are only resolved at deployment time, the values obtained are placeholder tokens for the real value (Token.isUnresolved() would return true for those):

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnParameter param = new CfnParameter(this, "ParameterName", new CfnParameterProps());
 
 // If the parameter is a String
 param.getValueAsString();
 
 // If the parameter is a Number
 param.getValueAsNumber();
 
 // If the parameter is a List
 param.getValueAsList();
 

Pseudo Parameters

CloudFormation supports a number of pseudo parameters, which resolve to useful values at deployment time. CloudFormation pseudo parameters can be obtained from static members of the Aws class.

It is generally recommended to access pseudo parameters from the scope's stack instead, which guarantees the values produced are qualifying the designated stack, which is essential in cases where resources are shared cross-stack:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 // "this" is the current construct
 Stack stack = Stack.of(this);
 
 stack.getAccount();// Returns the AWS::AccountId for this stack (or the literal value if known)
 stack.getRegion();// Returns the AWS::Region for this stack (or the literal value if known)
 stack.getPartition();
 

Resource Options

CloudFormation resources can also specify resource attributes. The CfnResource class allows accessing those through the cfnOptions property:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnBucket rawBucket = new CfnBucket(this, "Bucket", new CfnBucketProps());
 // -or-
 CfnBucket rawBucketAlt = (CfnBucket)myBucket.node.getDefaultChild();
 
 // then
 rawBucket.cfnOptions.getCondition() = new CfnCondition(this, "EnableBucket", new CfnConditionProps());
 rawBucket.cfnOptions.getMetadata() = Map.of(
         "metadataKey", "MetadataValue");
 

Resource dependencies (the DependsOn attribute) is modified using the cfnResource.addDependsOn method:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnResource resourceA = new CfnResource(this, "ResourceA", resourceProps);
 CfnResource resourceB = new CfnResource(this, "ResourceB", resourceProps);
 
 resourceB.addDependsOn(resourceA);
 

Intrinsic Functions and Condition Expressions

CloudFormation supports intrinsic functions. These functions can be accessed from the Fn class, which provides type-safe methods for each intrinsic function as well as condition expressions:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 // To use Fn::Base64
 Fn.base64("SGVsbG8gQ0RLIQo=");
 
 // To compose condition expressions:
 CfnParameter environmentParameter = new CfnParameter(this, "Environment");
 Fn.conditionAnd(Fn.conditionEquals("Production", environmentParameter), Fn.conditionNot(Fn.conditionEquals("us-east-1", Aws.REGION)));
 

When working with deploy-time values (those for which Token.isUnresolved returns true), idiomatic conditionals from the programming language cannot be used (the value will not be known until deployment time). When conditional logic needs to be expressed with un-resolved values, it is necessary to use CloudFormation conditions by means of the CfnCondition class:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnParameter environmentParameter = new CfnParameter(this, "Environment");
 CfnCondition isProd = new CfnCondition(this, "IsProduction", new CfnConditionProps()
         .expression(Fn.conditionEquals("Production", environmentParameter)));
 
 // Configuration value that is a different string based on IsProduction
 String stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString();
 
 // Make Bucket creation condition to IsProduction by accessing
 // and overriding the CloudFormation resource
 Bucket bucket = new Bucket(this, "Bucket");
 CfnBucket cfnBucket = (CfnBucket)myBucket.node.getDefaultChild();
 cfnBucket.cfnOptions.getCondition() = isProd;
 

Mappings

CloudFormation mappings are created and queried using the CfnMappings class:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnMapping regionTable = new CfnMapping(this, "RegionTable", new CfnMappingProps()
         .mapping(Map.of(
                 "regionName", Map.of(
                         "us-east-1", "US East (N. Virginia)",
                         "us-east-2", "US East (Ohio)"))));
 
 regionTable.findInMap("regionName", Aws.REGION);
 

This will yield the following template:

 Mappings:
   RegionTable:
     regionName:
       us-east-1: US East (N. Virginia)
       us-east-2: US East (Ohio)
 

Mappings can also be synthesized "lazily"; lazy mappings will only render a "Mappings" section in the synthesized CloudFormation template if some findInMap call is unable to immediately return a concrete value due to one or both of the keys being unresolved tokens (some value only available at deploy-time).

For example, the following code will not produce anything in the "Mappings" section. The call to findInMap will be able to resolve the value during synthesis and simply return 'US East (Ohio)'.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnMapping regionTable = new CfnMapping(this, "RegionTable", new CfnMappingProps()
         .mapping(Map.of(
                 "regionName", Map.of(
                         "us-east-1", "US East (N. Virginia)",
                         "us-east-2", "US East (Ohio)")))
         .lazy(true));
 
 regionTable.findInMap("regionName", "us-east-2");
 

On the other hand, the following code will produce the "Mappings" section shown above, since the second-level key is an unresolved token. The call to findInMap will return a token that resolves to { Fn::FindInMap: [ 'RegionTable', 'regionName', { Ref: AWS::Region } ] }.

 // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
 regionTable.findInMap("regionName", Aws.REGION);
 

Dynamic References

CloudFormation supports dynamically resolving values for SSM parameters (including secure strings) and Secrets Manager. Encoding such references is done using the CfnDynamicReference class:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CfnDynamicReference(CfnDynamicReferenceService.getSECRETS_MANAGER(), "secret-id:secret-string:json-key:version-stage:version-id");
 

Template Options & Transform

CloudFormation templates support a number of options, including which Macros or Transforms to use when deploying the stack. Those can be configured using the stack.templateOptions property:

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Stack stack = new Stack(app, "StackName");
 
 stack.templateOptions.getDescription() = "This will appear in the AWS console";
 stack.templateOptions.getTransforms() = List.of("AWS::Serverless-2016-10-31");
 stack.templateOptions.getMetadata() = Map.of(
         "metadataKey", "MetadataValue");
 

Emitting Raw Resources

The CfnResource class allows emitting arbitrary entries in the Resources section of the CloudFormation template.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CfnResource(this, "ResourceId", new CfnResourceProps()
         .type("AWS::S3::Bucket")
         .properties(Map.of(
                 "BucketName", "bucket-name")));
 

As for any other resource, the logical ID in the CloudFormation template will be generated by the AWS CDK, but the type and properties will be copied verbatim in the synthesized template.

Including raw CloudFormation template fragments

When migrating a CloudFormation stack to the AWS CDK, it can be useful to include fragments of an existing template verbatim in the synthesized template. This can be achieved using the CfnInclude class.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 new CfnInclude(this, "ID", new CfnIncludeProps()
         .template(Map.of(
                 "Resources", Map.of(
                         "Bucket", Map.of(
                                 "Type", "AWS::S3::Bucket",
                                 "Properties", Map.of(
                                         "BucketName", "my-shiny-bucket"))))));
 

Termination Protection

You can prevent a stack from being accidentally deleted by enabling termination protection on the stack. If a user attempts to delete a stack with termination protection enabled, the deletion fails and the stack--including its status--remains unchanged. Enabling or disabling termination protection on a stack sets it for any nested stacks belonging to that stack as well. You can enable termination protection on a stack by setting the terminationProtection prop to true.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 Stack stack = new Stack(app, "StackName", new StackProps()
         .terminationProtection(true));
 

By default, termination protection is disabled.

CfnJson

CfnJson allows you to postpone the resolution of a JSON blob from deployment-time. This is useful in cases where the CloudFormation JSON template cannot express a certain value.

A common example is to use CfnJson in order to render a JSON map which needs to use intrinsic functions in keys. Since JSON map keys must be strings, it is impossible to use intrinsics in keys and CfnJson can help.

The following example defines an IAM role which can only be assumed by principals that are tagged with a specific tag.

 // Example automatically generated. See https://github.com/aws/jsii/issues/826
 CfnParameter tagParam = new CfnParameter(this, "TagName");
 
 CfnJson stringEquals = new CfnJson(this, "ConditionJson", new CfnJsonProps()
         .value(Map.of(
                 String.format("aws:PrincipalTag/%s", tagParam.getValueAsString()), true)));
 
 IPrincipal principal = new iam.AccountRootPrincipal().withConditions(Map.of(
         "StringEquals", stringEquals));
 
 new Role(this, "MyRole", new RoleProps().assumedBy(principal));
 

Explanation: since in this example we pass the tag name through a parameter, it can only be resolved during deployment. The resolved value can be represented in the template through a { "Ref": "TagName" }. However, since we want to use this value inside a aws:PrincipalTag/TAG-NAME IAM operator, we need it in the key of a StringEquals condition. JSON keys must be strings, so to circumvent this limitation, we use CfnJson to "delay" the rendition of this template section to deploy-time. This means that the value of StringEquals in the template will be { "Fn::GetAtt": [ "ConditionJson", "Value" ] }, and will only "expand" to the operator we synthesized during deployment.

Stack Resource Limit

When deploying to AWS CloudFormation, it needs to keep in check the amount of resources being added inside a Stack. Currently it's possible to check the limits in the AWS CloudFormation quotas page.

It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources).

Set the context key @aws-cdk/core:stackResourceLimit with the proper value, being 0 for disable the limit of resources.

Skip navigation links