Skip to content
Ashish.
All posts
Diagram illustrating the layered defense of AWS VPC, Security Groups, NACLs, and IAM integration.

AWS Network Security: VPC, SG, NACLs & IAM Integration

An examination of AWS VPC, security groups, and NACLs with IAM integration for advanced network security.

By Ashish SrivastavaPart 12 of AWS IAM & Cloud Security Series

AWS Network Security: VPC, Security Groups, and NACLs with IAM Integration

In a traditional on-premises data center, the network perimeter was often defined by a physical firewall at the edge. In AWS, that perimeter is logical, distributed, and granular. The core mechanism of AWS network security relies on three distinct layers: the Virtual Private Cloud (VPC) as the container, Security Groups as the stateful host-level shield, and Network Access Control Lists (NACLs) as the stateless subnet-level gate. These layers do not operate in isolation; they are orchestrated through Identity and Access Management (IAM) policies that control the configuration of these resources via API calls, and vpc-endpoints that bypass public routing entirely to secure data flow.

This article is Part 12 of the AWS IAM & Cloud Security Series.

The VPC Boundary and Route Logic

The VPC is a logically isolated section of the AWS Cloud where you launch AWS resources. It is not merely a folder; it is a network topology defined by an IPv4 (and optionally IPv6) CIDR block. When you create a VPC, you establish a boundary where traffic must follow specific routing paths to reach destinations.

Consider a scenario where DevOps-Engineer-Alice provisions a VPC with CIDR 10.0.0.0/16. Within this VPC, she creates two subnets: subnet-public (10.0.1.0/24) and subnet-private (10.0.2.0/24). The critical mechanism here is the Route Table. Every subnet is associated with exactly one main route table. By default, this table allows local VPC traffic but blocks all internet traffic. To enable internet access, Alice must attach an Internet Gateway (IGW) and add a specific route: 0.0.0.0/0 pointing to the IGW.

Without this route entry, even if a Security Group allows port 80, the packet will never reach the instance because the routing logic determines the packet has no path to its destination. Conversely, if the route exists but the Security Group denies port 80, the packet leaves the instance but is dropped at the instance interface. This hierarchy means the Route Table determines reachability first, followed by the NACL as the first stateless security filter, and finally the Security Group.

It is crucial to distinguish that Route Tables do not drop packets based on security policy; they drop them due to a lack of a valid route. NACLs serve as the subnet-level security filtering layer.

Stateful Security Groups: The Connection Tracker

Security Groups (SGs) are the primary defense mechanism for individual EC2 instances, RDS databases, or Lambda functions. They operate at the OS network interface level. The defining characteristic of a Security Group is that it is stateful.

Imagine App-Server-01 running behind a Security Group with an inbound rule allowing TCP port 443 from 0.0.0.0/0. When a client at 203.0.113.50 initiates a HTTPS connection, the packet arrives. The Security Group checks the rule, sees the port and source match, and allows the packet. The instance processes the request and sends a response back to 203.0.113.50.

Because the Security Group is stateful, it automatically tracks the connection state in its internal session table. When the response packet (TCP SYN-ACK) returns, the Security Group does not check the inbound rules again. Instead, it verifies that the packet belongs to an established connection in its session table and allows it to pass through, regardless of the outbound rules. This is why Security Groups typically have no outbound rules configured by default; they allow all outbound traffic by default, but the stateful nature handles the return traffic automatically.

This mechanism contrasts sharply with stateless systems. If you were to manually configure a stateful filter without session tracking, you would need to write explicit rules for every possible return port, which is impossible for ephemeral ports used in dynamic applications.

# Example Security Group Rule (JSON format for clarity)
{
  "IpProtocol": "tcp",
  "FromPort": 443,
  "ToPort": 443,
  "IpRanges": [
    {
      "CidrIp": "0.0.0.0/0",
      "Description": "Allow HTTPS from anywhere"
    }
  ]
}

However, this stateful behavior has a tradeoff. If an attacker establishes a connection and then attempts to send a malicious payload on a different port within that same connection (e.g., tunneling), the stateful engine might allow it because the connection was already deemed valid at the handshake. This is why Security Groups are insufficient as the sole line of defense for high-security environments; they are designed for "allow-listing" trusted traffic, not deep packet inspection.

Stateless NACLs: The Subnet Gatekeeper

