How to do it...

Just a heads up: this will be one of the larger templates that we'll create in this book. Let's get started:

  1. Go ahead and create a new CloudFormation template for our VPC. Use the filename 07-01-VPC.yaml.
The entire template can be downloaded from this book's GitHub repository, which can be found at https://github.com/PacktPublishing/AWS-SysOps-Cookbook-Second-Edition.
  1. Start with the first two parameters, which correspond to the AZ we discussed previously. We don't provide any default values for these parameters in order to maintain region portability:
Parameters:
AvailabilityZone1:
Description: Availability zone 1 name (e.g. us-east-1a)
Type: AWS::EC2::AvailabilityZone::Name
AvailabilityZone2:
Description: Availability zone 2 name (e.g. us-east-1b)
Type: AWS::EC2::AvailabilityZone::Name

  1. Then, add the remaining parameters to define the IP address ranges for the following:
    • The entire VPC
    • The public subnets (A and B)
    • The private subnets (A and B):
  VPCCIDR: 
Description: CIDR block for VPC
Type: String
Default: "172.31.0.0/21" # 2048 IP addresses
PublicSubnetACIDR:
Description: CIDR block for public subnet A
Type: String
Default: "172.31.0.0/23" # 512 IP address
PublicSubnetBCIDR:
Description: CIDR block for public subnet B
Type: String
Default: "172.31.2.0/23" # 512 IP address
PrivateSubnetACIDR:
Description: CIDR block for private subnet A
Type: String
Default: "172.31.4.0/23" # 512 IP address
PrivateSubnetBCIDR:
Description: CIDR block for private subnet B
Type: String
Default: "172.31.6.0/23" # 512 IP address
AWS reserves a small number of IP addresses in your IP space for AWS-specific services. The VPC DNS server is one such example of this. It's usually located at the second (*.2) IP address in the block allocated to your VPC.
  1. Now, we can start to define Resources. We'll start by defining the VPC itself:
Resources: 
# VPC & subnets
ExampleVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- { Key: Name, Value: Example VPC }

  1. Then, we will define the public subnets. Public subnets are defined as subnets with a route to the Internet Gateway (IGW):
PublicSubnetA: 
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone1
CidrBlock: !Ref PublicSubnetACIDR
MapPublicIpOnLaunch: true
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Public Subnet A }
PublicSubnetB:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone2
CidrBlock: !Ref PublicSubnetBCIDR
MapPublicIpOnLaunch: true
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Public Subnet B }
  1. Next, we will add the private subnets:
PrivateSubnetA: 
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone1
CidrBlock: !Ref PrivateSubnetACIDR
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Private Subnet A }
PrivateSubnetB:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone2
CidrBlock: !Ref PrivateSubnetBCIDR
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Private Subnet B }
  1. Then, we will create the IGW for the VPC:
ExampleIGW: 
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- { Key: Name, Value: Example Internet Gateway }
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
DependsOn: ExampleIGW
Properties:
VpcId: !Ref ExampleVPC
InternetGatewayId: !Ref ExampleIGW
  1. We need to create a couple of route tables. The first one we'll focus on is the public route table. We'll assign this route table to the two public subnets we've created. This route table will have just one route in it, which will direct all internet-bound traffic to the internet gateway we created in the previous step:
PublicRouteTable: 
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Public Route Table }
PublicInternetRoute:
Type: AWS::EC2::Route
DependsOn: IGWAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
GatewayId: !Ref ExampleIGW
DestinationCidrBlock: "0.0.0.0/0"
RouteAssociationPublicA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetA
RouteAssociationPublicB:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetB
  1. We'll create the private route table in a similar fashion. Since the private subnet is isolated from the internet, we won't add a route to the internet gateway. Note that if you were to follow the NAT gateway recipe in this book, it will require a routing table as an input parameter—this is the routing table you want to add NAT routes to:
PrivateRouteTable: 
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Private Route Table }
PrivateSubnetAssociationA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnetA
PrivateSubnetAssociationB:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnetB
  1. We can now focus on the security aspects of our network. Let's focus on public subnets. These are the subnets you'll add your load balancers to; you'll also add things such as bastion boxes and NAT gateways. For this, we need to add a Network Access Control List (NACL) with several entries. An NACL is the equivalent of a stateless firewall that is applied to the subnet and allows the following:
    • Allows outbound traffic to all ports. Outbound access is unrestricted from hosts in our public subnets.
    • Allows inbound traffic to ephemeral ports (above 1024). This ensures that packets that are returned to us from our outbound connections are not dropped.
    • Allows inbound access to low port numbers for SSH, HTTP, and HTTPS (22, 80, and 443):
  PublicNACL: 
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Example Public NACL }

  1. Allow outbound to everywhere:
