-
-
Save milesjordan/d86942718f8d4dc20f9f331913e7367a to your computer and use it in GitHub Desktop.
--- | |
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 |
The routing issue looks to fixed now.
I suggest adding DependsOn: IPv6CidrBlock
to the AWS::EC2::Subnet
resources.
Otherwise you can get a race condition with the Subnet failing on the GetAtt VPC.Ipv6CidrBlocks
operation.
Thanks for this post!
Thanks for your work! I based my own template on it and found !Cidr ( https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-cidr.html) to make the subnet calculation more simple for a scenario with multiple subnets.
thanks for the ipv6 subnet piece.
Thanks for this post it really helped me !!!
I suggest adding
DependsOn: IPv6CidrBlock
to theAWS::EC2::Subnet
resources.Otherwise you can get a race condition with the Subnet failing on the
GetAtt VPC.Ipv6CidrBlocks
operation.
+1
I suggest using intrinsic function Fn::Cidr to break the /48 VPC Cidr block into /64 rather than hard coding the SubnetPart.
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!
This doesn't currently work due to an issue in cloudformation that prevents Egress Only Internet Gateways from routing properly. Let's hope it's fixed soon!