This is the second part of the series covering the security levels in a VPC. In the first part, we discussed concepts and saw the defaults for the security groups and network ACLs.

VMware Training – Resources (Intense)

In the second part of the series, we will do some hands-on study to understand the defaults and what are the effects in case they are altered.

We will perform our testing using the topology below.

To sum up, I have a VPC created in EU CENTRAL region with two subnets. One subnet is public and has access to the Internet and the other one is private.

I have another host in the Internet (that is on AWS as well, but in another region) from which I will test connectivity (ping and ssh) to the EC2 instances from the public subnet.

From and EC2 instance from the public subnet, I will again test the connectivity (ping and ssh) to the EC2 instances from the private subnet.

So this is the VPC:

And these are the four EC2 instances, two in each subnet of the VPC (note the name and the IP addresses assigned to understand how the tests are performed):

Each EC2 instance has a different security group attached, but all of them right now allow only SSH from any IP (anywhere) and allow all the traffic to be transmitted from the instance:

This is the default network ACL. The default network ACL has the default rules on inbound direction and outbound direction and that is to allow all traffic:

Because SSH is allowed on inbound rules on all security groups and because all inbound traffic is allowed on the network ACL, I’m able to connect to all EC2 instances using SSH.

As a side note, to access the EC2 instances from the private subnet, first I connect to one of the EC2 instances from the public subnet and from there I connect to the EC2 instances from the private subnet.

Any ICMP traffic toward the EC2 instances from the public subnet coming from the test station will be denied.

So let’s start testing ping, using ICMP traffic. I will change the security group of PUB_2 EC2 instance to allow ICMP traffic on the inbound direction:

I will ping both public EC2 instances and only PUB_2 will reply:

[ec2-user@TEST_STATION ~]$ ping 52.28.51.98 -c 2
PING 52.28.51.98 (52.28.51.98) 56(84) bytes of data.
^C
--- 52.28.51.98 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 6427ms

[ec2-user@TEST_STATION ~]$ ping 52.29.185.126 -c 2
PING 52.29.185.126 (52.29.185.126) 56(84) bytes of data.
64 bytes from 52.29.185.126: icmp_seq=1 ttl=46 time=88.7 ms
64 bytes from 52.29.185.126: icmp_seq=2 ttl=46 time=88.5 ms

--- 52.29.185.126 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1090ms
rtt min/avg/max/mdev = 88.563/88.658/88.753/0.095 ms
[ec2-user@TEST_STATION ~]$

So we have a firewall at the instance level that is in place and protects my instances.

For the PUB_1 instance, the ICMP packets are dropped at the instance level.

The network ACL that is in place lets the ICMP packets enter the subnet because of the allow ALL inbound rule.

Also, because I’m using the same network ACL for both VPC subnets, when I try to ping PRIV_1 from PUB_2 using the private IP addressing, it works:

[ec2-user@PUB_2 ~]$ ping 172.16.2.14
PING 172.16.2.14 (172.16.2.14) 56(84) bytes of data.
64 bytes from 172.16.2.14: icmp_seq=1 ttl=64 time=0.532 ms
^C
--- 172.16.2.14 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 710ms
rtt min/avg/max/mdev = 0.532/0.532/0.532/0.000 ms
[ec2-user@PUB_2 ~]$

Let’s see if we can drop the ICMP packets at the public subnet entrance. For this, I will add another rule on the inbound direction of the network ACL, where I will deny the ICMP traffic from the IP of the test station (52.91.24.202):

As expected, the test station can no longer reach PUB_2 instance, nor can PUB_1 (but this wasn’t possible even before changing the network ACL):

[ec2-user@TEST_STATION ~]$ ping 52.28.51.98 -c 2
PING 52.28.51.98 (52.28.51.98) 56(84) bytes of data.
^C
--- 52.28.51.98 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 3222ms

[ec2-user@TEST_STATION ~]$ ping 52.29.185.126 -c 2
PING 52.29.185.126 (52.29.185.126) 56(84) bytes of data.
^C
--- 52.29.185.126 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 3094ms

[ec2-user@TEST_STATION ~]$

But PUB_2 can still reach PRIV_1:

[ec2-user@PUB_2 ~]$ ping 172.16.2.14 -c 2
PING 172.16.2.14 (172.16.2.14) 56(84) bytes of data.
64 bytes from 172.16.2.14: icmp_seq=1 ttl=64 time=0.566 ms
64 bytes from 172.16.2.14: icmp_seq=2 ttl=64 time=0.561 ms

--- 172.16.2.14 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.561/0.563/0.566/0.023 ms
[ec2-user@PUB_2 ~]$

As mentioned, the network ACLs are stateless and this means that you need to allow the returning traffic.

For instance, if I ping PUB_2 from TEST_STATION and I do not allow the ICMP replies from PUB_2, then the ping will be unsuccessful.

Let’s see an example. I removed the DENY rule from the inbound direction of the network ACL and added it to the outbound direction of the network ACL:

This means that the ICMP Request packet sent by the TEST_STATION will be received by PUB_2. PUB_2 will reply with an ICMP Reply packet, but that packet will not reach the TEST_STATION because the network ACL will drop it due to the outbound rule that denies the ICMP traffic.

How will I test this? I will start a ping from TEST_STATION towards PUB_2 and, with tcpdump started on the both hosts, I will see that TEST_STATION is seeing only ICMP Requests, while PUB_2 is seeing both ICMP Requests and Replies.

Keep in mind that, because these are EC2 instances in AWS, you will see private IP addresses as well. So the ping was started on TEST_STATION and these are the packets captured towards PUB_2 (52.29.185.126):

[ec2-user@TEST_STATION ~]$ sudo tcpdump -n -i eth0 host 52.29.185.126
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:14:00.104546 IP 172.31.48.96 > 52.29.185.126: ICMP echo request, id 48993, seq 1, length 64
14:14:01.111820 IP 172.31.48.96 > 52.29.185.126: ICMP echo request, id 48993, seq 2, length 64
^C
2 packets captured
2 packets received by filter
0 packets dropped by kernel
[ec2-user@TEST_STATION ~]$

And on PUB_2, these are the packets captured from TEST_STATION (52.91.24.202):

[ec2-user@PUB_2 ~]$ sudo tcpdump -n -i eth0 host 52.91.24.202
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:14:00.151860 IP 52.91.24.202 > 172.16.1.106: ICMP echo request, id 48993, seq 1, length 64
14:14:00.151885 IP 172.16.1.106 > 52.91.24.202: ICMP echo reply, id 48993, seq 1, length 64
14:14:01.159089 IP 52.91.24.202 > 172.16.1.106: ICMP echo request, id 48993, seq 2, length 64
14:14:01.159116 IP 172.16.1.106 > 52.91.24.202: ICMP echo reply, id 48993, seq 2, length 64
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel
[ec2-user@PUB_2 ~]$

So we have the confirmation that the traffic is unidirectional because of the DENY rule from the outbound direction of the network ACL.

Also, one can associate one subnet per network ACL if that better fits the security design for even more granularity at subnet level.

We have reached the end of the series. In the first part of the series we saw what the security levels are within a VPC, what the defaults are, and the difference between the two security levels. In the second part of the series we saw some practical examples of what happens when the default security groups and network ACLs are changed.

References