Network Access Control Lists (NACLs) operate at the subnet boundary. Unlike Security Groups, NACLs are stateless. They do not track connection states. Every packet, whether it is an incoming request or an outgoing response, is evaluated against the rules independently. NACLs function as a robust AWS network firewall at the subnet level.

Let's trace a scenario where App-Server-01 in subnet-private initiates an SSH connection to a database in subnet-public.

  1. Outbound Request: The packet leaves App-Server-01. The NACL on subnet-private checks its outbound rules. It must have an explicit rule allowing traffic to the destination IP on the ephemeral port range. Linux instances typically use 32768-60999 for ephemeral ports, while Windows instances typically use 1024-65535. If this rule is missing, the packet is dropped immediately.
  2. Inbound Response: The database responds. The packet enters subnet-private. The NACL on subnet-private checks its inbound rules. Because the NACL is stateless, it does not know this packet is part of a conversation. It must have an explicit rule allowing the return traffic from the database's IP on the ephemeral port range.

If you configure an NACL to allow port 22 (SSH) for inbound traffic but forget to allow the ephemeral ports for outbound traffic, the connection will fail. The client sends the SYN, the server responds, but the NACL on the client's subnet drops the SYN-ACK because the ephemeral port rule is missing.

NACLs also support rule priorities. Rules are evaluated in ascending order (lower number = higher priority). The first rule that matches the traffic is applied, and the evaluation stops. If no rule matches, the default "deny all" rule (rule number *) at the end of the list kicks in. This is a crucial distinction from Security Groups, which evaluate all rules and implicitly deny anything not explicitly allowed.

# CLI example: Creating a NACL rule for ephemeral ports
aws ec2 create-network-acl-entry \
  --network-acl-id acl-0123456789abcdef0 \
  --protocol tcp \
  --rule-number 110 \
  --egress true \
  --port-range-from 1024 \
  --port-range-to 65535 \
  --cidr-block 0.0.0.0/0 \
  --allow

The operational implication is that NACLs are harder to manage at scale due to the need to explicitly define both ingress and egress paths for every flow. They are best suited for broad, coarse-grained filtering (e.g., blocking a specific malicious IP range across an entire subnet) rather than fine-grained instance control.

IAM Integration and VPC Endpoints

Network security in AWS is incomplete without controlling who can change these rules. This is where IAM integration becomes critical. Every action taken on a VPC, Security Group, or NACL is an API call to ec2:AuthorizeSecurityGroupIngress, ec2:CreateNetworkAclEntry, or similar. IAM controls the configuration of these layers via API calls, not the packet traversal itself.

An IAM policy can restrict these actions based on the principle of least privilege. For example, a junior engineer should not be able to open port 22 to the world (0.0.0.0/0). You can write an IAM policy that denies ec2:AuthorizeSecurityGroupIngress if the SourceIp is 0.0.0.0/0.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PreventPublicSSH",
      "Effect": "Deny",
      "Action": "ec2:AuthorizeSecurityGroupIngress",
      "Resource": "arn:aws:ec2:*:*:security-group/*",
      "Condition": {
        "StringEquals": {
          "ec2:SourceIp": "0.0.0.0/0"
        }
      }
    }
  ]
}

This policy acts as a logical firewall on the control plane. Even if a developer tries to run the AWS CLI command to open the port, the IAM layer intercepts the request and rejects it before the network configuration is updated.

Beyond access control, the architecture of data flow is secured using vpc-endpoints. By default, when an EC2 instance communicates with an AWS service like S3 or DynamoDB, the traffic traverses the public internet (via an Internet Gateway or NAT Gateway) unless a vpc-endpoint is configured. This exposes the traffic to potential interception and incurs data transfer costs.

A vpc-endpoint creates a private connection between your VPC and supported AWS services.

  • Gateway Endpoints (for S3 and DynamoDB): These modify the route table to direct traffic for these services directly to the AWS network backbone, bypassing the internet entirely.
  • Interface Endpoints (for most other services like SQS, SNS, Lambda): These create Elastic Network Interfaces (ENIs) with private IP addresses in your subnets, allowing traffic to stay within the AWS network.

When you combine vpc-endpoints with IAM policies, you achieve a "Private API" architecture. You can configure an IAM policy on the S3 bucket that says, "Only allow access from this specific vpc-endpoint." This means even if someone compromises an EC2 instance with public internet access, they cannot reach the S3 bucket because the IAM policy checks the aws:SourceVpce condition.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RestrictS3AccessToEndpoint",
      "Effect": "Deny",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::my-private-bucket/*",
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0123456789abcdef0"
        }
      }
    }
  ]
}

Synthesis: The Defense-in-Depth Flow

The security posture of an AWS VPC is the result of these mechanisms interacting in sequence. When a packet enters your infrastructure, it follows this path:

  1. Route Table Check: Does the route exist? If not, drop (no reachability).
  2. NACL Check: Is the subnet allowed to receive this packet on this port? (Stateless, explicit allow/deny).
  3. Security Group Check: Is the instance allowed to receive this packet? (Stateful, connection tracking).
  4. OS Firewall: The operating system's own firewall (e.g., iptables, Windows Firewall) provides the final layer.

Conversely, for API calls modifying these resources, the path is:

  1. IAM Authentication: Who is making the request?
  2. IAM Authorization: Does the user have permission to ec2:ModifyNetworkInterfaceAttribute on this specific resource?
  3. Service Validation: Does the AWS control plane allow this configuration change (e.g., checking for overlapping CIDRs)?

This layered approach ensures that even if one layer is misconfigured, the others provide a fallback. However, the complexity of managing stateless NACLs alongside stateful Security Groups requires strict operational discipline. A common failure mode is the "NACL blocking return traffic" scenario, which can be mitigated by using AWS Config rules to audit NACL rules for ephemeral port allowances.

Ultimately, the most robust network security architecture in AWS is not just about the rules you write, but the integration of IAM policies that prevent those rules from being misconfigured, and vpc-endpoints that ensure the data never leaves the private network fabric. This shifts the security model from perimeter-based to identity-based, where the "network" is secondary to the "identity" of the workload.

Conclusion

Securing AWS infrastructure requires a shift from physical perimeter thinking to a granular, identity-centric model. By leveraging the stateful nature of Security Groups, the strict subnet gating of NACLs, and the rigorous control of IAM policies, organizations can build a defense-in-depth architecture that protects both data in transit and the control plane. Understanding the precise interaction between these layers—specifically how routing precedes filtering and how IAM policies act as the ultimate gatekeeper—is essential for any advanced cloud practitioner.

Common Pitfalls

  1. Assuming Route Tables Block Traffic: Engineers often believe a missing route table entry is a security block. In reality, it is a routing failure. Security must be enforced explicitly via NACLs or Security Groups, not by relying on the absence of a route.
  2. Ignoring Ephemeral Ports in NACLs: Configuring an NACL to allow inbound traffic on a specific port (e.g., 22) without allowing the corresponding ephemeral port range for outbound responses is a leading cause of connectivity failures. Remember that Linux and Windows ephemeral port ranges differ.
  3. Over-reliance on Security Groups: Security Groups are stateful and excellent for allow-listing, but they do not inspect traffic payloads. For high-security environments requiring deep packet inspection or strict egress filtering, NACLs or AWS Network Firewall are necessary complements.

Practical Takeaways

  • Separation of Concerns: Use Route Tables for reachability, NACLs for coarse subnet filtering, and Security Groups for fine-grained instance control.
  • Stateless Discipline: When configuring NACLs, always define both inbound and outbound rules explicitly. The stateless nature requires you to anticipate return traffic.
  • Identity as the Perimeter: Use IAM policies with aws:SourceVpce conditions to ensure that even if network routes are compromised, access to sensitive services remains restricted to private endpoints.

FAQ

Q: Can I use a Security Group to filter traffic based on source IP? A: Yes, Security Groups can filter based on source IP addresses or CIDR blocks in their inbound rules. However, they cannot filter based on source port, whereas NACLs can.

Q: Do Security Groups apply to subnets or instances? A: Security Groups apply to network interfaces (instances, ENIs). NACLs apply to subnets. All instances in a subnet share the same NACL rules, but each instance can have its own unique Security Group rules.

Q: How do VPC Endpoints affect NAT Gateways? A: VPC Endpoints (specifically Interface and Gateway endpoints) allow instances in private subnets to access AWS services without traversing a NAT Gateway or Internet Gateway. This reduces costs and improves security by keeping traffic within the AWS backbone.

Related posts