One-liner#

iptables is an OS kernel-level firewall; Security Group is an AWS VPC-level virtual firewall. iptables runs inside the host; SG runs outside the host (at the hypervisor).


Where Each Operates#

[Internet]
    ↓
[AWS VPC]
    ↓
[Security Group]  ← Hypervisor (ENI) level — filters traffic before it reaches EC2
    ↓
[EC2 instance]
    ↓
[iptables]        ← OS kernel (netfilter) level — filters traffic inside EC2
    ↓
[Application]

SG filters traffic before it ever reaches the EC2 instance. iptables filters inside EC2 at the kernel level.


iptables is Linux-only#

iptables runs on top of the Linux kernel’s netfilter framework. Other operating systems have their own firewalls:

OSFirewallConfiguration
Linuxiptables / nftablesiptables, nft, or ufw (wrapper)
WindowsWindows Firewall (WFP)netsh advfirewall or GUI
macOSPF (Packet Filter)pfctl, /etc/pf.conf

iptables is Linux-only. Windows Firewall and macOS PF are conceptually similar (packet filtering) but are completely different implementations.

iptables configuration on Linux#

# View current rules
sudo iptables -L -n -v

# Rule files (varies by distro)
/etc/iptables/rules.v4          # Debian/Ubuntu (iptables-persistent)
/etc/sysconfig/iptables          # RHEL/CentOS

# Using ufw (Ubuntu default)
sudo ufw status
sudo ufw allow 443/tcp
# Internally creates iptables rules

# nftables (successor to iptables)
/etc/nftables.conf
sudo nft list ruleset

iptables vs nftables#

iptables is becoming legacy; nftables is its successor:

iptablesnftables
StatusLegacy (maintenance-only)Current standard
Kernelnetfilternetfilter (same framework)
PerformanceSlow with many rules (linear scan)Optimized (map/set support)
SyntaxSeparate commands per tableUnified syntax
K8skube-proxy defaultkube-proxy nftables mode

On recent Ubuntu/Debian, running iptables may internally use the nftables backend (iptables-nft).


Key Differences#

iptablesSecurity Group
Where it runsOS kernel (netfilter)AWS hypervisor (ENI)
Who manages itUser directlyAWS Console / API / Terraform
Default policyAllow (ACCEPT)Deny (DENY)
Rule typesBoth allow and denyAllow only (no DENY rules)
Stateful trackingStateful or stateless (your choice)Always stateful
Rule evaluationOrder matters (top to bottom)All evaluated (no order)
ScopeThe host itselfResources attached to the ENI

Stateful Tracking#

Both can be stateful, but they differ:

Security Group (always stateful)#

Inbound: allow 443
  → Client request arrives (443)
  → Response goes out (automatically allowed — no outbound rule needed)

SG is unconditionally stateful. If an inbound connection is allowed, the return traffic is automatically permitted without any outbound rule.

iptables (configurable)#

# Stateful (using conntrack)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Stateless (without conntrack)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 443 -j ACCEPT  # Response must be explicitly allowed

iptables can be stateful via the conntrack module, or run stateless when performance demands it.


Rule Evaluation#

iptables: first match wins#

iptables -A INPUT -s 10.0.0.5 -j DROP           # Rule 1: block this IP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT  # Rule 2: allow 443

A request from 10.0.0.5 to port 443 hits Rule 1 and is DROPped. Order matters.

Security Group: all rules evaluated#

Inbound:
  443 ← 0.0.0.0/0
  443 ← sg-ecs-app

All rules are evaluated; a packet is allowed if any rule matches. There is no ordering. Also, there are no DENY rules — to block a specific IP you need NACL, not SG.


DENY Rules#

ToolAllowDeny
iptablesYes (ACCEPT)Yes (DROP/REJECT)
Security GroupYesNo (DENY not available)
NACLYesYes

Want to block a specific IP with SG? You can’t. In AWS, IP blocking requires NACL (Network ACL) or WAF.

When you need to block:
  L3/L4 block → NACL (subnet level, stateless)
  L7 block    → WAF (HTTP level, path/header based)
  Host block  → iptables (OS level)

In Kubernetes#

Both are used in K8s environments:

[AWS VPC]
  Security Group → Network access control at EKS node/Pod level
      ↓
[K8s cluster]
  NetworkPolicy → Pod-to-pod communication control (implemented by CNI via iptables/eBPF)
      ↓
[Pod]
  iptables/nftables → Istio sidecar, kube-proxy service routing
  • kube-proxy: implements Service → Pod routing as iptables rules
  • Calico/Cilium: implements NetworkPolicy via iptables or eBPF
  • Istio: controls traffic via Envoy sidecar (iptables redirects traffic into the sidecar)

Security Group vs NACL#

Both are AWS firewalls but operate at different levels:

Security GroupNACL
ScopeENI (instance/Pod)Subnet
Stateful trackingStatefulStateless
Rule typesAllow onlyAllow + Deny
Rule evaluationAll rules (no order)In order (lowest number first)
Default policyDeny allAllow all (default NACL)
Use casePer-resource access controlSubnet-level IP blocking
[Internet]
    ↓
[NACL]            ← Filters at the subnet boundary (can block IPs)
    ↓
[Security Group]  ← Filters at the ENI level (allow rules only)
    ↓
[EC2 / Pod]

When to use NACL#

SG cannot block a specific IP (no DENY rules). Use NACL when IP blocking is needed:

NACL Inbound:
  Rule 10:  DENY  TCP 443  from 203.0.113.5/32   ← block malicious IP
  Rule 100: ALLOW TCP 443  from 0.0.0.0/0        ← allow everything else
  Rule *:   DENY  ALL      from 0.0.0.0/0        ← default deny

NACL is stateless, so outbound response rules are also required:

NACL Outbound:
  Rule 100: ALLOW TCP 1024-65535 from 0.0.0.0/0  ← response (ephemeral ports)

In practice#

SG alone is sufficient for most cases, and NACL is often left untouched. Use NACL when:

  • Blocking specific IPs or ranges (attacker IPs)
  • Restricting communication at the subnet level (compliance requirements)
  • DENY rules that cannot be expressed with SG

Summary#

SituationChoice
Access control between AWS resourcesSecurity Group
Block a specific IPNACL or WAF
Host-level firewalliptables
Pod-to-pod communication control in K8sNetworkPolicy (backed by iptables/eBPF)
On-premises server firewalliptables / nftables / ufw

In the cloud, SG is the first line of defense; iptables is used inside hosts or as an internal implementation detail in K8s. On-premises, iptables (or ufw) is the primary firewall.