Join our Newsletter — 33% off our NHI Course
Home› Guides› Security Groups vs Network ACLs: Evaluation Order and…
Guide Cloud Security

Security Groups vs Network ACLs: Evaluation Order and Failure Modes Across Clouds

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 17 min read
On this page

Most cloud filtering outages and most silent exposures come from the same root cause: engineers assume a rule is evaluated the way their last firewall worked, when the cloud evaluates it differently. A stateless AWS network ACL drops return traffic that a stateful security group would have allowed, an Azure subnet NSG denies a flow before the NIC NSG ever sees it, and a Google Cloud hierarchical policy can allow traffic that a project's VPC firewall rules were written to block. This guide compares stateful and stateless cloud filtering in depth: how each layer is evaluated, which one wins, why ephemeral ports and asymmetric rules break things, and which design patterns hold up at scale. Platforms are listed alphabetically (AWS, Azure, Google Cloud); order is never a ranking.

Key takeaways

  • Stateful and stateless solve different problems. A stateful filter tracks a connection and lets the reply back in automatically; a stateless filter judges every packet alone, so each allowed request needs a matching rule for the response on ephemeral ports.
  • Evaluation order is the real comparison. AWS security groups evaluate all rules and allow on any match, AWS network ACLs stop at the lowest-numbered match, Azure NSGs stop at the first match by priority, and Google Cloud walks a fixed sequence of policies before VPC firewall rules or after them.
  • Both layers must agree. Traffic that crosses two filters (subnet and instance, subnet NSG and NIC NSG, hierarchical policy and VPC rule) is only delivered if every layer it meets allows it, so troubleshoot with the effective rules, not one rule list.
  • Rule changes do not always cut live sessions. Tracked connections survive the removal of the rule that allowed them on all three platforms; AWS documents a network ACL deny as the way to stop a tracked flow immediately.
  • Use the instance layer for intent and the subnet or organisation layer for guardrails. Write application allow lists against workload identities (security group references, application security groups, service accounts) and keep coarse, rarely changing denies at the outer layer.

The short answer

A security group (AWS), a network security group (Azure) and a VPC firewall rule or firewall policy (Google Cloud) are all stateful: allow a request and the reply is let back in. An AWS network ACL is stateless and attached to a subnet: it allows or denies each packet in each direction independently, in rule-number order. AWS describes the security group as the instance-level control and the network ACL as the subnet-level control, and says you can secure instances with security groups alone and add network ACLs as an additional layer.

Azure and Google Cloud do not have a separate stateless subnet ACL in the AWS sense. On Azure the subnet layer is another stateful NSG, plus Azure Virtual Network Manager security admin rules applied to whole virtual networks. On Google Cloud the outer layer is the hierarchical firewall policy attached to the organisation or folders. So the cross-cloud question is less "stateful or stateless" and more "which layer decides first, and which layer is allowed to override the other".

For AWS defaults see the Amazon VPC Security Guide; for cross-cloud design see the Cloud Network Security Guide.

How each platform evaluates rules

Platform and controlAttached toStateRule actionsEvaluation
AWS security groupNetwork interface (instance level)StatefulAllow onlyAll rules evaluated before deciding; any matching allow permits the traffic
AWS network ACLSubnet (one ACL per subnet, one ACL can serve many subnets)StatelessAllow and denyAscending rule number, first match applies; a final * rule denies anything unmatched and cannot be deleted
Azure network security groupSubnet or network interfaceStateful (flow records)Allow and denyPriority 100 to 4096, lowest first, processing stops at first match; default rules at 65000, 65001 and 65500
Azure Virtual Network Manager security admin ruleVirtual networks in a network groupApplied before NSGsAllow, Always allow, DenyPriority 1 to 4096; Allow continues to NSGs, Always allow and Deny stop evaluation
Google Cloud VPC firewall ruleVPC network, targeted by network tag or service accountStateful (connection tracking)Allow and denyPriority 0 to 65535 (default 1000), highest priority wins; at equal priority deny beats allow
Google Cloud firewall policy (hierarchical, global or regional network)Organisation, folder, or networkStatefulAllow, deny, goto_next, apply_security_profile_groupUnique priorities within a policy, first match; allow or deny stops all evaluation, goto_next passes to the next step

AWS: route table, then network ACL, then security group

