AWS VPC (Part 2): Spinning-up EC2 instances and setting traffic rules

Configuring a VPC network, traffic rules, ping and more

After describing the foundations of VPC in the previous blog-post (“AWS VPC intro: Review the building-blocks and their principles”), it’s time to implement this knowledge.

VPC implementation

The purpose is to implement a simple VPC network with two subnets. Our planned network topology is outlined in the diagram below:

The planned VPC topology

Ultimately, we shall have one VPC with two subnets (one public and the other private) and two EC2 instances, each resides in a different subnet. The public instance is accessible to the internet, but the private not. An extra step will be connecting the private subnet to the internet via a NAT gateway.

A note about possible cost

Before we rush to allocate EC2 instances and VPC, let’s talk about the cost. Following this demo steps may cost you money if you’ve already utilised the AWS free-tier package. You will be billed for the time your VPC’s resources and EC2 instances were active. Read here for more information about VPC pricing.

In any case, you can follow the demo steps and delete the instances at the end.

Configure VPC and its components

Step #1: Creating VPC: I named my VPC as “medium-VPC” and allocated the IP address 10.0.0.0/16. Leave the “tenancy” value as default. Otherwise, it will incur a cost. The tenancy attribute is used to ensure the resources in the VPC will be allocated as dedicated resources.

Step #2: Configure two subnets under the VPC’s available range and give each of them a meaningful name to facilitate the subnet’s identification. It’s a best-practice habit to adhere. For the sake of the demo, I placed each subnet in a different availability zone to exemplify it can be done.

Since I defined the CIDR block to 18, there are 4 available subnets (the first two left bits are taken for the network address): 10.0.0.0/18, 10.0.64.0/18, 10.0.128.0/18 and 10.0.192.0/18. I assigned the first two IP addresses to our subnets.

As you can see in the screenshot, the available IP address range in each subnet is 16,379 (²¹⁴ -5=16,379. Explanation: 14 available bits minus the 5 IP addresses reserved for AWS).

Step #3: Create an internet gateway and attach it to our VPC.

Internet gateway after attaching the VPC

We can attach the default route table to the internet gateway by adding it as a target under the allowed routes.

At this point, there is only one main route table attached to the VPC. Since it’s the main route table and all the VPC’s subnets are not associated with any other route tables, these routing rules apply to all subnets. Therefore, practically, all the subnets have access to the internet gateway (!). The next step is to rectify this and create real segregation to private and public subnets.

Step #4: Setting a route table for each subnet: To create a private network, we need to define an additional route table and associate it with our designated private subnet. Let’s classify the subnet 10.0.0.0/18 as public and 10.0.64.0/18 as private. Therefore, after creating the new route table, associate the subnet 10.0.64.0/18 with it. This time, don’t add any routeing rule. The route table should have only one rule that allows communication from the VPC to the local subnet.

Route table: the routes and the associated subnets

In order to prevent any confusion and be more precise, we can deliberately associate the public subnet with the main route table, although it is already attached to this route table de facto. However, it’s not a mandatory step.

Congratulations! If you’ve made it so far, you’re a halfway through. Now, we want to see the communication at work, so our next step is to create resources and place them in our subnets.

Let’s move on!

Configuring the EC2 resources

This section describes the steps to create two EC2 instances, place one instance in the private subnet and the other in the public subnet. Afterwards, we shall test the communication to exemplify the security rules we’ve configured.

Open the EC2 dashboard, click on instances and select “Launch instances”. For the first resource at this demo, I chose windows server AMI. The exact image is Microsoft Windows Server 2016 Base with Containers ( ami-9e0d5ee6).

Reach to Step no. 3 (Configure Instance Details) and select our VPC and the public subnet. Since the server should have access to the internet, it should have a public IP address. Previously, we didn’t configure the flag to “Enable auto-assign public IPv4 address” in the nominated public subnet (10.0.0.0/18), and thus it should be configured as part of the EC2 instance definition (see below).

Let’s run through the subsequent steps: at the storage step select the default, it’s negligible for this demo. At step no. 5, it’s the best practice to add meaningful tags, so tag your instance to identify it later.

Configuration of the security groups (step no. 6) is an important step, but I’d rather address later, as part of modifying the traffic rules. Therefore, select the only existing security group, which is the default security group of the VPC.

Selecting the security group

This was the last configuration step. After reviewing the configuration, click on “Launch”. A pop-up screen will request to define a key-pair for the new server. This is AWS way to establish an authentication process with this instance. By using this key, you can obtain the administrator’s password. You can opt to create a new key-pair for the new server or use an existing one (in case you’ve already created one in the past). Please note: do not lose or delete this key or else you may have to undergo a certain procedure for regaining access to the EC2 instance.

Defining the key-pair for the EC2 instance

Setting-up the second EC2 instance: for the second EC2 instance, the one that will be placed in the private subnet, I chose a different Windows server AMI just for the variety (Microsoft Windows Server 2012 Base: ami-da0754a2).

The next difference from the first EC2 instance configuration is the network definition. If you recall, we’ve decided to place this instance in the private network, and thus its subnet should be the private one. Furthermore, the public IP assignment is disabled, the same as the subnet’s default. We should keep it as is since this instance will not have a public IP address.

As for the security groups, let’s choose the default, as we did with the first EC2 instance.

After AWS has finished setting-up and loading both instances, they should be in a “running state” mode. If you look at the Public IP address column, you should see that only one has such address. Not surprisingly, this is the instance that lies in the public subnet. Furthermore, as can be seen in the image below, each instance is located in different availability zones, based on its subnet’s definition.

Checking traffic and connectivity

Now the interesting part really starts, as we move on to testing the connectivity and troubleshooting.

Obtaining the public IP of our EC2 instance can simply be done through the EC2 instances screen. This public IP address is not permanent, and it is changed whenever the EC2 instance connects to the internet. To keep it constant, you can set up an Elastic IP instance (EIP) and attached it to the EC2 instance. It may incur an additional cost since an EIP that’s not associated with a running EC2 instance bears a cost, so if you’re holding such an unused EIP resource, you may consider to terminate it.

In this demo, our instance has an IP address that was allocated temporarily after connecting to the Internet. Pinging to this temporary public IP (54.213.251.82) yields the following response. Our ping requests do not receive responses. Why?

Troubleshooting is required. There are several locations in which the communication can be blocked: Network ACL (subnet level), security groups (instance level) internal firewall (EC2 instance level).

If you recall, the default NACL opens all the traffic (allow all), so let’s see the security group. At step #6 of the EC2 configuration, we chose the default security group of the VPC. Although the inbound rule allows all traffic, if you remember, AWS blocks ICMP by default. After adding an ICMP communication rule to the inbound rules security group (pay attention to pick the “All ICMP — IPv4” and not other ICMP rules, such as “Custom ICMP Rule”), the inbound rules list should have two rules:

You don’t have to add the ICMP rule to the outbound rules since the security group is stateless. Nonetheless, in my case, it didn’t work and the ping requests still didn’t get through. I checked the NACL, but there were no deny rules, and thus I decided to connect to the server using remote control. In order to obtain the administrator’s password, I selected the EC2 instance and opened the Actions → Connect menu item. Afterwards, to decrypt the administrator’s password, the private key of the server should be provided (I told you, don’t lose it).

Try to run the remote control, but probably you’ll fail at the beginning and won’t even reach to the user-password dialogue. Guess why? Right, there is no rule that allows RDP connections. To tackle this, you need to allow incoming RDP connection by adding a new rule to the security group. At the source field, you can allow all range (0.0.0.0/0) for simplicity, however, in real life, you may want to reduce the source and tighten the control by allowing only specific IPs to connect remotely. Opening your instances from RDP from everywhere is not a best practice.

Now there are more rules in our security group:

The security group after adding the RDP rule

The same security group is accessible either from the EC2 dashboard or from the VPC dashboard, but its display is a bit different (see the difference in the tabular format in the to images above).

At this point, you should be able to remote control the EC2 instance. Once you’re in, you can change the administrator password that AWS has generated for you. It’s not mandatory, but you can opt for this option if you want to manage your own password.

Since my ping requests kept on failing, I decided to check the server’s internal firewall. I opened the “Windows Firewall and Advanced Security” and couldn’t find a rule that allows ICMP requests. That may be the problem. To overcome this, I added a new rule to allow incoming ICMP requests (click here for a detailed guide) and finally received the desired result 🙏:

Getting ping replies from the public EC2 instance

Altering the Network ACL rules

Now, after opening a communication channel to our server, let’s implement what we’ve learnt about NACLs. Let the ping continue running (ping 54.213.251.82 -t) and start to manipulate the NACL a bit. I remind you that our NACL is still the default one.

Add a rule to deny ICMP communication, but don’t forget to rank it higher than the “Allow All” rule:

The default NACL after denying ICMP

Look what happens now — the ping is blocked:

Ping is blocked after altering the NACL

The next move will be to differ the NACL of the public and the private subnets. At this stage, both subnets are associated with the default NACL of the VPC, therefore let’s configure a new NACL and associate it with the private subnet. In the real world, this is the best practice, since we want to have the ability to define different rules for public and private subnets and protect their assets.

Now, the public subnet is associated with the default NACL, while the private subnet is associated with the new NACL.

Establish traffic between the public and the private resources

Log in to the public EC2 instance and try to ping to the EC2 in the private subnet (the private IP can be taken from the EC2 instances screen).

Unfortunately, the ping fails, no replies on the horizon. How’s that? Yep, the new NACL we configured has, by default, a “Deny All” rule (remember, it’s the opposite compared to the default NACL). Let’s rectify that and add an “Allow ICMP” rule to the inbound and outbound rules (the NACL rules are stateless). You are supposed to see similar rules as in the image below (notice that each NACL is associated with only one subnet):

The private subnet’s NACL

Voilà! The ping packets are flowing from the public EC2 to the EC2 in the private subnet and back successfully. Luckily, the destination’s firewall allowed incoming ICMP. This disparity between the two Windows servers is caused since each instance was created from a different AMI template.

Successful ping responses between the public and the private EC2 instances

This demonstration emphasizes that such scenarios can happen, so be aware of it.

What’s next? Testing more scenarios

After you’ve created the VPC as described, you have built a learning playground for future use. To deeply understand the VPC traffic control, I suggest you continue to modify the security groups.

Creating a new security group to be associated with one EC2 instance can be a good start. Afterwards, you can try to remote control the private EC2 instance from within the public EC2 instance, but remember to configure the RDP rules properly in the new security group.

In addition, you can configure a NAT gateway instance and open the communication to the private subnet. You can follow the steps described in the first part (“NAT gateway”).

An example of VPC with NAT gateway

Another nice experience would be to create a Bastion Server and connect it to a private subnet; you can read more about this option at this blog-post.

Use your imagination to alter this VPC as you wish; this is the best way to gain more knowledge and experience. It’s recommended to stop or terminate the EC2 instances and the VPC components (such as EIP) to avoid additional cost.

Wrapping-up

Wow, I hope you’ve managed to follow the guide’s steps. At first, my intent was to include also the steps to configure the NAT gateway and test it, but I think that would have been too exhausting for one blog post.

Hope you enjoyed reading this blog-post and that it shed more light about VPC and its configuration. As always, please don’t hesitate to give feedback, ask questions.

Keep on clouding ⛅.

— Lior

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s