I want to modify a resource property value when there's a gap between AWS Cloud Development Kit (AWS CDK) L3/L2 constructs and an AWS CloudFormation.
Short description
In some cases, higher level constructs (L3 and L2) will have a resource property that can't be modified. To work around this issue, use AWS CDK escape hatches to move to a lower level of abstraction and modify the resource property value.
Example of an Amazon Virtual Private Cloud (Amazon VPC) using AWS CDK Python:
vpc = ec2.Vpc(self, "MyCDKVPC",
max_azs=2,
cidr='60.0.0.0/16',
subnet_configuration=[
ec2.SubnetConfiguration(
name="public",
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24,
),
ec2.SubnetConfiguration(
name="private",
subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT,
cidr_mask=24,
)
]
)
The preceding example Amazon VPC is defined using the L2 construct aws_cdk.aws_ec2.Vpc, which has two Availability Zones (AZ) with the CidrBlock set to 60.0.0.0/16. The example Amazon VPC also contains two PublicSubnets and two PrivateSubnets spread across the two AZs.
When generating a CloudFormation to check the AWS::EC2::Subnet resource, the CidrBlock will start from the first IP range 60.0.0.0/24 and can't be modified.
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.0.0/24
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.1.0/24
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.2.0/24
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.3.0/24
To resolve this issue, do these steps:
- Retrieve generated subnets inside the Amazon VPC (which are the L2 PublicSubnet construct and the L2 PrivateSubnet construct).
- Use the AWS CDK escape hatch, node.default_child, on the L2 constructs and cast it as the L1 CfnSubnet resource.
- Modify the cidr_block directly or by using raw overrides.
- Verify the cidr_block update on the CloudFormation template.
Resolution
To use an AWS CDK escape hatch to modify the CidrBlock value of a lower abstraction layer for PublicSubnets or PrivateSubnets, do these steps:
Important: The following steps apply to PublicSubnets. To apply to PrivateSubnets, replace all instances of PublicSubnet with PrivateSubnet.
1. Retrieve a list of PublicSubnets in the Amazon VPC by using the vpc.public_subnets attribute:
public_subnets = vpc.public_subnets
Note: Each element inside the generated list is a L2 PublicSubnet construct. See the following example printout:
########## confirm public_subnets is a L2 construct ##########
print(public_subnets)
# printout: [<aws_cdk.aws_ec2.PublicSubnet object at 0x7f3f48acb490>, <aws_cdk.aws_ec2.PublicSubnet object at 0x7f3f48acb050
2. Use the node.default_child attribute on the desired L2 construct (for this example aws_cdk.aws_ec2.PublicSubnet). Then, cast it as the L1 CfnSubnet resource (for this example aws_cdk.aws_ec2.CfnSubnet):
########## confirm cfn_public_subnet is a L1 construct ##########
for public_subnet in public_subnets:
cfn_public_subnet = public_subnet.node.default_child
print(cfn_public_subnet)
# printout: <aws_cdk.aws_ec2.CfnSubnet object at 0x7f3f48acb710>
# printout: <aws_cdk.aws_ec2.CfnSubnet object at 0x7f3f48acb950>
3. After accessing the L1 CfnSubnet resource, modify the CidrBlock on the L1 CfnSubnet construct by using one of the following methods:
- Modify the cidr_block directly
- Modify the cidr_block by using raw overrides
Example of modifying the cidr_block directly or by using raw overrides:
public_subnets = vpc.public_subnets
public_subnet_index = 0
for public_subnet in public_subnets:
cfn_public_subnet = public_subnet.node.default_child
########### 1) modify the cidr_block property directly ###########
cfn_public_subnet.cidr_block = "60.0." + str(public_subnet_index + example_start_value) + ".0/24")
########### 2) modify the cidr_block by using raw overrides ###########
cfn_public_subnet.add_property_override("CidrBlock", "60.0." + str(public_subnet_index + example_start_value) + ".0/24")
public_subnet_index += 1
Important: Make sure to replace example_start_value with your specified value. For example, if you want to modify your public_subnet to start from 60.0.100.0/24, then set your example_start_value to 100.
4. Verify the CidrBlock update inside the AWS::EC2::Subnet resource on the newly generated CloudFormation template by running the cdk synth command:
cdk synth
Example output:
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.100.0/24 <---
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: 60.0.101.0/24
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: <example_custom_value>/24
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
...
CidrBlock: <example_custom_value>/24
Related information
PrivateSubnet
vpc.private_subnets