How do I customize a resource property value when there is a gap between CDK higher level constructs and a CloudFormation resource?

4 minute read
7

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:

  1. Retrieve generated subnets inside the Amazon VPC (which are the L2 PublicSubnet construct and the L2 PrivateSubnet construct).
  2. Use the AWS CDK escape hatch, node.default_child, on the L2 constructs and cast it as the L1 CfnSubnet resource.
  3. Modify the cidr_block directly or by using raw overrides.
  4. 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

AWS OFFICIAL
AWS OFFICIALUpdated a year ago