Last active
November 3, 2020 06:19
-
-
Save atheiman/70679d300b8d94ee6414a6629b88a9cc to your computer and use it in GitHub Desktop.
VPC with generated CIDR block determined by AWS account ID + Region. 4 subnets (Public/Private, 2 AZs).
This file contains hidden or 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
Description: > | |
Builds a basic /24 2x2 VPC (Public/Private, 2 AZs). The VPC CIDR block is determined by a combination | |
of the account ID and Region, giving a _very strong_ probability of a unique range within an | |
Organization. | |
Parameters: | |
VpcNameTag: | |
Type: String | |
Default: 2x2 | |
VpcCidrSuffix: | |
Type: String | |
Default: '.0/24' | |
Description: > | |
CIDR block to assign to the VPC (first three octets will be prepended). | |
AvailabilityZone1NameSuffix: | |
Type: String | |
Default: 'a' | |
AllowedValues: [a, b, c, d, e, f] | |
Description: > | |
Will be appended to ${AWS::Region} to build an Availability Zone name. Example: 'a' in Region | |
'us-east-1' builds the Availability Zone name 'us-east-1a'. | |
AvailabilityZone2NameSuffix: | |
Type: String | |
Default: 'b' | |
AllowedValues: [a, b, c, d, e, f] | |
Description: > | |
Will be appended to ${AWS::Region} to build an Availability Zone name. Example: 'b' in Region | |
'us-east-1' builds the Availability Zone name 'us-east-1b'. | |
SubnetPrivate1CidrSuffix: | |
Type: String | |
Default: '.0/26' | |
Description: > | |
CIDR block to assign to the Private subnet in Availability Zone 1 (first three octets will be prepended). | |
SubnetPrivate2CidrSuffix: | |
Type: String | |
Default: '.64/26' | |
Description: > | |
CIDR block to assign to the Private subnet in Availability Zone 2 (first three octets will be prepended). | |
SubnetPublic1CidrSuffix: | |
Type: String | |
Default: '.128/27' | |
Description: > | |
CIDR block to assign to the Public subnet in Availability Zone 1 (first three octets will be prepended). | |
SubnetPublic2CidrSuffix: | |
Type: String | |
Default: '.160/27' | |
Description: > | |
CIDR block to assign to the Public subnet in Availability Zone 2 (first three octets will be prepended). | |
MultiAzNatGateway: | |
Type: String | |
Default: 'False' | |
AllowedValues: ['True', 'False'] | |
Description: > | |
If True, a NAT Gateway will be deployed in both subnets. This adds cost, but adds high availability to the | |
network. | |
TransitGatewayId: | |
Type: String | |
Default: '' | |
Description: > | |
Transit Gateway ID to attach to the VPC. If left blank, no Transit Gateway will be attached to the VPC. | |
TransitGatewayRouteCidr: | |
Type: String | |
Default: '10.0.0.0/8' | |
AllowedPattern: '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}' | |
Description: > | |
CIDR block to route traffic to the attached Transit Gateway. | |
Conditions: | |
TransitGatewayIdProvided: !Not [!Equals [!Ref TransitGatewayId, '']] | |
cMultiAzNatGateway: !Equals [!Ref MultiAzNatGateway, 'True'] | |
TransitGatewayIdProvidedAndMultiAzNatGateway: !And | |
- Condition: TransitGatewayIdProvided | |
- Condition: cMultiAzNatGateway | |
Resources: | |
####### | |
# VPC # | |
####### | |
Vpc: | |
Type: AWS::EC2::VPC | |
Properties: | |
CidrBlock: !Sub '${CidrUtil.CidrPrefix}${VpcCidrSuffix}' | |
EnableDnsHostnames: True | |
EnableDnsSupport: True | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-${CidrUtil.CidrPrefix}${VpcCidrSuffix}' | |
########### | |
# Subnets # | |
########### | |
SubnetPublic1: | |
Type: AWS::EC2::Subnet | |
Properties: | |
# TODO: Availability Zone name parameter rather than hardcoded a / b | |
AvailabilityZone: !Sub '${AWS::Region}${AvailabilityZone1NameSuffix}' | |
CidrBlock: !Sub '${CidrUtil.CidrPrefix}${SubnetPublic1CidrSuffix}' | |
MapPublicIpOnLaunch: True | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Public-${AvailabilityZone1NameSuffix}-${CidrUtil.CidrPrefix}${SubnetPublic1CidrSuffix}' | |
SubnetPublic2: | |
Type: AWS::EC2::Subnet | |
Properties: | |
AvailabilityZone: !Sub '${AWS::Region}${AvailabilityZone2NameSuffix}' | |
CidrBlock: !Sub '${CidrUtil.CidrPrefix}${SubnetPublic2CidrSuffix}' | |
MapPublicIpOnLaunch: True | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Public-${AvailabilityZone2NameSuffix}-${CidrUtil.CidrPrefix}${SubnetPublic2CidrSuffix}' | |
SubnetPrivate1: | |
Type: AWS::EC2::Subnet | |
Properties: | |
AvailabilityZone: !Sub '${AWS::Region}${AvailabilityZone1NameSuffix}' | |
CidrBlock: !Sub '${CidrUtil.CidrPrefix}${SubnetPrivate1CidrSuffix}' | |
MapPublicIpOnLaunch: False | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Private-${AvailabilityZone1NameSuffix}-${CidrUtil.CidrPrefix}${SubnetPrivate1CidrSuffix}' | |
SubnetPrivate2: | |
Type: AWS::EC2::Subnet | |
Properties: | |
AvailabilityZone: !Sub '${AWS::Region}${AvailabilityZone2NameSuffix}' | |
CidrBlock: !Sub '${CidrUtil.CidrPrefix}${SubnetPrivate2CidrSuffix}' | |
MapPublicIpOnLaunch: False | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Private-${AvailabilityZone2NameSuffix}-${CidrUtil.CidrPrefix}${SubnetPrivate2CidrSuffix}' | |
############### | |
# NAT Gateway # | |
############### | |
NatGateway1Eip: | |
Type: AWS::EC2::EIP | |
Properties: | |
Domain: vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-NatGateway-${AvailabilityZone1NameSuffix}' | |
NatGateway1: | |
Type: AWS::EC2::NatGateway | |
Properties: | |
AllocationId: !Sub '${NatGateway1Eip.AllocationId}' | |
SubnetId: !Ref SubnetPublic1 | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-${AvailabilityZone1NameSuffix}' | |
NatGateway2Eip: | |
Type: AWS::EC2::EIP | |
Condition: cMultiAzNatGateway | |
Properties: | |
Domain: vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-NatGateway-${AvailabilityZone2NameSuffix}' | |
NatGateway2: | |
Type: AWS::EC2::NatGateway | |
Condition: cMultiAzNatGateway | |
Properties: | |
AllocationId: !Sub '${NatGateway2Eip.AllocationId}' | |
SubnetId: !Ref SubnetPublic2 | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-${AvailabilityZone2NameSuffix}' | |
#################### | |
# Internet Gateway # | |
#################### | |
InternetGateway: | |
Type: AWS::EC2::InternetGateway | |
Properties: | |
Tags: | |
- Key: Name | |
Value: !Ref VpcNameTag | |
InternetGatewayAttachment: | |
Type: AWS::EC2::VPCGatewayAttachment | |
Properties: | |
InternetGatewayId: !Ref InternetGateway | |
VpcId: !Ref Vpc | |
###################### | |
# Public Route Table # | |
###################### | |
PublicRouteTable: | |
Type: AWS::EC2::RouteTable | |
Properties: | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Public' | |
PublicDefaultRoute: | |
Type: AWS::EC2::Route | |
DependsOn: InternetGatewayAttachment | |
Properties: | |
RouteTableId: !Ref PublicRouteTable | |
DestinationCidrBlock: '0.0.0.0/0' | |
GatewayId: !Ref InternetGateway | |
SubnetPublic1RouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !Ref PublicRouteTable | |
SubnetId: !Ref SubnetPublic1 | |
SubnetPublic2RouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !Ref PublicRouteTable | |
SubnetId: !Ref SubnetPublic2 | |
######################## | |
# Private Route Tables # | |
######################## | |
Private1RouteTable: | |
Type: AWS::EC2::RouteTable | |
Properties: | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Private-${AvailabilityZone1NameSuffix}' | |
Private1DefaultRoute: | |
Type: AWS::EC2::Route | |
Properties: | |
RouteTableId: !Ref Private1RouteTable | |
DestinationCidrBlock: '0.0.0.0/0' | |
NatGatewayId: !Ref NatGateway1 | |
SubnetPrivate1RouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !Ref Private1RouteTable | |
SubnetId: !Ref SubnetPrivate1 | |
Private2RouteTable: | |
Type: AWS::EC2::RouteTable | |
Condition: cMultiAzNatGateway | |
Properties: | |
VpcId: !Ref Vpc | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-Private-${AvailabilityZone2NameSuffix}' | |
Private2DefaultRoute: | |
Type: AWS::EC2::Route | |
Condition: cMultiAzNatGateway | |
Properties: | |
RouteTableId: !Ref Private2RouteTable | |
DestinationCidrBlock: '0.0.0.0/0' | |
NatGatewayId: !Ref NatGateway2 | |
SubnetPrivate2RouteTableAssociation: | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
RouteTableId: !If [cMultiAzNatGateway, !Ref Private2RouteTable, !Ref Private1RouteTable] | |
SubnetId: !Ref SubnetPrivate2 | |
################### | |
# Transit Gateway # | |
################### | |
TransitGatewayAttachment: | |
Type: AWS::EC2::TransitGatewayAttachment | |
Condition: TransitGatewayIdProvided | |
Properties: | |
VpcId: !Ref Vpc | |
TransitGatewayId: !Ref TransitGatewayId | |
SubnetIds: [!Ref SubnetPrivate1, !Ref SubnetPrivate2] | |
Tags: | |
- Key: Name | |
Value: !Sub '${VpcNameTag}-${TransitGatewayId}' | |
Private1TransitGatewayRoute: | |
Type: AWS::EC2::Route | |
DependsOn: TransitGatewayAttachment | |
Condition: TransitGatewayIdProvided | |
Properties: | |
RouteTableId: !Ref Private1RouteTable | |
DestinationCidrBlock: !Ref TransitGatewayRouteCidr | |
TransitGatewayId: !Ref TransitGatewayId | |
Private2TransitGatewayRoute: | |
Type: AWS::EC2::Route | |
DependsOn: TransitGatewayAttachment | |
Condition: TransitGatewayIdProvidedAndMultiAzNatGateway | |
Properties: | |
RouteTableId: !Ref Private2RouteTable | |
DestinationCidrBlock: !Ref TransitGatewayRouteCidr | |
TransitGatewayId: !Ref TransitGatewayId | |
####### | |
# RDS # | |
####### | |
DBSubnetGroup: | |
Type: AWS::RDS::DBSubnetGroup | |
Properties: | |
DBSubnetGroupName: !Sub 'vpc-${VpcNameTag}-private' | |
DBSubnetGroupDescription: !Sub '${VpcNameTag} VPC private subnets' | |
SubnetIds: [!Ref SubnetPrivate1, !Ref SubnetPrivate2] | |
################### | |
# Security Groups # | |
################### | |
SecurityGroupNoInbound: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupName: NoInbound | |
GroupDescription: No inbound traffic open | |
VpcId: !Ref Vpc | |
SecurityGroupEgress: | |
- IpProtocol: '-1' | |
CidrIp: 0.0.0.0/0 | |
SecurityGroupPrivateInbound: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupName: PrivateInbound | |
GroupDescription: Allows inbound traffic from private IP address ranges | |
VpcId: !Ref Vpc | |
SecurityGroupIngress: | |
- IpProtocol: '-1' | |
CidrIp: 10.0.0.0/8 | |
- IpProtocol: '-1' | |
CidrIp: 172.16.0.0/12 | |
- IpProtocol: '-1' | |
CidrIp: 192.168.0.0/16 | |
SecurityGroupEgress: | |
- IpProtocol: '-1' | |
CidrIp: 0.0.0.0/0 | |
############# | |
# CIDR Util # | |
############# | |
CidrUtil: | |
Type: Custom::CidrUtil | |
Properties: | |
ServiceToken: !Sub '${CidrUtilLambdaFunction.Arn}' | |
CidrUtilLambdaFunction: | |
Type: AWS::Lambda::Function | |
Properties: | |
Role: !Sub '${CidrUtilLambdaExecutionRole.Arn}' | |
Handler: index.handler | |
Timeout: 20 | |
Runtime: python3.7 | |
Code: | |
ZipFile: !Sub | | |
import boto3 | |
import cfnresponse | |
def handler(event, context): | |
try: | |
print(event) | |
ec2 = boto3.client('ec2', region_name='${AWS::Region}') | |
region_splay = [r['RegionName'] for r in ec2.describe_regions()['Regions']].index('${AWS::Region}') | |
print('Region, region_splay: ${AWS::Region}', region_splay) | |
account_id = '${AWS::AccountId}' | |
cidr_prefix = f'10.{account_id[:2]}.{int(account_id[-2:]) + region_splay}' | |
print('Account Id: ${AWS::AccountId}, CIDR Prefix:', cidr_prefix) | |
cfnresponse.send(event, context, cfnresponse.SUCCESS, {"CidrPrefix": cidr_prefix}) | |
except Exception as e: | |
print('Error:', repr(e)) | |
cfnresponse.send(event, context, cfnresponse.FAILED, {"Message": "Exception during processing"}) | |
CidrUtilLambdaExecutionRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: lambda.amazonaws.com | |
Action: ['sts:AssumeRole'] | |
ManagedPolicyArns: ['arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'] | |
Policies: | |
- PolicyName: root | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Action: 'ec2:DescribeRegions' | |
Resource: '*' | |
Outputs: | |
DBSubnetGroupName: | |
Value: !Ref DBSubnetGroup | |
Export: | |
Name: !Sub '${VpcNameTag}:DBSubnetGroupName' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment