Flow Logs
VPC Flow Logs, CloudWatch Logs Insights, the seven-layer connectivity checklist, and VPC Reachability Analyzer.
- This builds on The VPC Itself through Network Interfaces and IPs. Your VPC, subnets, route tables, IGW, and SGs must exist.
- In a new terminal session, run the resume script at the end of Network Interfaces and IPs.
- Read the callout before every step. Predict, run, verify.
Enable VPC Flow Logs
Goal
Enable flow logs for the entire VPC. Understand what they capture and what they don't. Know where to look first when traffic is mysteriously blocked.
Estimated time: 30 minutes
What flow logs capture (and don't)
What's happening here
VPC Flow Logs capture metadata about IP traffic at the ENI level, not the actual payload. Each record tells you: source IP, destination IP, source port, destination port, protocol, number of bytes, number of packets, start time, end time, and whether the traffic was ACCEPT or REJECT. They do not capture the HTTP body, headers, or any application-layer data.
Key things flow logs do NOT capture:
- Traffic to/from the instance metadata service (
169.254.169.254) - Traffic to/from the DNS resolver (
169.254.169.253) - DHCP traffic
- Windows license activation traffic
- Traffic between an instance and Amazon Time Sync Service
Flow logs have a delay: records appear in CloudWatch Logs or S3 typically within 5–15 minutes of the traffic occurring. They are not a real-time debugging tool. For real-time: use VPC Reachability Analyzer (Cross-Cutting Scenarios) or test with actual traffic.
| Field | Example | Meaning |
|---|---|---|
| version | 2 | Flow log version |
| account-id | 123456789012 | AWS account |
| interface-id | eni-abc123 | ENI that recorded the traffic |
| srcaddr | 10.0.11.5 | Source IP address |
| dstaddr | 10.0.1.10 | Destination IP address |
| srcport | 54321 | Source port |
| dstport | 443 | Destination port |
| protocol | 6 | 6 = TCP, 17 = UDP, 1 = ICMP |
| packets | 12 | Number of packets in the flow |
| bytes | 4096 | Total bytes in the flow |
| start | 1609459200 | Flow start Unix timestamp |
| end | 1609459260 | Flow end Unix timestamp |
| action | ACCEPT / REJECT | ACCEPT = allowed, REJECT = SG or NACL blocked |
| log-status | OK | OK, NODATA, SKIPDATA |
Reading `action`
REJECT means a security group or NACL blocked the packet.
ACCEPT means the packet passed SG and NACL checks, but the application could still refuse the connection (nothing listening, wrong port, TLS error, etc.).
Create an IAM role for flow logs
What's happening here
Flow logs need an IAM role that allows the VPC Flow Logs service to write records to CloudWatch Logs. The trust policy allows vpc-flow-logs.amazonaws.com to assume the role. The permissions policy allows creating log groups, log streams, and putting log events. Without this role, the flow log creation appears to succeed but no records are ever written, a silent failure.
# Create the IAM role
cat > flow-logs-trust.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "vpc-flow-logs.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
EOF
export FLOW_LOGS_ROLE=$(aws iam create-role \
--role-name networking-lab-flow-logs-role \
--assume-role-policy-document file://flow-logs-trust.json \
--query 'Role.Arn' --output text)
echo "Flow logs role ARN: $FLOW_LOGS_ROLE"
# Attach permissions
cat > flow-logs-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
],
"Resource": "*"
}]
}
EOF
aws iam put-role-policy \
--role-name networking-lab-flow-logs-role \
--policy-name flow-logs-policy \
--policy-document file://flow-logs-policy.json
echo "Permissions attached."Create the flow log
What's happening here
We create a flow log at the VPC level: this captures traffic on every ENI in the VPC. You can also scope flow logs to a specific subnet or a specific ENI for lower volume and targeted debugging. traffic-type ALL captures both accepted and rejected traffic. ACCEPT only misses rejected packets, REJECT only shows blocked traffic. For troubleshooting, you nearly always want ALL. The log group is created automatically if it doesn't exist.