Last active
September 26, 2024 20:08
-
-
Save milesjordan/d86942718f8d4dc20f9f331913e7367a to your computer and use it in GitHub Desktop.
Cloudformation template for a VPC with ipv6, with public and private subnets, calculating the subnet ipv6 CIDR blocks on the fly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
AWSTemplateFormatVersion: '2010-09-09' | |
Description: Public VPC and subnets | |
Resources: | |
# | |
# Public VPC | |
# | |
PublicVpc: | |
Type: AWS::EC2::VPC | |
Properties: | |
CidrBlock: 172.31.0.0/16 | |
InstanceTenancy: default | |
Tags: | |
- Key: Name | |
Value: Public VPC | |
IPv6CidrBlock: | |
Type: AWS::EC2::VPCCidrBlock | |
Properties: | |
VpcId: !Ref PublicVpc | |
AmazonProvidedIpv6CidrBlock: true | |
# | |
# Internet gateways (ipv4, and egress for ipv6) | |
# | |
InternetGateway: | |
Type: AWS::EC2::InternetGateway | |
Properties: | |
Tags: | |
- Key: Name | |
Value: Public VPC Internet Access | |
InternetGatewayAttachment: | |
Type: AWS::EC2::VPCGatewayAttachment | |
Properties: | |
VpcId: !Ref PublicVpc | |
InternetGatewayId: !Ref InternetGateway | |
EgressOnlyInternetGateway: | |
Type: AWS::EC2::EgressOnlyInternetGateway | |
Properties: | |
VpcId: !Ref PublicVpc | |
# | |
# Routing - public subnets | |
# | |
PublicSubnetRouteTable: | |
Type: AWS::EC2::RouteTable | |
Properties: | |
VpcId: !Ref PublicVpc | |
Tags: | |
- Key: Name | |
Value: Route Table for Public Subnets in Public VPC | |
PublicSubnetDefaultRoute: | |
DependsOn: InternetGatewayAttachment | |
Type: AWS::EC2::Route | |
Properties: | |
DestinationCidrBlock: 0.0.0.0/0 | |
RouteTableId: !Ref PublicSubnetRouteTable | |
GatewayId: !Ref InternetGateway | |
PublicSubnetDefaultIpv6Route: | |
Type: AWS::EC2::Route | |
Properties: | |
DestinationIpv6CidrBlock: ::/0 | |
RouteTableId: !Ref PublicSubnetRouteTable | |
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway | |
# | |
# Routing - private subnets | |
# | |
PrivateSubnetRouteTable: | |
Type: AWS::EC2::RouteTable | |
Properties: | |
VpcId: !Ref PublicVpc | |
Tags: | |
- Key: Name | |
Value: Route Table for Private Subnets in Public VPC | |
PrivateSubnetDefaultIpv6Route: | |
Type: AWS::EC2::Route | |
Properties: | |
DestinationIpv6CidrBlock: ::/0 | |
RouteTableId: !Ref PrivateSubnetRouteTable | |
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway | |
# | |
# Access control | |
# | |
PrivateSubnetsNetworkAcl: | |
Type: AWS::EC2::NetworkAcl | |
Properties: | |
VpcId: !Ref PublicVpc | |
Tags: | |
- Key: Name | |
Value: Private Subnet on Public VPC ACL | |
PrivateSubnetsNetworkAclInboundEntry: | |
Type: AWS::EC2::NetworkAclEntry | |
Properties: | |
NetworkAclId: !Ref PrivateSubnetsNetworkAcl | |
RuleNumber: 1 | |
PortRange: | |
From: 22 # SSH | |
To: 22 | |
Protocol: 6 # TCP | |
RuleAction: allow | |
Egress: false | |
CidrBlock: 172.31.0.0/16 | |
PrivateSubnetsNetworkAclIpv6OutboundEntry: | |
Type: AWS::EC2::NetworkAclEntry | |
Properties: | |
NetworkAclId: !Ref PrivateSubnetsNetworkAcl | |
RuleNumber: 1 | |
Protocol: -1 | |
RuleAction: allow | |
Egress: true | |
Ipv6CidrBlock: ::/0 | |
PrivateSubnetsNetworkAclOutboundEntry: | |
Type: AWS::EC2::NetworkAclEntry | |
Properties: | |
NetworkAclId: !Ref PrivateSubnetsNetworkAcl | |
RuleNumber: 2 | |
Protocol: -1 | |
RuleAction: allow | |
Egress: true | |
CidrBlock: 0.0.0.0/0 | |
# | |
# Public subnet A | |
# | |
PublicSubnetA: | |
Type: AWS::EC2::Subnet | |
Properties: | |
CidrBlock: 172.31.0.0/20 | |
Ipv6CidrBlock: | |
Fn::Sub: | |
- "${VpcPart}${SubnetPart}" | |
- SubnetPart: '01::/64' | |
VpcPart: !Select [ 0, !Split [ '00::/56', !Select [ 0, !GetAtt PublicVpc.Ipv6CidrBlocks ]]] | |
AvailabilityZone: !Select [ 0, !GetAZs '' ] | |
VpcId: !Ref PublicVpc | |
MapPublicIpOnLaunch: 'true' | |
Tags: | |
- Key: Name | |
Value: Public Subnet A | |
PublicSubnetARouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !Ref PublicSubnetRouteTable | |
SubnetId: !Ref PublicSubnetA | |
# | |
# Private subnet A | |
# | |
PrivateSubnetA: | |
Type: AWS::EC2::Subnet | |
Properties: | |
CidrBlock: 172.31.48.0/20 | |
Ipv6CidrBlock: | |
Fn::Sub: | |
- "${VpcPart}${SubnetPart}" | |
- SubnetPart: 'a1::/64' | |
VpcPart: !Select [ 0, !Split [ '00::/56', !Select [ 0, !GetAtt PublicVpc.Ipv6CidrBlocks ]]] | |
AssignIpv6AddressOnCreation: true | |
AvailabilityZone: !Select [ 0, !GetAZs '' ] | |
VpcId: !Ref PublicVpc | |
Tags: | |
- Key: Name | |
Value: Private Subnet A in Public VPC | |
PrivateSubnetAAclAssociation: | |
Type: AWS::EC2::SubnetNetworkAclAssociation | |
Properties: | |
NetworkAclId: !Ref PrivateSubnetsNetworkAcl | |
SubnetId: !Ref PrivateSubnetA | |
PrivateSubnetARouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !Ref PrivateSubnetRouteTable | |
SubnetId: !Ref PrivateSubnetA |
I suggest using intrinsic function Fn::Cidr to break the /48 VPC Cidr block into /64 rather than hard coding the SubnetPart.
Indeed, it looks like the docs for this function have an example of doing exactly this (search for "Creating an IPv6 enabled VPC"): https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-cidr.html
Thanks for the suggestions! Indeed, using the newer Fn::Cidr function and adding DependsOn would be a nice addition. I'm glad this helped some of you out!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I suggest using intrinsic function Fn::Cidr to break the /48 VPC Cidr block into /64 rather than hard coding the SubnetPart.