On AWS, segment with layers. Use subnets to group tiers, security groups as the main per-resource control, and network ACLs as a coarse subnet-level backstop. Add flow logs and an access analysis to confirm the real paths match your intent. Security groups are stateful and network ACLs are stateless, and that difference shapes how you write rules.
What is segmentation trying to achieve?
The aim is to limit what a compromised component can reach. A web tier that is breached should not be able to talk to every database, build server and admin interface in the account. Segmentation turns "everything can reach everything" into a short list of allowed paths that you can read and review.
CISA's hardening guidance for communications infrastructure, written for network devices but a good general statement, calls for strong segmentation, placing externally facing services in a DMZ away from internal resources, and putting devices with similar purposes in the same group. The same ideas map to subnets and security groups in a cloud network.
How do security groups and NACLs differ?
AWS documents the two clearly.
Security groups attach to resources, such as an EC2 instance, and control inbound and outbound traffic for them. They are stateful: if you send a request from an instance, response traffic is allowed back in regardless of inbound rules, and responses to allowed inbound traffic can leave regardless of outbound rules. Each rule names a source or destination, port range and protocol.
Network ACLs attach to subnets. Each rule is numbered from 1 to 32766 and either allows or denies, evaluated in order starting from the lowest number. A subnet can be associated with only one NACL at a time. NACLs are stateless, so a rule allowing inbound traffic does not automatically allow the reply. AWS recommends numbering in increments of 10 or 100 so you can insert rules later.
Because NACLs can deny and security groups cannot express a deny, NACLs are the place for a coarse "never" rule, such as blocking a known-bad range for a whole subnet. Keep most logic in security groups, which are easier to reason about.
What does a sensible layout look like?
A constructed example for a three-tier web application, spread across multiple Availability Zones as AWS advises for availability:
- A public subnet group holds only the load balancer.
- An application subnet group holds the web or API servers. Their security group accepts traffic only from the load balancer's group on the application port.
- A data subnet group holds the database. Its security group accepts traffic only from the application group on the database port, and its NACL denies everything else.
- Management access goes through a separate path, not through the public tier.
Notice that rules refer to roles, not addresses. When rules are written by group, adding a server to a tier needs no rule changes.
How do you check it's working?
Do not trust the diagram. The VPC security best practices page suggests VPC Flow Logs to monitor IP traffic to and from a VPC, subnet or network interface, Network Access Analyzer to identify unintended network access to resources, and AWS Network Firewall to filter inbound and outbound traffic. The same page notes that these are general guidelines, not a complete security solution, and may not suit every environment.
Use flow logs to find accepted traffic you did not expect. Use access analysis to ask "can this subnet reach that one?" and compare the answer with your design.
What mistakes recur?
Wide open ranges "temporarily" added during debugging and never removed. One flat security group shared by every instance. Databases in a subnet with a route to the internet. Forgetting that NACLs are stateless and breaking replies. And no review process, so rules only ever grow.
What to do
- Draw the allowed paths first: who talks to whom, on which port.
- Create subnet groups per tier across multiple Availability Zones.
- Write security groups per role, referencing roles and not address ranges where possible.
- Use NACLs sparingly for coarse denies, with numbered gaps.
- Turn on flow logs and run an access analysis to compare with the design.
- Review rules on a schedule and remove anything without an owner.
- Scan what runs inside the segments too. Safeguard's free scan at gold.safeguard.sh/scan checks up to 100 dependencies.
Quick check
Do I need to add a return rule for a security group?
No. Security groups are stateful, so response traffic for allowed requests is permitted.
Why is a NACL rule for inbound traffic sometimes not enough?
NACLs are stateless. Replies are not automatically allowed, so you need a matching rule for the return direction.
Sources
- AWS: Security groups
- AWS: Network ACLs
- AWS: Security best practices for your VPC
- CISA: Enhanced Visibility and Hardening Guidance for Communications Infrastructure
Last reviewed: 18 October 2026.