AWS describes inbound traffic from an internet gateway as being routed to a subnet by the route table, then filtered by the subnet's network ACL, then filtered by the security group on the instance. Inside the security group there is no order: all rules are evaluated, and because rules are allow only, a broad rule in any attached group opens the port for the interface. Inside the network ACL order is everything: the lowest-numbered match applies regardless of any later rule. AWS advises giving a deny rule a lower number than a broader allow it must override.

Azure: subnet NSG and NIC NSG in series

For inbound traffic Azure evaluates the NSG on the subnet first, then the NSG on the network interface; outbound traffic meets the NIC NSG first and the subnet NSG second. The same order applies inside a subnet, and both NSGs must allow a flow: if the subnet NSG denies inbound traffic, the NIC NSG never evaluates it. Above both sit security admin rules from Azure Virtual Network Manager, evaluated before any NSG, so a central Deny on a port holds even when an application team allows it.

Google Cloud: a fixed sequence of policy steps

Google documents the order exactly. With the default enforcement order AFTER_CLASSIC_FIREWALL, a packet meets hierarchical firewall policies (organisation first, then folders down to the project's folder), then regional system firewall policies, then VPC firewall rules, then global network firewall policies, then regional network firewall policies, and finally the implied action. Setting networkFirewallPolicyEnforcementOrder to BEFORE_CLASSIC_FIREWALL moves VPC firewall rules after the network policies; hierarchical and regional system policies always run first. If every step passes, the implied action denies ingress to a VM interface and allows egress.

Why stateless filtering breaks: ephemeral ports and asymmetric rules

Every client connection uses a high, temporary source port for the reply. A stateful filter remembers the outbound request and lets the reply in on that port. A stateless AWS network ACL does not, so AWS states that for every rule you add there must be an inbound or outbound rule that allows the response traffic. The client chooses the port range, and the range differs by client:

Client (AWS documentation)Ephemeral port range
Many Linux kernels, including Amazon Linux32768 to 61000
Windows Server 2008 and later49152 to 65535
Windows through Windows Server 20031025 to 5000
Elastic Load Balancing1024 to 65535
NAT gateway1024 to 65535
AWS Lambda functions1024 to 65535

AWS recommends opening 1024 to 65535 for return traffic so that every client type works, and placing any deny rules for specific ports in that range earlier in the table than the allow. Four failure modes follow from this:

  • Linux-only return range: an ACL written for 32768 to 61000 works in testing from Linux hosts, then breaks for traffic arriving through a load balancer or NAT gateway, which use 1024 to 65535. The symptom is intermittent: only some connections fail.
  • Asymmetric rule pairs: an inbound allow for TCP 443 on the web subnet without the matching outbound allow to the client range. The TCP handshake never completes, and security group logs look clean because the drop happens at the subnet.
  • Forgotten initiator direction: instances in a subnet that call out (package mirrors, APIs, databases in another subnet) need an outbound allow to the destination port and an inbound allow for the reply on the instance's own ephemeral range. Teams that think only about inbound service ports break outbound calls.
  • Two subnets, four rules: traffic between an application subnet and a database subnet crosses two ACLs. A single flow needs an outbound and inbound rule on each side, four in total, and any one missing rule fails the connection.

Stateful filters avoid all four. On Azure and Google Cloud the equivalent asymmetry is two stateful layers in series, such as a subnet NSG allowing what the NIC NSG denies; the fix is the same: list every layer a packet meets and confirm each allows it.

Connection tracking and live sessions

Stateful means rule changes behave differently from what many responders expect.

  • AWS: tracked connections continue until they time out even after the allowing rule is removed. AWS documents adding a network ACL deny to stop them immediately, because ACLs are stateless. A flow is untracked only when rules allow all traffic (0.0.0.0/0 or ::/0) in one direction and all response traffic on all ports in the other; untracked flows stop as soon as the rule changes. On Nitro instances the idle TCP established timeout defaults to 432,000 seconds on most instance types (350 seconds on Nitro v6, excluding P6e-GB200) and can be set per network interface between 60 and 432,000 seconds.
  • Azure: NSG rule changes apply only to new connections. Microsoft's example is an SSH session that stays connected after the allowing rule is removed, while new SSH attempts are blocked.
  • Google Cloud: Cloud NGFW checks the connection tracking table before evaluating rules, and an existing tracking entry takes precedence over a later deny rule. Tracking stays active while at least one packet passes every 10 minutes, and return traffic for an allowed connection cannot be denied by a rule.

For incident response, removing an attacker's inbound rule does not end their session. On AWS a subnet ACL deny ends it; on Azure and Google Cloud also act at the workload (isolate the VM, revoke credentials).

What none of these filters see

Each platform exempts some platform traffic from its filters by default, and these exemptions are where filtering assumptions fail.

PlatformTraffic outside the filter by defaultWhat to use instead
AWSSecurity groups do not filter Amazon DNS, DHCP, EC2 instance metadata, ECS task metadata, Windows licence activation, Amazon Time Sync Service and reserved router addressesRequire IMDSv2 with a hop limit; filter DNS with Route 53 Resolver DNS Firewall
AzureNSGs do not filter platform traffic to 168.63.129.16 and 169.254.169.254 by defaultDeny rules using the AzurePlatformDNS, AzurePlatformIMDS and AzurePlatformLKM service tags, after testing (blocking IMDS breaks managed identity token requests)
Google CloudTraffic to and from the metadata server at 169.254.169.254 (and fd20:ce::254) and traffic that stays inside the VM are not subject to firewall rulesScope the attached service account tightly and control what can make requests from the VM

The metadata exemption is the important one: a web flaw that makes a server fetch its own metadata endpoint returns cloud credentials, and no security group, NSG or firewall rule sees it. That is the pattern in the Capital One breach, where a firewall's role credentials were read through the metadata service. See the Cloud Instance Metadata Services Compared Guide and the EC2 Instance Metadata Service Hardening Guide.

Where identity fits

The strongest cloud rules name a workload identity instead of an address. AWS security groups can reference another security group, so the database allows "the application tier" rather than a list of IPs. Azure application security groups let NSG rules use a group of VMs as source or destination. Google Cloud VPC firewall rules can target by service account or by network tag, and Google notes that a service account target is controlled through the Service Account User role and needs a stop and restart to change, unlike a tag. Treat the permission to change tags, groups or rules as privileged. Adversaries who change cloud firewall rules map to ATT&CK T1686 Disable or Modify System Firewall. See the Google Cloud VPC and Cloud NGFW Security Guide and the Azure Virtual Network Security Guide.

Design patterns that hold up

  • Intent at the workload, guardrails outside: write per-application allow lists in security groups, NIC-level or subnet NSGs with application security groups, or VPC firewall rules targeted by service account. Put a short list of organisation-wide denies (remote administration ports from the internet, known bad ranges) in an AWS network ACL, an Azure security admin Deny rule or a Google Cloud hierarchical policy. Application teams then cannot override the guardrail.
  • One NSG layer per path on Azure: follow Microsoft's advice to attach an NSG to the subnet or the NIC, not both, unless you have a written reason. Two layers double the rules and the troubleshooting.
  • Simple, numbered network ACLs on AWS: number in steps of 10 or 100 so a deny can be inserted above an allow, open return traffic on 1024 to 65535, and keep the rule count well below the quota. AWS sets a default of 20 rules per ACL per direction, adjustable to 40, and notes that raising it may affect network performance.
  • Few groups, referenced not duplicated: AWS defaults to 60 rules per security group and 5 groups per interface, and the product of the two cannot exceed 1,000. Reference tier groups instead of listing addresses.
  • Everything as code: manage rules through reviewed infrastructure as code and scan before merge. See the Checkov and IaC Scanners Guide.

Decision guidance: when to use each layer

NeedAWSAzureGoogle Cloud
Per-application allow listSecurity group referencing tier groupsNSG rules using application security groupsVPC firewall rule or network firewall policy targeted by service account
Organisation-wide deny that teams cannot overrideNetwork ACL deny (per subnet), managed centrallySecurity admin Deny ruleHierarchical firewall policy deny at organisation or folder
Cut an active tracked session nowNetwork ACL deny for the flowRule change plus action at the workloadRule change plus action at the workload
Allow traffic a project must not blockCentral account owns the security groupSecurity admin Always allowHierarchical policy allow

Small organisations can run on workload-level stateful rules alone, with flow logs and change alerts, adding an AWS ACL only for a specific block list. Large organisations should separate the guardrail owner (central team) from the rule owner (application team) using the layer built for that split.

Worked scenario: a three-tier application on each platform

A web tier behind a load balancer calls an application tier on TCP 8443, which calls a database on TCP 5432. Administrators reach hosts only through a bastion service.

  1. AWS: the web group allows 443 from the load balancer group; the application group allows 8443 from the web group; the database group allows 5432 from the application group. A shared network ACL on all three subnets denies 22 and 3389 from 0.0.0.0/0 at rule 100, then allows inbound and outbound to the VPC range and return traffic on 1024 to 65535. A return rule written as 32768 to 61000 would fail load balancer traffic.
  2. Azure: one NSG per subnet with application security groups for web, app and data; an explicit deny for VirtualNetwork to VirtualNetwork at priority 4000 so the 65000 default no longer flattens the network; allows for 8443 and 5432 between groups above it. A security admin Deny for 22, 3389 and 445 from the internet sits above all of it.
  3. Google Cloud: each tier runs as its own service account. VPC firewall rules allow 8443 to the app service account from the web service account and 5432 to the database service account from the app service account. An organisation-level hierarchical policy denies 22 and 3389 from 0.0.0.0/0 and ends with goto_next for everything else.

The review question is always the same: for each flow, list every layer it crosses in order, and confirm no lower layer can override a guardrail.

Implementation and rollback

  1. Inventory: export every security group, network ACL, NSG, security admin configuration, VPC firewall rule and firewall policy, with attachment points. Flag rules open to 0.0.0.0/0 or ::/0 and Azure subnets relying on the 65000 defaults.
  2. Observe: turn on flow logs for two to four weeks to learn real flows before tightening.
  3. Tighten the workload layer first: replace address-based rules with group, application security group or service account references, environment by environment.
  4. Add guardrails second: deploy the organisation-wide denies in a non-production scope, then production. Test with new connections, because tracked sessions will not show the effect.
  5. Verify reachability: check effective rules before and after each change (on Azure, effective security rules, IP flow verify and the Virtual Network Manager network verifier).
  6. Roll back: every change is a code commit; rollback is a redeploy of the previous version. Keep a pre-approved emergency change to widen an AWS ACL return range or remove a guardrail rule.

Detection and measurement

  • Log: every rule and policy change in the control-plane audit log, alerting on rules that open administration ports to the internet.
  • Metric: internet-open admin rules. Rules allowing 22, 3389 or 445 from 0.0.0.0/0 or ::/0 across all three layers. Target zero.
  • Metric: guardrail coverage. Percentage of networks covered by an organisation-level deny (ACL, security admin rule or hierarchical policy). Target 100%.
  • Metric: identity-based rules. Percentage of workload rules that reference groups, application security groups or service accounts instead of raw addresses.
  • Metric: unexplained denies. Weekly denied internal flows; spikes after a change point to missing return rules.

Common failure patterns

  • Removing a rule and calling it containment: tracked sessions continue on all three platforms.
  • Trusting the default "allow internal" rule: Azure's AllowVNetInBound and AllowVnetOutBound at 65000 permit everything inside the VirtualNetwork tag until you add your own deny.
  • Tags as security boundaries: Google Cloud network tags can be changed by anyone with edit rights on the instance.
  • One wide group among many: on AWS any allow in any attached group opens the interface; one legacy group with a broad rule undoes the rest.

Framework mapping

FrameworkReferenceHow the controls in this guide apply
NIST SP 800-53 Rev 5SC-7 Boundary Protection; SC-7(5) Deny by Default, Allow by Exception; AC-4 Information Flow Enforcement; CM-7 Least FunctionalityLayered stateful and stateless filtering, explicit denies above permissive defaults, only required ports
NIST CSF 2.0PR.IR-01Networks protected from unauthorised logical access
CIS Controls v8.1Control 12 Network Infrastructure Management; Control 13 Network Monitoring and DefenseRules as code, flow logging, alerts on rule changes
ISO/IEC 27001:2022 Annex AA.8.20 Networks security; A.8.22 Segregation of networksTier segmentation and central guardrails
MITRE ATT&CK v20T1686 Disable or Modify System FirewallDetect unauthorised rule and policy changes

Practitioner checklist

  • Every flow is documented with each layer it crosses, in the platform's evaluation order.
  • AWS network ACLs allow return traffic on 1024 to 65535 and number rules with gaps.
  • Azure subnets carry an explicit internal deny above the 65000 defaults, with NSGs on subnet or NIC, not both.
  • Google Cloud sensitive tiers are targeted by service account, not network tag, and the enforcement order setting is a deliberate choice.
  • Organisation-wide denies live in the layer application teams cannot override.
  • Incident playbooks cover tracked sessions and metadata access, which filters do not stop.
  • All rules are managed as code, and console changes in production raise alerts.

Standards and references

Related NHI Mgmt Group resources: Cloud Network Security Guide, Amazon VPC Security Guide, Azure Virtual Network Security Guide, Google Cloud VPC and Cloud NGFW Security Guide, VLAN Segmentation vs Firewall Zones.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org