In part two of the Cloud Network Security blog series, we will discuss two methods of securing your network within Amazon Web Services: security groups and network access control lists (NACLs). Both resource types act as a virtual firewall to protect your network, and they have some similarities. For example, security groups and NACLs both use sets of inbound and outbound rules to control traffic to and from resources in a VPC.
However, security groups and NACLs operate at separate layers in the VPC, have slightly different default rules, and don't handle response traffic the same way.
So, which is the best way to secure your network—security groups or NACLs?
The best solution, actually, is to implement both resource types to lock down your network. Defense in depth is all about layers of security; security groups and NACLs are two layers that complement each other.
But we'll get to that in a minute. First, let's quickly review the basics. We'll start with security groups.
What is an AWS security group?
In AWS, a security group controls traffic to or from an EC2 instance according to a set of inbound and outbound rules. This means it represents instance-level security. For example, an inbound rule might allow traffic from a single IP address to access the instance, while an outbound rule might allow all traffic to leave the instance.
Because security groups function at the instance level of a VPC, each security group can be applied to one or more instances, even across subnets. And each instance is required to be associated with one or more security groups. To be precise, a security group is associated with a network interface that is attached to an instance, but we don’t discuss that detail for simplicity.
When you create a VPC, AWS automatically creates a default security group for it. You can add and remove rules from a default security group, but you can't delete the security group itself.
Next, let's look at NACLs.
What is an AWS NACL?
In AWS, a network ACL (or NACL) controls traffic to or from a subnet according to a set of inbound and outbound rules. This means it represents network level security. For example, an inbound rule might deny incoming traffic from a range of IP addresses, while an outbound rule might allow all traffic to leave the subnet.
Because NACLs function at the subnet level of a VPC, each NACL can be applied to one or more subnets, but each subnet is required to be associated with one—and only one—NACL.
When you create a VPC, AWS automatically creates a default NACL for it. You can add and remove rules from a default NACL, but you can't delete the NACL itself.
What's the difference?
You can certainly protect your VPC with security groups alone. Since instances require security groups, you'll be using them anyway, so you might as well configure them according to your needs. And since security groups and NACLs have so much in common, you can achieve the same results with both. But to practice defense in depth, the best solution is to use both resource types as virtual firewalls. If you configure their rules properly, they make a very effective combination for filtering traffic to and from your instances.
Now that we've established the basics, let's dive into what makes security groups and NACLs different – and, more importantly, how they work together. We'll focus on these key areas:
- How to take advantage of the "order of operations"
- How they are applied to instances
- Everything you wanted to know about rules but were afraid to ask
- How state is handled
- Separation of duties
Taking advantage of the "order of operations"
When traffic enters your network, it is filtered by NACLs before it is filtered by security groups.
This means that traffic allowed by a NACL can then be allowed or denied by a security group, and traffic stopped by a NACL never makes it any further.
Given this "order of operations" in processing incoming traffic, here are two examples of implementing NACLs and security groups in tandem:
Use fine-grained rules with NACLs and let security groups handle inter-VPC connectivity.
For example, if you configure NACLs with granular rules for controlling inbound and outbound traffic, the NACLs can take the brunt of the work for filtering traffic. You can configure a NACL to allow inbound HTTP and HTTPS traffic from any IP address, deny all other inbound traffic, and allow all outbound traffic. As another example, you can allow inbound SSH access (port 22) from one IP address—yours—and allow outbound access on any port to the same IP address.
Meanwhile, you can configure a security group to allow inbound traffic from itself, enabling communication between resources. Or, you can configure the security group to allow traffic into and out of a different security group, which enables instances within different subnets to talk to each other.
Eliminate whole classes of traffic with NACLs and use fine-grained rules with security groups.
In this scenario, you can configure a NACL to deny all traffic from a wide range of IP addresses to a certain protocol and port and allow the rest to continue to the security group, which may be configured to evaluate incoming and outgoing traffic on a more granular level. The NACL takes a coarse-grained approach to controlling traffic, leaving the security group to filter the rest through a fine-toothed comb.
Application to AWS EC2 instances
As we mentioned earlier, security groups work at the instance level while NACLs work at the subnet level.
Security groups are a required form of defense for instances, because an instance must be associated with at least one security group. You can't launch an instance without one, and you can't remove the only remaining security group from an existing instance.
However, a particular security group only applies to an instance if a user deliberately associates it with the instance, either at launch time or after the instance has been created.
A NACL, on the other hand, automatically applies to all instances in the subnet it is associated with. This bolsters security when used in conjunction with security groups. For example, if a user accidentally associates the instance with an overly permissive security group, the instance can still be protected by the NACL.
NACLs are considered an optional form of defense for instances. A subnet must have a NACL, but by default, a NACL is configured to allow all traffic in and out. In contrast, security groups are locked down by default.
Speaking of rules, let's dive into how they work for both security groups and NACLs.
Inbound and outbound rules
How rules are evaluated
Both security groups and NACLs have inbound and outbound rules. However, AWS evaluates all rules for all the security groups associated with an instance before deciding whether to allow traffic in or out. The most permissive rule is applied—so remember that your instance is only as secure as your weakest rule.
In contrast, AWS processes NACL rules one at a time. Each NACL rule has a number, and AWS starts with the lowest numbered rule. If traffic matches a rule, the rule is applied and no further rules are evaluated. If traffic doesn't match a rule, AWS moves on to evaluate the next consecutive rule.
Allow vs. deny rules
Security group rules are implicit deny, which means all traffic is denied unless an inbound or outbound rule explicitly allows it. You can only add or remove "allow" rules—you can't add or remove "deny" rules, and there's no need to.
With NACLs, on the other hand, you may add or remove "allow" and "deny" rules. An inbound or outbound rule may explicitly allow or deny matching traffic.
Default security groups, default NACLs
When you create a VPC, AWS automatically creates a default security group and default NACL for you.
You may also create custom (non-default) security groups and NACLs on your own.
All security groups and NACLs—whether default and custom—come with a set of default rules.
This set of default rules varies depending on whether it applies to a default or custom security group or NACL. Let's take a look at the difference.
Default security groups: An AWS created default security group has one default inbound rule allowing traffic from other instances associated with the same security group. The rule enables the instances to communicate with each other without needing to go out to the internet.
Default security groups, like all security groups, have one default outbound rule allowing all outbound traffic.
Custom security groups: When you create a custom (non-default) security group, it has no inbound rules by default.
User-created security groups, like all security groups, have one default outbound rule allowing all outbound traffic.
Default NACLs: Unlike security groups, an AWS created default NACL has default rules that allow all inbound and outbound traffic. This default NACL has one "allow-all" and one "deny-all" rule for both inbound and outbound traffic, for a total of four default rules. The allow-all rules are processed first. The deny-all rules have an asterisk instead of a number, so they are not processed unless no other rule matches.
As a result, default NACLs allow all inbound and outbound traffic by default.
Custom NACLs: When you create a custom (non-default) NACL, it has one deny-all rule for both inbound and outbound traffic, like default NACLs do. The deny-all rules have an asterisk instead of a number. However, unlike default NACLs, a custom NACL has no allow-all rules, so the deny-all rule matches traffic instead.
As a result, custom NACLs deny all inbound and outbound traffic by default.
You can remove any existing inbound or outbound rule on a security group.
In contrast, you can remove any existing rule on a NACL except for the default deny-all rules.
In either case, the end result is the same—all inbound and all outbound traffic is denied.
NACL rules, security group rules, and you
Security group rules and NACL rules can accomplish the same tasks and control traffic the same way. Default NACLs are allow-all, so if you choose to leave them that way, use security groups to filter VPC traffic. However, the most secure approach is to use NACLs as a first line of defense and then configure security groups to handle traffic allowed from the NACLs. You can do this by configuring the same rules for both security groups and NACLs.
This defense in depth method promotes network redundancy and lowers the risk of misconfiguration, data leakage, and attacks from malicious actors. If a NACL is misconfigured, a security group would have to be misconfigured the same way in order to let traffic through. For example, if a NACL rule opens port 22 up to the world, a security group rule would also have to open port 22 to the world in order for unauthorized SSH traffic to get through to the instance.
Another important distinction between security groups and NACLs is whether they apply rules based on connection state.
Security groups are stateful; they automatically allow return traffic, no matter what rules are specified. If your instance sends out a request, the connection is tracked and the response is accepted regardless of explicit inbound rules. If traffic is allowed into an instance, the response is allowed out regardless of explicit outbound rules.
NACLs, on the other hand, are stateless. If an instance in your subnet sends out a request, the connection is not tracked and the response is subject to the NACL's inbound rules. Likewise, if traffic is allowed into a subnet, the response is evaluated according to outbound rules.
Practically speaking, this means that NACL rules typically come in pairs. For every inbound rule for a NACL, there must be a corresponding outbound rule, and vice versa.
Security groups don't need rules to evaluate response traffic. There's only a need to define inbound or outbound rules to evaluate requests, because once a request is permitted, its response is automatically permitted as well.
State doesn't generally weigh heavily in the decision to implement security groups vs. NACLs, because both tools can effectively control traffic. The main difference with regard to statefulness is that with security groups, you can't allow traffic in one direction but disallow the response.
For instance, if your source is outside the instance and it's permitted in, you'll be unable to deny the response because it will automatically flow back out. If your security posture requires very granular controls for handling request and response traffic, NACLs are more suitable for the task because both requests and responses are evaluated according to explicit rules.
On the other hand, if you have a small operation and don't need request and response traffic evaluated on such a granular level, security groups are easier to manage and require fewer rules than NACLs.
Ultimately, both methods are valid on their own—and even better when combined.
Separation of duties
Configuring both security groups and NACLs promotes separation of duties, which is another security best practice. Since security groups and NACLs operate at different levels, you can ensure different teams are responsible for them. If your organization has a team for the network security layer and a team for the server security layer, the network admins can manage the NACLs and the server admins can manage the security groups. This way, it's much more difficult for a single team member to compromise both layers of security. It's also a way to promote the security principle of least privilege, because responsibilities are divvied up between teams.
The best of both worlds
Let's sum up what we've learned about security groups and NACLs:
- Use inbound and outbound rules to control traffic
- Can be applied to more than one instance (security group) or subnet (NACL)
- Can be locked down to deny all traffic in either direction
- Are valid methods of securing resources in a VPC
- Work together to promote network redundancy and prevent unauthorized activity
In short, security groups and NACLs can be used to secure your network—on their own and together. When configured properly, both present effective ways of protecting resources in your VPC. Please note that simply having these resources in your network isn't enough; in the end, it all comes down to how you configure them. Your strictest firewall is only as secure as its most permissive rule. And all of the security groups and all of the NACLs in the world can't protect your instance if there's a rule allowing all traffic from all sources to access it.