(to the tune of the Ewoks Victory Song. Now it can be stuck in your head, and not just mine)
Picking up from last time, I needed to start creating things inside my Virtual Private Cloud, or VPC. The first things to create are subnets – public subnets, in particular. Without a public subnet, nothing that I run in the VPC can be accessed from the internet – nor can they access the internet in turn.
(Caveat: I’m not a networking engineer. This network design represents a standard industry practice, but may not be necessary or suitable for your needs)
What’s a Subnet?
It’s a miniature virtual network inside of the VPC. It’s analogous to an ethernet network. The servers within a subnet can all talk to each other – but can’t talk outside the subnet without instructions
What else do we need?
Besides the subnet, we will need to define:
- an internet gateway, to allow servers in the subnet
- a network routing table, with routes, to tell servers to use the gateway.
Also, we won’t be making one subnet. We’ll make two. This is a minor tease for later, but we need to make two because when we create a load balancer, we will need two public subnets for it. Note that everything we’re doing in this post is free (this will not be true for later posts!)
Break It Down
In this section, we once again ask for the stack environment. We’re going to be doing this every time, as it lets us distinguish between a production stack and testing stacks. We also get the user to specify two Availability Zones – the subnets will get created in those.
This introduces the use of intrinsic functions. These are functions that get called as part of processing the CloudFormation stack. When using YAML, these can be called using the verbose mode (e.g.
Fn::ImportValue), or with a shortcut (e.g.
!Sub). However, you can’t do the shortcut twice.
ImportValue function is the most important here. It makes a connection between this stack and the Globals stack made last time – it lets us use a reference to the VPC defined there, without having to look up the ID and either hardcode it or pass it as a parameter. By using the
Sub function, I make sure I get the VPC for this test environment.
Public Subnet 1 and Public Subnet 2
The next two resources list the two public subnets –
PublicSubnetAZ2. (AZ stands for ‘Availability Zone’).
One important option here is the
CidrBlock. This specifies the range of IP addresses that can be addressed within the subnet. I don’t want them overlapping (I don’t even know if you can!), so I use a simple technique to allocate the range.
Another thing to note is that I don’t actually want to assign public IPs to instances automatically. One reason is that the IPs get changed every time you create a server; that’s okay for temporary servers, but for long-term ones I want something more permanent. Amazon provides this in the form of Elastic IP addresses (yes, that’s another teaser for a later post)
Right now, those subnets aren’t actually public. I need to put in a network route table, so that servers in these subnets (and yes, there aren’t any yet) can send traffic to the internet.
PublicRouteTable holds the routes. The
PublicSubnetRoute describes the route – sending all traffic out via the previously created
VPCGateway. Note that there is a dependency on the
VPCGatewayAttachment – the route can’t be associated with the gateway until it’s attached to a VPC, so we have to wait for that to get setup.
Finally, the route table gets associated with the newly created subnets.
We don’t use the subnets here – that happens later. So we export the subnets out for wider consumption, just like the VPC was exported last time.
From here, we’ll go on to create a ‘bastion host’. This is a server that we can SSH into, so that we can then SSH into other servers. It will be the only server that we expose directly to the world (and, even then, only via SSH).
This bastion host will also do double-duty as a NAT Gateway, so that servers in private subnets can communicate with the outside internet.
All that will be coming up next time.