NACLRulePublicEgressAllowAll: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Egress: true
Protocol: 6
PortRange: { From: 1, To: 65535 }
RuleAction: allow
RuleNumber: 100
NetworkAclId: !Ref PublicNACL

  1. Allow outbound to the VPC on all protocols:
NACLRulePublicEgressAllowAllToVPC: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: !Ref VPCCIDR
Egress: true
Protocol: -1
RuleAction: allow
RuleNumber: 200
NetworkAclId: !Ref PublicNACL
  1. Allow inbound from everywhere to ephemeral ports:
NACLRulePublicIngressAllowEphemeral: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Protocol: 6
PortRange: { From: 1024, To: 65535 }
RuleAction: allow
RuleNumber: 100
NetworkAclId: !Ref PublicNACL
  1. Allow inbound from everywhere on port 22 for SSH:
NACLRulePublicIngressAllowSSH: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Protocol: 6
PortRange: { From: 22, To: 22 }
RuleAction: allow
RuleNumber: 200
NetworkAclId: !Ref PublicNACL
  1. Allow inbound from everywhere on port 443 for HTTPS:
NACLRulePublicIngressAllowHTTPS: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Protocol: 6
PortRange: { From: 443, To: 443 }
RuleAction: allow
RuleNumber: 300
NetworkAclId: !Ref PublicNACL

  1. Allow inbound from everywhere on port 80 for HTTP:
NACLRulePublicIngressAllowHTTP: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Protocol: 6
PortRange: { From: 80, To: 80 }
RuleAction: allow
RuleNumber: 400
NetworkAclId: !Ref PublicNACL
  1. Allow inbound from VPC on all protocols:
NACLRulePublicIngressAllowFromVPC: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: !Ref VPCCIDR
Protocol: -1
RuleAction: allow
RuleNumber: 500
NetworkAclId: !Ref PublicNACL
  1. Associate the NACLs with the subnets:
NACLAssociationPublicSubnetA: 
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
NetworkAclId: !Ref PublicNACL
SubnetId: !Ref PublicSubnetA
NACLAssociationPublicSubnetB:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
NetworkAclId: !Ref PublicNACL
SubnetId: !Ref PublicSubnetB
  1. We need to do the same for our private subnets. These subnets are somewhat easier to deal with. They should only be allowed to talk to hosts within our VPC, so we just need to add some NACLs that allow inbound and outbound traffic in our VPCs IP range:
  PrivateNACL: 
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref ExampleVPC
Tags:
- { Key: Name, Value: Example Private NACL }

  1. Allow all protocols from the VPC range:
NACLRulePrivateIngressAllowVPC: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: !Ref VPCCIDR
Protocol: -1
RuleAction: allow
RuleNumber: 100
NetworkAclId: !Ref PrivateNACL
  1. Allow TCP responses from everywhere:
NACLRulePrivateIngressAllowEphemeral: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Protocol: 6
PortRange: { From: 1024, To: 65535 }
RuleAction: allow
RuleNumber: 200
NetworkAclId: !Ref PrivateNACL
  1. The following code allows outbound traffic to everywhere (all protocols):
NACLRulePrivateEgressAllowVPC: 
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: "0.0.0.0/0"
Egress: true
Protocol: -1
RuleAction: allow
RuleNumber: 100
NetworkAclId: !Ref PrivateNACL
  1. Associate the NACLs with the subnets:
NACLAssociationPrivateSubnetA: 
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
NetworkAclId: !Ref PrivateNACL
SubnetId: !Ref PrivateSubnetA
NACLAssociationPrivateSubnetB:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
NetworkAclId: !Ref PrivateNACL
SubnetId: !Ref PrivateSubnetB

  1. Finally, we'll add some Outputs to our template. These outputs are usually candidates that we can feed into other templates or components of automation:
     
Outputs:
ExampleVPC:
Value: !Ref ExampleVPC
PublicSubnetA:
Value: !Ref PublicSubnetA
PublicSubnetB:
Value: !Ref PublicSubnetB
PrivateRouteTable:
Value: !Ref PrivateRouteTable
PublicRouteTable:
Value: !Ref PublicRouteTable
PrivateSubnetA:
Value: !Ref PrivateSubnetA
PrivateSubnetB:
Value: !Ref PrivateSubnetB
  1. You can go ahead and create your VPC in the web console or via the CLI using the following command:
      aws cloudformation create-stack 
--stack-name secure-vpc
--template-body file://07-01-VPC.yaml
--parameters
ParameterKey=AvailabilityZone1,ParameterValue=<az-1>
ParameterKey=AvailabilityZone2,ParameterValue=<az-2>

You can fine-tune this template for your own use, or if you don't need it after completing the recipe, delete it to avoid any future charges associated with the VPC.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset