AWS Cloud Development Kit Core Library
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.
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:
Duration.seconds(300)
Duration.minutes(5)
Duration.hours(1)
Duration.days(7)
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:
Size.kibibytes(200)
Size.mebibytes(5)
Size.gibibytes(40)
Size.tebibytes(200)
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.
Size.mebibytes(2).toKibibytes()
Size.kibibytes(2050).toMebibyte({ integral: false })
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
:
const secret = SecretValue.secretsManager('secretId', {
jsonField: 'password'
versionId: 'id'
versionStage: 'stage'
});
Using AWS Secrets Manager is the recommended way to reference secrets in a CDK app.
SecretValue
also supports the following secret sources:
SecretValue.plainText(secret)
: stores the secret as plain text in your app and the resulting template (not recommended).SecretValue.ssmSecure(param, version)
: refers to a secret stored as a SecureString in the SSM Parameter Store.SecretValue.cfnParameter(param)
: refers to a secret passed through a CloudFormation parameter (must have NoEcho: true
).SecretValue.cfnDynamicReference(dynref)
: refers to a secret described by a CloudFormation dynamic reference (used by ssmSecure
and secretsManager
).
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:
stack.formatArn({
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.
const arnComponents = stack.parseArn(arn, ':');
const functionName = arnComponents.resourceName;
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
construts, constructB
and constructC
:
const bAndC = new ConcreteDependable();
bAndC.add(constructB);
bAndC.add(constructC);
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:
- Cyclic dependencies are not allowed, so if
stackA
is using resources from
stackB
, the reverse is not possible anymore. - Stacks with dependencies between them are treated specially by the CDK
toolkit:
- If
stackA
depends on stackB
, running cdk deploy stackA
will also
automatically deploy stackB
. stackB
's deployment will be performed before stackA
's deployment.
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:
new CfnOutput(this, 'OutputName', {
value: bucket.bucketName,
description: 'The name of an S3 bucket',
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:
new CfnParameter(this, 'MyParameter', {
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):
const param = new CfnParameter(this, 'ParameterName', { });
param.valueAsString;
param.valueAsNumber;
param.valueAsList;
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:
const stack = Stack.of(this);
stack.account;
stack.region;
stack.partition;
Resource Options
CloudFormation resources can also specify resource
attributes. The CfnResource
class allows
accessing those through the cfnOptions
property:
const rawBucket = new s3.CfnBucket(this, 'Bucket', { });
const rawBucket = bucket.node.defaultChild as s3.CfnBucket;
rawBucket.cfnOptions.condition = new CfnCondition(this, 'EnableBucket', { });
rawBucket.cfnOptions.metadata = {
metadataKey: 'MetadataValue',
};
Resource dependencies (the DependsOn
attribute) is modified using the
cfnResource.addDependsOn
method:
const resourceA = new CfnResource(this, 'ResourceA', { });
const resourceB = new CfnResource(this, 'ResourceB', { });
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:
Fn.base64('SGVsbG8gQ0RLIQo=');
const 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:
const environmentParameter = new CfnParameter(this, 'Environment');
const isProd = new CfnCondition(this, 'IsProduction', {
expression: Fn.conditionEquals('Production', environmentParameter),
});
const stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString();
const bucket = new s3.Bucket(this, 'Bucket');
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;
cfnBucket.cfnOptions.condition = isProd;
Mappings
CloudFormation mappings are created and queried using the
CfnMappings
class:
const mapping = new CfnMapping(this, 'MappingTable', {
mapping: {
regionName: {
'us-east-1': 'US East (N. Virginia)',
'us-east-2': 'US East (Ohio)',
},
}
});
mapping.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:
new CfnDynamicReference(this, 'SecureStringValue', {
service: CfnDynamicReferenceService.SECRETS_MANAGER,
referenceKey: '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:
const stack = new Stack(app, 'StackName');
stack.templateOptions.description = 'This will appear in the AWS console';
stack.templateOptions.transforms = ['AWS::Serverless-2016-10-31'];
stack.templateOptions.metadata = {
metadataKey: 'MetadataValue',
};
Emitting Raw Resources
The CfnResource
class allows emitting arbitrary entries in the
Resources section of the CloudFormation template.
new CfnResource(this, 'ResourceId', {
type: 'AWS::S3::Bucket',
properties: {
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.
new CfnInclude(this, 'ID', {
template: {
Resources: {
Bucket: {
Type: 'AWS::S3::Bucket',
Properties: {
BucketName: 'my-shiny-bucket'
}
}
}
},
});