Package: aws-cdk.cloudformation-include
Include CloudFormation templates in the CDK---AWS CDK v1 has reached End-of-Support on 2023-06-01.
This package is no longer being updated, and users should migrate to AWS CDK v2.For more information on how to migrate, see theMigrating to AWS CDK v2guide.This module contains a set of classes whose goal is to facilitate working
with existing CloudFormation templates in the CDK.
It can be thought of as an extension of the capabilities of theCfnIncludeclass.Basic usageAssume we have a file with an existing template.
It could be in JSON format, in a filemy-template.json:{"Resources":{"Bucket":{"Type":"AWS::S3::Bucket","Properties":{"BucketName":"some-bucket-name"}}}}Or it could by in YAML format, in a filemy-template.yaml:Resources:Bucket:Type:AWS::S3::BucketProperties:BucketName:some-bucket-nameIt can be included in a CDK application with the following code:cfn_template=cfn_inc.CfnInclude(self,"Template",template_file="my-template.json")Or, if your template uses YAML:cfn_template=cfn_inc.CfnInclude(self,"Template",template_file="my-template.yaml")Note: different YAML parsers sometimes don't agree on what exactly constitutes valid YAML.
If you get a YAML exception when including your template,
try converting it to JSON, and including that file instead.
If you're downloading your template from the CloudFormation AWS Console,
you can easily get it in JSON format by clicking the 'View in Designer'
button on the 'Template' tab -
once in Designer, select JSON in the "Choose template language"
radio buttons on the bottom pane.This will add all resources frommy-template.json/my-template.yamlinto the CDK application,
preserving their original logical IDs from the template file.Note that this including process willnotexecute anyCloudFormation transforms-
including theServerless transform.Any resource from the included template can be retrieved by referring to it by its logical ID from the template.
If you know the class of the CDK object that corresponds to that resource,
you can cast the returned object to the correct type:# cfn_template: cfn_inc.CfnIncludecfn_bucket=cfn_template.get_resource("Bucket")Note that any resources not present in the latest version of the CloudFormation schema
at the time of publishing the version of this module that you depend on,
includingCustom Resources,
will be returned as instances of the classCfnResource,
and so cannot be cast to a different resource type.Any modifications made to that resource will be reflected in the resulting CDK template;
for example, the name of the bucket can be changed:# cfn_template: cfn_inc.CfnIncludecfn_bucket=cfn_template.get_resource("Bucket")cfn_bucket.bucket_name="my-bucket-name"You can also refer to the resource when defining other constructs,
including the higher-level ones
(those whose name does not start withCfn),
for example:# cfn_template: cfn_inc.CfnIncludecfn_bucket=cfn_template.get_resource("Bucket")role=iam.Role(self,"Role",assumed_by=iam.AnyPrincipal())role.add_to_policy(iam.PolicyStatement(actions=["s3:*"],resources=[cfn_bucket.attr_arn]))Converting L1 resources to L2The resources thegetResourcemethod returns are what the CDK callsLayer 1 resources(likeCfnBucket).
However, in many places in the Construct Library,
the CDK requires so-called Layer 2 resources, likeIBucket.
There are two ways of going from an L1 to an L2 resource.UsingfromCfn*()methodsThis is the preferred method of converting an L1 resource to an L2.
It works by invoking a static method of the class of the L2 resource
whose name starts withfromCfn-
for example, for KMS Keys, that would be theKms.fromCfnKey()method -
and passing the L1 instance as an argument:# cfn_template: cfn_inc.CfnIncludecfn_key=cfn_template.get_resource("Key")key=kms.Key.from_cfn_key(cfn_key)This returns an instance of thekms.IKeytype that can be passed anywhere in the CDK anIKeyis expected.
What is more, thatIKeyinstance will be mutable -
which means calling any mutating methods on it,
likeaddToResourcePolicy(),
will be reflected in the resulting template.Note that, in some cases, thefromCfn*()method might not be able to create an L2 from the underlying L1.
This can happen when the underlying L1 heavily uses CloudFormation functions.
For example, if you tried to create an L2IKeyfrom an L1 represented as this CloudFormation template:{"Resources":{"Key":{"Type":"AWS::KMS::Key","Properties":{"KeyPolicy":{"Statement":[{"Fn::If":["Condition",{"Action":"kms:if-action","Resource":"*","Principal":"*","Effect":"Allow"},{"Action":"kms:else-action","Resource":"*","Principal":"*","Effect":"Allow"}]}],"Version":"2012-10-17"}}}}}TheKey.fromCfnKey()method does not know how to translate that into CDK L2 concepts,
and would throw an exception.In those cases, you need the use the second method of converting an L1 to an L2.Usingfrom*Name/Arn/Attributes()methodsIf the resource you need does not have afromCfn*()method,
or if it does, but it throws an exception for your particular L1,
you need to use the second method of converting an L1 resource to L2.Each L2 class has static factory methods with names likefrom*Name(),from*Arn(), and/orfrom*Attributes().
You can obtain an L2 resource from an L1 by passing the correct properties of the L1 as the arguments to those methods:# cfn_template: cfn_inc.CfnInclude# using from*Attributes()# private_cfn_subnet1: ec2.CfnSubnet# private_cfn_subnet2: ec2.CfnSubnet# using from*Name()cfn_bucket=cfn_template.get_resource("Bucket")bucket=s3.Bucket.from_bucket_name(self,"L2Bucket",cfn_bucket.ref)# using from*Arn()cfn_key=cfn_template.get_resource("Key")key=kms.Key.from_key_arn(self,"L2Key",cfn_key.attr_arn)cfn_vpc=cfn_template.get_resource("Vpc")vpc=ec2.Vpc.from_vpc_attributes(self,"L2Vpc",vpc_id=cfn_vpc.ref,availability_zones=core.Fn.get_azs(),private_subnet_ids=[private_cfn_subnet1.ref,private_cfn_subnet2.ref])As long as they just need to be referenced,
and not changed in any way, everything should work;
however, note that resources returned from those methods,
unlike those returned byfromCfn*()methods,
are immutable, which means calling any mutating methods on them will have no effect.
You will have to mutate the underlying L1 in order to change them.Non-resource template elementsIn addition to resources,
you can also retrieve and mutate all other template elements:Parameters:# cfn_template: cfn_inc.CfnIncludeparam=cfn_template.get_parameter("MyParameter")# mutating the parameterparam.default="MyDefault"Conditions:# cfn_template: cfn_inc.CfnIncludecondition=cfn_template.get_condition("MyCondition")# mutating the conditioncondition.expression=core.Fn.condition_equals(1,2)Mappings:# cfn_template: cfn_inc.CfnIncludemapping=cfn_template.get_mapping("MyMapping")# mutating the mappingmapping.set_value("my-region","AMI","ami-04681a1dbd79675a5")Service Catalog template Rules:# cfn_template: cfn_inc.CfnInclude# mutating the rule# my_parameter: core.CfnParameterrule=cfn_template.get_rule("MyRule")rule.add_assertion(core.Fn.condition_contains(["m1.small"],my_parameter.value_as_string),"MyParameter has to be m1.small")Outputs:# cfn_template: cfn_inc.CfnInclude# mutating the output# cfn_bucket: s3.CfnBucketoutput=cfn_template.get_output("MyOutput")output.value=cfn_bucket.attr_arnHooks for blue-green deployments:# cfn_template: cfn_inc.CfnInclude# mutating the hook# my_role: iam.Rolehook=cfn_template.get_hook("MyOutput")code_deploy_hook=hookcode_deploy_hook.service_role=my_role.role_arnParameter replacementIf your existing template uses CloudFormation Parameters,
you may want to remove them in favor of build-time values.
You can do that using theparametersproperty:cfn_inc.CfnInclude(self,"includeTemplate",template_file="path/to/my/template",parameters={"MyParam":"my-value"})This will replace all references toMyParamwith the string'my-value',
andMyParamwill be removed from the 'Parameters' section of the resulting template.Nested StacksThis module also supports templates that usenested stacks.For example, if you have the following parent template:{"Resources":{"ChildStack":{"Type":"AWS::CloudFormation::Stack","Properties":{"TemplateURL":"https://my-s3-template-source.s3.amazonaws.com/child-stack.json"}}}}where the child template pointed to byhttps://my-s3-template-source.s3.amazonaws.com/child-stack.jsonis:{"Resources":{"MyBucket":{"Type":"AWS::S3::Bucket"}}}You can include both the parent stack,
and the nested stack in your CDK application as follows:parent_template=cfn_inc.CfnInclude(self,"ParentStack",template_file="path/to/my-parent-template.json",load_nested_stacks={"ChildStack":cfn_inc.CfnIncludeProps(template_file="path/to/my-nested-template.json")})Here,path/to/my-nested-template.jsonrepresents the path on disk to the downloaded template file from the original template URL of the nested stack
(https://my-s3-template-source.s3.amazonaws.com/child-stack.json).
In the CDK application,
this file will be turned into anAsset,
and theTemplateURLproperty of the nested stack resource
will be modified to point to that asset.The included nested stack can be accessed with thegetNestedStackmethod:# parent_template: cfn_inc.CfnIncludeincluded_child_stack=parent_template.get_nested_stack("ChildStack")child_stack=included_child_stack.stackchild_template=included_child_stack.included_templateNow you can reference resources fromChildStack,
and modify them like any other included template:# child_template: cfn_inc.CfnIncludecfn_bucket=child_template.get_resource("MyBucket")cfn_bucket.bucket_name="my-new-bucket-name"role=iam.Role(self,"MyRole",assumed_by=iam.AccountRootPrincipal())role.add_to_policy(iam.PolicyStatement(actions=["s3:GetObject*","s3:GetBucket*","s3:List*"],resources=[cfn_bucket.attr_arn]))You can also include the nested stack after theCfnIncludeobject was created,
instead of doing it on construction:# parent_template: cfn_inc.CfnIncludeincluded_child_stack=parent_template.load_nested_stack("ChildTemplate",template_file="path/to/my-nested-template.json")Vending CloudFormation templates as ConstructsIn many cases, there are existing CloudFormation templates that are not entire applications,
but more like specialized fragments, implementing a particular pattern or best practice.
If you have templates like that,
you can use theCfnIncludeclass to vend them as CDK Constructs:fromconstructsimportConstructimportaws_cdk.cloudformation_includeascfn_incimportpathaspathclassMyConstruct(Construct):def__init__(self,scope,id):super().__init__(scope,id)# include a template inside the Constructcfn_inc.CfnInclude(self,"MyConstruct",template_file=path.join(__dirname,"my-template.json"),preserve_logical_ids=False)Notice thepreserveLogicalIdsparameter -
it makes sure the logical IDs of all the included template elements are re-named using CDK's algorithm,
guaranteeing they are unique within your application.
Without that parameter passed,
instantiatingMyConstructtwice in the same Stack would result in duplicated logical IDs.