A security group guards an instance. A network ACL guards a whole subnet, and traffic must pass both.
| Network ACL | Security group | |
|---|---|---|
| guards | a subnet | an instance |
| remembers connections | no: stateless | yes: stateful |
| rules | numbered, allow and deny | allow only |
| order | lowest number first; first match wins | all rules together |
Every subnet uses one ACL. The VPC's default ACL allows everything, which is why it has not mattered so far.
Stateless
A security group lets a reply out because it remembers the request. A network ACL remembers nothing: the reply is a new packet that needs its own rule. Replies go back to a temporary port the caller picked, anywhere in 1024-65535, so a subnet that serves port 80 needs an inbound rule for 80 and an outbound rule for 1024-65535.
Reading one
$SUBNET holds the subnet's id, found by its Name as in lesson 5.
ACL=$(aws ec2 describe-network-acls --filters Name=association.subnet-id,Values=$SUBNET --query "NetworkAcls[0].NetworkAclId" --output text)aws ec2 describe-network-acls --network-acl-ids $ACL --query "NetworkAcls[0].Entries[].[RuleNumber,Egress,RuleAction,PortRange.From,PortRange.To]" --output tableEgress is False for inbound rules and True for outbound ones. Rule 32767 is the catch-all deny at the end of every ACL.
Changing one
aws ec2 create-network-acl-entry --network-acl-id $ACL --egress --rule-number 100 --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow--ingress or --egress picks the direction. A rule is removed by its number and direction:
aws ec2 delete-network-acl-entry --network-acl-id $ACL --ingress --rule-number 90