Skip to content

Instantly share code, notes, and snippets.

@jbouse
Last active August 21, 2018 04:56
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC: Public and Private subnets'
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'VPC Parameters'
Parameters:
- ClassB
- DualStack
- NumberAZs
Parameters:
ClassB:
Description: 'Class B of VPC (10.XXX.0.0/16)'
Type: Number
Default: 0
ConstraintDescription: 'Must be in the range [0-255]'
MinValue: 0
MaxValue: 255
DualStack:
Description: 'Request IPv6 CIDR block'
Type: String
Default: 'false'
AllowedValues: ['true', 'false']
NumberAZs:
Description: 'Number of Availability Zones'
Type: Number
Default: 2
AllowedValues: [2, 3, 4]
Conditions:
Have4AZs: !Equals [!Ref NumberAZs, 4]
Have3AZs: !Or [!Condition Have4AZs, !Equals [!Ref NumberAZs, 3]]
DualStacked: !Equals [!Ref DualStack, 'true']
DualStacked3AZs: !And [!Condition DualStacked, !Condition Have3AZs]
DualStacked4AZs: !And [!Condition DualStacked, !Condition Have4AZs]
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Sub "10.${ClassB}.0.0/16"
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VPCv6CIDR:
Condition: DualStacked
Type: AWS::EC2::VPCCidrBlock
Properties:
AmazonProvidedIpv6CidrBlock: !Ref DualStack
VpcId: !Ref VPC
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub "10.${ClassB}.0.0/16"
EgressOnlyInternetGateway:
Condition: DualStacked
Type: AWS::EC2::EgressOnlyInternetGateway
Properties:
VpcId: !Ref VPC
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# Setup Subnet for each tier
# - Cut off a /20 IPv4 CIDR block for each Subnet from the /16 VPC CIDR
# - If DualStack, cut off a /64 IPv6 CIDR block for each Subnet from /56 VPCv6CIDR
# - Each tier can be referenced by a single /18 IPv4 CIDR block
# - If DualStack, each tier can be referenced by a single /66 IPv6 CIDR block
SubnetAPublic:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [0, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [0, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A public
- Key: Reach
Value: public
SubnetAPrivate:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [0, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [4, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [4, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A private
- Key: Reach
Value: private
SubnetBPublic:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [1, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B public
- Key: Reach
Value: public
SubnetBPrivate:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [1, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [5, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [5, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B private
- Key: Reach
Value: private
SubnetCPublic:
Condition: Have3AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [2, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [2, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [2, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C public
- Key: Reach
Value: public
SubnetCPrivate:
Condition: Have3AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [2, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [6, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [6, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C private
- Key: Reach
Value: private
SubnetDPublic:
Condition: Have4AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [3, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [3, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [3, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D public
- Key: Reach
Value: public
SubnetDPrivate:
Condition: Have4AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [3, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [7, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [7, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D private
- Key: Reach
Value: private
# Setup a RouteTable for each Subnet
RouteTableAPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A Public
RouteTableAPrivate:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A Private
RouteTableBPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B Public
RouteTableBPrivate:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B Private
RouteTableCPublic:
Condition: Have3AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C Public
RouteTableCPrivate:
Condition: Have3AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C Private
RouteTableDPublic:
Condition: Have4AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D Public
RouteTableDPrivate:
Condition: Have4AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D Private
# Associate each Subnet with the correct RouteTable
RouteTableAssociationAPublic:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetAPublic
RouteTableId: !Ref RouteTableAPublic
RouteTableAssociationAPrivate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetAPrivate
RouteTableId: !Ref RouteTableAPrivate
RouteTableAssociationBPublic:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetBPublic
RouteTableId: !Ref RouteTableBPublic
RouteTableAssociationBPrivate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetBPrivate
RouteTableId: !Ref RouteTableBPrivate
RouteTableAssociationCPublic:
Condition: Have3AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetCPublic
RouteTableId: !Ref RouteTableCPublic
RouteTableAssociationCPrivate:
Condition: Have3AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetCPrivate
RouteTableId: !Ref RouteTableCPrivate
RouteTableAssociationDPublic:
Condition: Have4AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetDPublic
RouteTableId: !Ref RouteTableDPublic
RouteTableAssociationDPrivate:
Condition: Have4AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetDPrivate
RouteTableId: !Ref RouteTableDPrivate
# Setup default routes for each RouteTable
# - InternetGateway for Public Subnets
# - EgressOnlyInternetGateway for Private Subnets if DualStack
RouteTablePublicAInternetRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableAPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicAInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableAPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateAInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableAPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicBInternetRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableBPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicBInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableBPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateBInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableBPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicCInternetRoute:
Condition: Have3AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableCPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicCInternetRouteIpv6:
Condition: DualStacked3AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableCPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateCInternetRouteIpv6:
Condition: DualStacked3AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableCPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicDInternetRoute:
Condition: Have4AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableDPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicDInternetRouteIpv6:
Condition: DualStacked4AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableDPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateDInternetRouteIpv6:
Condition: DualStacked4AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableDPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
# Setup our VPC Gateway Endpoints
EndpointS3:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !Ref VPC
EndpointDynamoDB:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
ServiceName: !Sub "com.amazonaws.${AWS::Region}.dynamodb"
VpcId: !Ref VPC
# Setup NetworkAcl for each tier
NetworkAclPublic:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Public
NetworkAclPrivate:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Private
# Associate each Subnet with the respective tier NetworkAcl
SubnetNetworkAclAssociationAPublic:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetAPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationAPrivate:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetAPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationBPublic:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetBPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationBPrivate:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetBPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationCPublic:
Condition: Have3AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetCPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationCPrivate:
Condition: Have3AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetCPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationDPublic:
Condition: Have4AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetDPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationDPrivate:
Condition: Have4AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetDPrivate
NetworkAclId: !Ref NetworkAclPrivate
# Setup NetworkAclEntry for each tier
# - Allow all traffic inbound & outbound for Public & Private tier
NetworkAclEntryInPublicAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: '0.0.0.0/0'
NetworkAclEntryOutPublicAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: '0.0.0.0/0'
NetworkAclEntryInPublicAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: false
Ipv6CidrBlock: '::/0'
NetworkAclEntryOutPublicAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: true
Ipv6CidrBlock: '::/0'
NetworkAclEntryInPrivateAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: '0.0.0.0/0'
NetworkAclEntryOutPrivateAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: '0.0.0.0/0'
NetworkAclEntryInPrivateAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: false
Ipv6CidrBlock: '::/0'
NetworkAclEntryOutPrivateAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: true
Ipv6CidrBlock: '::/0'
Outputs:
StackName:
Description: 'Stack name'
Value: !Ref 'AWS::StackName'
AZs:
Description: 'AZs'
Value: !Ref NumberAZs
Export:
Name: !Sub "${AWS::StackName}-AZs"
AZA:
Description: 'AZ of A'
Value: !GetAtt SubnetAPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZA"
AZB:
Description: 'AZ of B'
Value: !GetAtt SubnetBPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZB"
AZC:
Condition: Have3AZs
Description: 'AZ of C'
Value: !GetAtt SubnetCPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZC"
AZD:
Condition: Have4AZs
Description: 'AZ of D'
Value: !GetAtt SubnetDPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZD"
ClassB:
Description: 'Class B.'
Value: !Ref ClassB
Export:
Name: !Sub "${AWS::StackName}-ClassB"
VPC:
Description: 'VPC.'
Value: !Ref VPC
Export:
Name: !Sub "${AWS::StackName}-VPC"
SubnetsPublic:
Description: 'Subnets public.'
Value:
Fn::Join:
- ','
- - !Ref SubnetAPublic
- !Ref SubnetBPublic
- !If [Have3AZs, !Ref SubnetCPublic, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref SubnetDPublic, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-SubnetsPublic"
SubnetsPrivate:
Description: 'Subnets private.'
Value:
Fn::Join:
- ','
- - !Ref SubnetAPrivate
- !Ref SubnetBPrivate
- !If [Have3AZs, !Ref SubnetCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref SubnetDPrivate, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-SubnetsPrivate"
RouteTablesPublic:
Description: 'Route tables public.'
Value:
Fn::Join:
- ','
- - !Ref RouteTableAPublic
- !Ref RouteTableBPublic
- !If [Have3AZs, !Ref RouteTableCPublic, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPublic, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-RouteTablesPublic"
RouteTablesPrivate:
Description: 'Route tables private.'
Value:
Fn::Join:
- ','
- - !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-RouteTablesPrivate"
SubnetAPublic:
Description: 'Subnet A public.'
Value: !Ref SubnetAPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetAPublic"
RouteTableAPublic:
Description: 'Route table A public.'
Value: !Ref RouteTableAPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableAPublic"
SubnetAPrivate:
Description: 'Subnet A private.'
Value: !Ref SubnetAPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetAPrivate"
RouteTableAPrivate:
Description: 'Route table A private.'
Value: !Ref RouteTableAPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableAPrivate"
SubnetBPublic:
Description: 'Subnet B public.'
Value: !Ref SubnetBPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetBPublic"
RouteTableBPublic:
Description: 'Route table B public.'
Value: !Ref RouteTableBPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableBPublic"
SubnetBPrivate:
Description: 'Subnet B private.'
Value: !Ref SubnetBPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetBPrivate"
RouteTableBPrivate:
Description: 'Route table B private.'
Value: !Ref RouteTableBPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableBPrivate"
SubnetCPublic:
Condition: Have3AZs
Description: 'Subnet C public.'
Value: !Ref SubnetCPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetCPublic"
RouteTableCPublic:
Condition: Have3AZs
Description: 'Route table C public.'
Value: !Ref RouteTableCPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableCPublic"
SubnetCPrivate:
Condition: Have3AZs
Description: 'Subnet C private.'
Value: !Ref SubnetCPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetCPrivate"
RouteTableCPrivate:
Condition: Have3AZs
Description: 'Route table C private.'
Value: !Ref RouteTableCPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableCPrivate"
SubnetDPublic:
Condition: Have4AZs
Description: 'Subnet D public.'
Value: !Ref SubnetDPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetDPublic"
RouteTableDPublic:
Condition: Have4AZs
Description: 'Route table D public.'
Value: !Ref RouteTableDPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableDPublic"
SubnetDPrivate:
Condition: Have4AZs
Description: 'Subnet D private.'
Value: !Ref SubnetDPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetDPrivate"
RouteTableDPrivate:
Condition: Have4AZs
Description: 'Route table D private.'
Value: !Ref RouteTableDPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableDPrivate"
EndpointS3:
Description: 'The VPC endpoint to S3.'
Value: !Ref EndpointS3
Export:
Name: !Sub "${AWS::StackName}-EndpointS3"
EndpointDynamoDB:
Description: 'The VPC endpoint to DynamoDB.'
Value: !Ref EndpointDynamoDB
Export:
Name: !Sub "${AWS::StackName}-EndpointDynamoDB"
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC: Public, Private and Data subnets'
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'VPC Parameters'
Parameters:
- ClassB
- DualStack
- NumberAZs
Parameters:
ClassB:
Description: 'Class B of VPC (10.XXX.0.0/16)'
Type: Number
Default: 0
ConstraintDescription: 'Must be in the range [0-255]'
MinValue: 0
MaxValue: 255
DualStack:
Description: 'Request IPv6 CIDR block'
Type: String
Default: 'false'
AllowedValues: ['true', 'false']
NumberAZs:
Description: 'Number of Availability Zones'
Type: Number
Default: 2
AllowedValues: [2, 3, 4]
Conditions:
Have4AZs: !Equals [!Ref NumberAZs, 4]
Have3AZs: !Or [!Condition Have4AZs, !Equals [!Ref NumberAZs, 3]]
DualStacked: !Equals [!Ref DualStack, 'true']
DualStacked3AZs: !And [!Condition DualStacked, !Condition Have3AZs]
DualStacked4AZs: !And [!Condition DualStacked, !Condition Have4AZs]
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Sub "10.${ClassB}.0.0/16"
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
VPCv6CIDR:
Condition: DualStacked
Type: AWS::EC2::VPCCidrBlock
Properties:
AmazonProvidedIpv6CidrBlock: !Ref DualStack
VpcId: !Ref VPC
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub "10.${ClassB}.0.0/16"
EgressOnlyInternetGateway:
Condition: DualStacked
Type: AWS::EC2::EgressOnlyInternetGateway
Properties:
VpcId: !Ref VPC
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# Setup Subnet for each tier
# - Cut off a /20 IPv4 CIDR block for each Subnet from the /16 VPC CIDR
# - If DualStack, cut off a /64 IPv6 CIDR block for each Subnet from /56 VPCv6CIDR
# - Each tier can be referenced by a single /18 IPv4 CIDR block
# - If DualStack, each tier can be referenced by a single /66 IPv6 CIDR block
SubnetAPublic:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [0, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [0, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A public
- Key: Reach
Value: public
SubnetAPrivate:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [0, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [4, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [4, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A private
- Key: Reach
Value: private
SubnetAData:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [0, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [8, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [8, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A data
- Key: Reach
Value: data
SubnetBPublic:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [1, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B public
- Key: Reach
Value: public
SubnetBPrivate:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [1, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [5, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [5, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B private
- Key: Reach
Value: private
SubnetBData:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [1, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [9, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [9, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B data
- Key: Reach
Value: data
SubnetCPublic:
Condition: Have3AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [2, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [2, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [2, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C public
- Key: Reach
Value: public
SubnetCPrivate:
Condition: Have3AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [2, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [6, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [6, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C private
- Key: Reach
Value: private
SubnetCData:
Condition: Have3AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [2, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [10, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [10, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C data
- Key: Reach
Value: data
SubnetDPublic:
Condition: Have4AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [3, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [3, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [3, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D public
- Key: Reach
Value: public
SubnetDPrivate:
Condition: Have4AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [3, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [7, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [7, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D private
- Key: Reach
Value: private
SubnetDData:
Condition: Have4AZs
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: !If [DualStacked, !Ref DualStack, !Ref 'AWS::NoValue']
AvailabilityZone: !Select [3, {'Fn::GetAZs': !Ref 'AWS::Region'}]
CidrBlock: !Select [11, !Cidr [!GetAtt VPC.CidrBlock, 12, 12]]
Ipv6CidrBlock: !If [DualStacked, !Select [11, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 12, 64]], !Ref 'AWS::NoValue']
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D data
- Key: Reach
Value: data
# Setup a RouteTable for each Subnet
RouteTableAPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A Public
RouteTableAPrivate:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A Private
RouteTableAData:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: A Data
RouteTableBPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B Public
RouteTableBPrivate:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B Private
RouteTableBData:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: B Data
RouteTableCPublic:
Condition: Have3AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C Public
RouteTableCPrivate:
Condition: Have3AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C Private
RouteTableCData:
Condition: Have3AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: C Data
RouteTableDPublic:
Condition: Have4AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D Public
RouteTableDPrivate:
Condition: Have4AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D Private
RouteTableDData:
Condition: Have4AZs
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: D Data
# Associate each Subnet with the correct RouteTable
RouteTableAssociationAPublic:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetAPublic
RouteTableId: !Ref RouteTableAPublic
RouteTableAssociationAPrivate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetAPrivate
RouteTableId: !Ref RouteTableAPrivate
RouteTableAssociationAData:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetAData
RouteTableId: !Ref RouteTableAData
RouteTableAssociationBPublic:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetBPublic
RouteTableId: !Ref RouteTableBPublic
RouteTableAssociationBPrivate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetBPrivate
RouteTableId: !Ref RouteTableBPrivate
RouteTableAssociationBData:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetBData
RouteTableId: !Ref RouteTableBData
RouteTableAssociationCPublic:
Condition: Have3AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetCPublic
RouteTableId: !Ref RouteTableCPublic
RouteTableAssociationCPrivate:
Condition: Have3AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetCPrivate
RouteTableId: !Ref RouteTableCPrivate
RouteTableAssociationCData:
Condition: Have3AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetCData
RouteTableId: !Ref RouteTableCData
RouteTableAssociationDPublic:
Condition: Have4AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetDPublic
RouteTableId: !Ref RouteTableDPublic
RouteTableAssociationDPrivate:
Condition: Have4AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetDPrivate
RouteTableId: !Ref RouteTableDPrivate
RouteTableAssociationDData:
Condition: Have4AZs
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SubnetDData
RouteTableId: !Ref RouteTableDData
# Setup default routes for each RouteTable
# - InternetGateway for Public Subnets
# - EgressOnlyInternetGateway for Private & Data Subnets if DualStack
RouteTablePublicAInternetRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableAPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicAInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableAPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateAInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableAPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTableDataAInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableAData
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicBInternetRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableBPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicBInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableBPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateBInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableBPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTableDataBInternetRouteIpv6:
Condition: DualStacked
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableBData
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicCInternetRoute:
Condition: Have3AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableCPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicCInternetRouteIpv6:
Condition: DualStacked3AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableCPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateCInternetRouteIpv6:
Condition: DualStacked3AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableCPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTableDataCInternetRouteIpv6:
Condition: DualStacked3AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableCData
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTablePublicDInternetRoute:
Condition: Have4AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableDPublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
RouteTablePublicDInternetRouteIpv6:
Condition: DualStacked4AZs
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTableDPublic
DestinationIpv6CidrBlock: '::/0'
GatewayId: !Ref InternetGateway
RouteTablePrivateDInternetRouteIpv6:
Condition: DualStacked4AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableDPrivate
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
RouteTableDataDInternetRouteIpv6:
Condition: DualStacked4AZs
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTableDData
DestinationIpv6CidrBlock: '::/0'
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
# Setup our VPC Gateway Endpoints
EndpointS3:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
- !Ref RouteTableAData
- !Ref RouteTableBData
- !If [Have3AZs, !Ref RouteTableCData, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDData, !Ref 'AWS::NoValue']
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !Ref VPC
EndpointDynamoDB:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
- !Ref RouteTableAData
- !Ref RouteTableBData
- !If [Have3AZs, !Ref RouteTableCData, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDData, !Ref 'AWS::NoValue']
ServiceName: !Sub "com.amazonaws.${AWS::Region}.dynamodb"
VpcId: !Ref VPC
# Setup NetworkAcl for each tier
NetworkAclPublic:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Public
NetworkAclPrivate:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Private
NetworkAclData:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Data
# Associate each Subnet with the respective tier NetworkAcl
SubnetNetworkAclAssociationAPublic:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetAPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationAPrivate:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetAPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationAData:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetAData
NetworkAclId: !Ref NetworkAclData
SubnetNetworkAclAssociationBPublic:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetBPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationBPrivate:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetBPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationBData:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetBData
NetworkAclId: !Ref NetworkAclData
SubnetNetworkAclAssociationCPublic:
Condition: Have3AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetCPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationCPrivate:
Condition: Have3AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetCPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationCData:
Condition: Have3AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetCData
NetworkAclId: !Ref NetworkAclData
SubnetNetworkAclAssociationDPublic:
Condition: Have4AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetDPublic
NetworkAclId: !Ref NetworkAclPublic
SubnetNetworkAclAssociationDPrivate:
Condition: Have4AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetDPrivate
NetworkAclId: !Ref NetworkAclPrivate
SubnetNetworkAclAssociationDData:
Condition: Have4AZs
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetDData
NetworkAclId: !Ref NetworkAclData
# Setup NetworkAclEntry for each tier
# - Allow all traffic inbound & outbound for Public & Private tier
# - Deny all traffic to/from Public tier to Data tier
# - Allow all other traffic inbound & outbound for Data Tier
NetworkAclEntryInPublicAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: '0.0.0.0/0'
NetworkAclEntryOutPublicAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: '0.0.0.0/0'
NetworkAclEntryInPublicAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: false
Ipv6CidrBlock: '::/0'
NetworkAclEntryOutPublicAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPublic
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: true
Ipv6CidrBlock: '::/0'
NetworkAclEntryInPrivateAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: '0.0.0.0/0'
NetworkAclEntryOutPrivateAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 100
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: '0.0.0.0/0'
NetworkAclEntryInPrivateAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: false
Ipv6CidrBlock: '::/0'
NetworkAclEntryOutPrivateAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclPrivate
RuleNumber: 101
Protocol: -1
RuleAction: allow
Egress: true
Ipv6CidrBlock: '::/0'
NetworkAclEntryInDataDenyPublic:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 100
Protocol: -1
RuleAction: deny
Egress: false
CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 4, 14]]
NetworkAclEntryOutDataDenyPublic:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 100
Protocol: -1
RuleAction: deny
Egress: true
CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 4, 14]]
NetworkAclEntryInDataAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 200
Protocol: -1
RuleAction: allow
Egress: false
CidrBlock: '0.0.0.0/0'
NetworkAclEntryOutDataAllowAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 200
Protocol: -1
RuleAction: allow
Egress: true
CidrBlock: '0.0.0.0/0'
NetworkAclEntryInDataDenyPublicIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 101
Protocol: -1
RuleAction: deny
Egress: false
Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 4, 66]]
NetworkAclEntryOutDataDenyPublicIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 101
Protocol: -1
RuleAction: deny
Egress: true
Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 4, 66]]
NetworkAclEntryInDataAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 201
Protocol: -1
RuleAction: allow
Egress: false
Ipv6CidrBlock: '::/0'
NetworkAclEntryOutDataAllowAllIpv6:
Condition: DualStacked
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref NetworkAclData
RuleNumber: 201
Protocol: -1
RuleAction: allow
Egress: true
Ipv6CidrBlock: '::/0'
Outputs:
StackName:
Description: 'Stack name'
Value: !Ref 'AWS::StackName'
AZs:
Description: 'AZs'
Value: !Ref NumberAZs
Export:
Name: !Sub "${AWS::StackName}-AZs"
AZA:
Description: 'AZ of A'
Value: !GetAtt SubnetAPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZA"
AZB:
Description: 'AZ of B'
Value: !GetAtt SubnetBPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZB"
AZC:
Condition: Have3AZs
Description: 'AZ of C'
Value: !GetAtt SubnetCPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZC"
AZD:
Condition: Have4AZs
Description: 'AZ of D'
Value: !GetAtt SubnetDPublic.AvailabilityZone
Export:
Name: !Sub "${AWS::StackName}-AZD"
ClassB:
Description: 'Class B.'
Value: !Ref ClassB
Export:
Name: !Sub "${AWS::StackName}-ClassB"
VPC:
Description: 'VPC.'
Value: !Ref VPC
Export:
Name: !Sub "${AWS::StackName}-VPC"
SubnetsPublic:
Description: 'Subnets public.'
Value:
Fn::Join:
- ','
- - !Ref SubnetAPublic
- !Ref SubnetBPublic
- !If [Have3AZs, !Ref SubnetCPublic, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref SubnetDPublic, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-SubnetsPublic"
SubnetsPrivate:
Description: 'Subnets private.'
Value:
Fn::Join:
- ','
- - !Ref SubnetAPrivate
- !Ref SubnetBPrivate
- !If [Have3AZs, !Ref SubnetCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref SubnetDPrivate, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-SubnetsPrivate"
SubnetsData:
Description: 'Subnets data.'
Value:
Fn::Join:
- ','
- - !Ref SubnetAData
- !Ref SubnetBData
- !If [Have3AZs, !Ref SubnetCData, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref SubnetDData, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-SubnetsData"
RouteTablesPublic:
Description: 'Route tables public.'
Value:
Fn::Join:
- ','
- - !Ref RouteTableAPublic
- !Ref RouteTableBPublic
- !If [Have3AZs, !Ref RouteTableCPublic, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPublic, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-RouteTablesPublic"
RouteTablesPrivate:
Description: 'Route tables private.'
Value:
Fn::Join:
- ','
- - !Ref RouteTableAPrivate
- !Ref RouteTableBPrivate
- !If [Have3AZs, !Ref RouteTableCPrivate, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDPrivate, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-RouteTablesPrivate"
RouteTablesData:
Description: 'Route tables data.'
Value:
Fn::Join:
- ','
- - !Ref RouteTableAData
- !Ref RouteTableBData
- !If [Have3AZs, !Ref RouteTableCData, !Ref 'AWS::NoValue']
- !If [Have4AZs, !Ref RouteTableDData, !Ref 'AWS::NoValue']
Export:
Name: !Sub "${AWS::StackName}-RouteTablesData"
SubnetAPublic:
Description: 'Subnet A public.'
Value: !Ref SubnetAPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetAPublic"
RouteTableAPublic:
Description: 'Route table A public.'
Value: !Ref RouteTableAPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableAPublic"
SubnetAPrivate:
Description: 'Subnet A private.'
Value: !Ref SubnetAPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetAPrivate"
RouteTableAPrivate:
Description: 'Route table A private.'
Value: !Ref RouteTableAPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableAPrivate"
SubnetAData:
Description: 'Subnet A data.'
Value: !Ref SubnetAData
Export:
Name: !Sub "${AWS::StackName}-SubnetAData"
RouteTableAData:
Description: 'Route table A data.'
Value: !Ref RouteTableAData
Export:
Name: !Sub "${AWS::StackName}-RouteTableAData"
SubnetBPublic:
Description: 'Subnet B public.'
Value: !Ref SubnetBPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetBPublic"
RouteTableBPublic:
Description: 'Route table B public.'
Value: !Ref RouteTableBPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableBPublic"
SubnetBPrivate:
Description: 'Subnet B private.'
Value: !Ref SubnetBPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetBPrivate"
RouteTableBPrivate:
Description: 'Route table B private.'
Value: !Ref RouteTableBPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableBPrivate"
SubnetBData:
Description: 'Subnet B data.'
Value: !Ref SubnetBData
Export:
Name: !Sub "${AWS::StackName}-SubnetBData"
RouteTableBData:
Description: 'Route table B data.'
Value: !Ref RouteTableBData
Export:
Name: !Sub "${AWS::StackName}-RouteTableBData"
SubnetCPublic:
Condition: Have3AZs
Description: 'Subnet C public.'
Value: !Ref SubnetCPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetCPublic"
RouteTableCPublic:
Condition: Have3AZs
Description: 'Route table C public.'
Value: !Ref RouteTableCPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableCPublic"
SubnetCPrivate:
Condition: Have3AZs
Description: 'Subnet C private.'
Value: !Ref SubnetCPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetCPrivate"
RouteTableCPrivate:
Condition: Have3AZs
Description: 'Route table C private.'
Value: !Ref RouteTableCPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableCPrivate"
SubnetCData:
Condition: Have3AZs
Description: 'Subnet C data.'
Value: !Ref SubnetCData
Export:
Name: !Sub "${AWS::StackName}-SubnetCData"
RouteTableCData:
Condition: Have3AZs
Description: 'Route table C data.'
Value: !Ref RouteTableCData
Export:
Name: !Sub "${AWS::StackName}-RouteTableCData"
SubnetDPublic:
Condition: Have4AZs
Description: 'Subnet D public.'
Value: !Ref SubnetDPublic
Export:
Name: !Sub "${AWS::StackName}-SubnetDPublic"
RouteTableDPublic:
Condition: Have4AZs
Description: 'Route table D public.'
Value: !Ref RouteTableDPublic
Export:
Name: !Sub "${AWS::StackName}-RouteTableDPublic"
SubnetDPrivate:
Condition: Have4AZs
Description: 'Subnet D private.'
Value: !Ref SubnetDPrivate
Export:
Name: !Sub "${AWS::StackName}-SubnetDPrivate"
RouteTableDPrivate:
Condition: Have4AZs
Description: 'Route table D private.'
Value: !Ref RouteTableDPrivate
Export:
Name: !Sub "${AWS::StackName}-RouteTableDPrivate"
SubnetDData:
Condition: Have4AZs
Description: 'Subnet D data.'
Value: !Ref SubnetDData
Export:
Name: !Sub "${AWS::StackName}-SubnetDData"
RouteTableDData:
Condition: Have4AZs
Description: 'Route table D data.'
Value: !Ref RouteTableDData
Export:
Name: !Sub "${AWS::StackName}-RouteTableDData"
EndpointS3:
Description: 'The VPC endpoint to S3.'
Value: !Ref EndpointS3
Export:
Name: !Sub "${AWS::StackName}-EndpointS3"
EndpointDynamoDB:
Description: 'The VPC endpoint to DynamoDB.'
Value: !Ref EndpointDynamoDB
Export:
Name: !Sub "${AWS::StackName}-EndpointDynamoDB"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment