VPC
02 / 03

Security Groups, NACLs & Flow Logs

AWS VPC: Security Groups, NACLs & Flow Logs

Security Groups

Security groups are stateful firewalls attached to EC2 instances, RDS, etc. Rules are evaluated as a whole — if any rule allows the traffic, it's permitted. Deny rules are not possible.

# Create security group
aws ec2 create-security-group   --group-name web-sg   --description "Web server security group"   --vpc-id vpc-0abc123

# Add inbound rules
aws ec2 authorize-security-group-ingress   --group-id sg-0abc123   --protocol tcp   --port 80   --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress   --group-id sg-0abc123   --protocol tcp   --port 443   --cidr 0.0.0.0/0

# Allow SSH from specific IP
aws ec2 authorize-security-group-ingress   --group-id sg-0abc123   --protocol tcp   --port 22   --cidr 203.0.113.0/32

# Reference another SG (allow app-sg to connect to db-sg on 5432)
aws ec2 authorize-security-group-ingress   --group-id sg-db123   --protocol tcp   --port 5432   --source-group sg-app123

# Describe rules
aws ec2 describe-security-group-rules --filter Name=group-id,Values=sg-0abc123

# Revoke rule
aws ec2 revoke-security-group-ingress   --group-id sg-0abc123   --protocol tcp   --port 22   --cidr 0.0.0.0/0

Network ACLs (NACLs)

NACLs are stateless subnet-level firewalls. Both inbound AND outbound rules must explicitly allow traffic. Rules are evaluated in order by rule number (lowest first).

Security Groups vs NACLs:
                     Security Group           NACL
  Level:             Instance (ENI)           Subnet
  State:             Stateful (return         Stateless (must allow
                     traffic auto-allowed)     return traffic too)
  Allow/Deny:        Allow only               Allow AND Deny
  Rule evaluation:   All rules together       In order (100, 200, ...)
  Default:           Deny all in, all out     Allow all in, all out

NACL use cases:
  - Block specific IP addresses (can't do this with SG)
  - Add extra defense-in-depth at subnet boundary
  - Emergency "shut off" — deny all ingress on subnet
# Add inbound deny rule (rule 50 evaluated before allow rules)
aws ec2 create-network-acl-entry   --network-acl-id acl-0abc123   --rule-number 50   --protocol tcp   --rule-action deny   --ingress   --cidr-block 192.168.1.0/24   --port-range From=0,To=65535

# Ephemeral ports must be allowed for return traffic (1024-65535)
aws ec2 create-network-acl-entry   --network-acl-id acl-0abc123   --rule-number 200   --protocol tcp   --rule-action allow   --egress   --cidr-block 0.0.0.0/0   --port-range From=1024,To=65535

VPC Flow Logs

Flow logs capture IP traffic information for network interfaces, subnets, or VPCs. Essential for security analysis and troubleshooting.

# Create flow log (to CloudWatch Logs)
aws ec2 create-flow-logs   --resource-type VPC   --resource-ids vpc-0abc123   --traffic-type ALL   --log-destination-type cloud-watch-logs   --log-destination arn:aws:logs:us-east-1:123456789:log-group:/vpc/flowlogs   --deliver-logs-permission-arn arn:aws:iam::123456789:role/FlowLogsRole

# Or to S3 (cheaper for long retention)
aws ec2 create-flow-logs   --resource-type VPC   --resource-ids vpc-0abc123   --traffic-type REJECT   --log-destination-type s3   --log-destination arn:aws:s3:::my-flow-logs-bucket/vpc/

# Flow log record format:
# version accountid interface-id srcaddr dstaddr srcport dstport protocol
# packets bytes windowstart windowend action flowdirection log-status

# Example: REJECT record
# 2 123456789012 eni-abc123 203.0.113.1 10.0.1.5 45678 22 6 1 40 ... REJECT INGRESS OK

# Query with CloudWatch Logs Insights
# fields @timestamp, srcAddr, dstAddr, dstPort, action
# | filter action = "REJECT"
# | stats count() by srcAddr
# | sort count desc

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free