Network Access Control Lists and Security Groups

Network Access Control Lists (NACLs)

Security is a key part of any deployment within AWS, and managing security around your virtual private cloud is no different. NACLs are network access control lists.

Now these are essentially virtual network-level firewalls that are associated to each and every subnet, and they help to control both ingress and egress traffic moving in and out of your VPC and between your subnets.

To get started, lets first draw out our VPC and our public subnet represented in yellow. Now, this public subnet has a route to the Internet Gateway which allows us to reach the internet.

So what we can do here to help maintain security is to configure the network access control list associated to this subnet.

Now much like route tables, whenever you create a new subnet, it will also associate a network access control list.

Now by default, this NACL will allow all traffic, both inbound and outbound, so it’s not very secure, so it’s a really good practice to configure your NACLs to only allow the traffic that you want to come in and out of your subnet.

Inbound NACL

Now with this being a public subnet, we’ll probably have some web servers in here talking over HTTP and HTTPS, so let’s look at the inbound network access control list that could be associated to this subnet.

Now as you can see, there are a number of different fields. We have the rule number, the type, the protocol, port range, source, and allow or deny.

Now the rule numbers allow you to specify what order the rules will appear inside the NACL, and as soon as traffic hits one of these rule where it matches all of the type, protocol, port range, and source, et cetera, it will carry out the action at the end, whether that is allow or deny.

So let’s look at the requirements required to match the first rule. The type of traffic will need to be HTTP under port 80 using the TCP protocol, and again, the port range is 80 as that’s what used for HTTP. Now the source can be any IP address, so any IP address running HTTP coming into our subnet will be allowed. So as long as they’re running this protocol, then the traffic will be allowed inbound into our public subnet.

Now let’s look at the second rule. Now the second rule uses HTTPS using the TCP protocol using port 443, and again, any source, and the action will be allow.

Now the last rule here, now this is a default rule that’s applied at the end of every network access control list, and that’s why it doesn’t have a rule number, and it states that all traffic using any protocol in any port range from any IP address, then deny that access. So this rule is kind of a cover rule. So basically, what that allows you to do is ensure that any traffic that doesn’t meet the rules that you’ve entered is deleted and denied access to your subnet.

So with this in mind, the only traffic allowed in our public subnet is essentially HTTP and HTTPS, which is exactly what we want for our web servers here, and all other traffic will be denied. So that’s the inbound NACL.

Outbound NACL

Let’s now take a look at the outbound. Now the field types are all exactly the same except there is now a destination instead of a source. This has a destination whereas on the inbound, it has the source. So on the outbound, we restrict traffic against its destination.

So the first rule we have here says any traffic using any protocol in any port range going to any destination, then allow that traffic. Anything else should be denied, but in this case, there won’t be anything else because this outbound rule is essentially saying send any traffic you want to using any protocol out from this subnet to any destination.

Now an important point to make about NACLs is that they are stateless, and this means that any response traffic generated from a request will have to be explicitly allowed and configured in either the inbound or the outbound ruleset, depending on where the response is coming from. Now again, much like route tables, you can have the same NACL applied to a number of subnets, but only a single NACL can be associated to one subnet. So network access control lists are a great way to control traffic that comes into and out of a particular subnet.

What about Security groups then?:

You may have heard about security groups, and these are another method of controlling traffic, but this time, they work at the instance level rather than the network level like NACLs do.

Security Groups

Now these are similar to Network Access Controllers where they filter traffic both inbound and outbound but whereas NACLs worked at the subnet level, security groups work at the instance level and I’ll explain more about this as we go.

NACLs work at the subnet level, whereas Security Groups work at the instance level

Security Groups act as a virtual firewall at the instance level.

So let’s say we have three private subnets. Each of them will have their IP addresses listed, first one being, second one being and the last one Now lets say the first subnet will have EC2 instances in them. The second subnet will have RDS instances running MySQL or Aurora and the last subnet here will also have EC2 instances in them.

Now each of these three subnets are associated to the same Network Access Control list. And this network access control list looks like what is shown in the picture and this is simply saying that any traffic that is running a TCP Protocol across any port range from any source, then allow it and deny all other traffic. So, between these subnets, any TCP Protocol on any port can be used and for simplicity, the same NACL rules are being used for both inbound and outbound. Now that’s not very secure, it’s not very restrictive but from a subnet network level, that is what it’s controlling.

Now what we want to do is restrict access to which instances can actually talk to our RDS and Aurora databases here.

Now we only want to allow access from the subnet and deny access from subnet and we can use security groups to do just that.

So, let’s take a look at the security group for the subnet, from where our databases are. Now security groups have similar fields to NACLs but there’s just a couple less.

So, there’s no rule number with the security group which means all the rules within the security group will be assessed before a decision is made on the action and you’ll also notice, there’s no allow or deny either.

With security groups, if there’s a rule in there, then it’s considered allowed, if there’s no rule, then all traffic is dropped by default

So what this security group is stating that any MySQL or Aurora traffic using a TCP Protocol on the port 3306 from the source which is this subnet to the left, then it’s considered allowed as we don’t have another rule in this security group for the source of which is this subnet to the right. Then it’s considered denied. It doesn’t exist, so it’s not allowed access.

NACLs and Security Groups together

So how do both these NACLs and security groups work together?:

Well, the NACL works at the subnet level, so for illustration purposes let’s say the NACL is the purple line and as this NACL is associated to subnet as an example, let’s just put that NACL around the edge of the subnet like shown in the picture and let’s say the orange border is our security group and that security group is associated to our databases inside this subnet. So, let’s assume that our EC2 instances in the left subnet are looking to communicate with the RDS and Aurora databases.

So let’s have a look how that traffic would flow through the NACL and also the security group. So, the request would be sent, it would get to the NACL and the NACL say okay, is this traffic TCP traffic within this port range from any source? And it is. So, the traffic is allowed. So, that traffic is now allowed inside the subnet.

It then hits the security group and the security group says is this a MySQL or Aurora traffic running the TCP Protocol using port range 3306 coming from And it is as we’re trying to communicate with the databases, then access is allowed.

Now if we look from this subnet in the right, the and do the same thing where these two EC2 instances are trying to communicate with the RDS and Aurora instances using port 3306, let’s follow the same process.

So, the request is sent, it hits the NACL, the NACL says are you running TCP within this port range from any source? The answer is yes, so access is allowed. It then hits a security group and it says is this traffic MySQL or Aurora using TCP Protocol on port range 3306? At this point, everything is correct, yes. However, the source is different. We don’t have a source address of It doesn’t exist in the security group. So, at this point, the traffic is dropped at the security group and access is not allowed.

So, you can see how NACLs and security groups can be used to filter traffic at different layers. The NACLs are used for the subnet and network layer and the security groups are used at the instance layer. Now one final thing I want to say about security groups is that unlike NACLs which are stateless by design, security groups are stateful which means you don’t have to configure specific rules to allow return traffic from requests like you have to do with NACLs.


Network Access Control Lists filter traffic both inbound and outbound at the subnet level.

Security Groups filter traffic both inbound and outbound at the instance level.