VPC Flow Logs via Terraform
Enable VPC Flow Logs using Terraform to capture network traffic data for security analysis and troubleshooting. Create a CloudWatch Log Group, IAM role with appropriate policies, and the Flow Log resource. Logs include source/destination IPs, ports, protocol, and ACCEPT/REJECT actions.
Introduction
Network flow logs are gathered, archived, and analyzed by numerous organizations. They utilize this data to diagnose connectivity and security problems and check that network access rules are functioning as intended.
Amazon Virtual Private Cloud (VPC) allows us to better support this crucial part of network monitoring through VPC Flow Logs. Relevant network traffic will be logged to CloudWatch Logs once enabled for a specific VPC, subnet, or Elastic Network Interface (ENI). These logs can be sent to storage and analysis by your own applications or third-party tools.
What Flow Logs Capture
- Permitted and prohibited traffic (based on security group and NACL rules)
- Packet and byte counts
- Source and destination IP addresses
- Source and destination ports
- IANA protocol number
- Timestamp of the flow
- Action (ACCEPT or REJECT)
Set up CloudWatch metrics and alarms on your flow logs to detect suspicious traffic patterns or unexpected REJECT actions that might indicate security issues or misconfigurations.
Architecture

Terraform Configuration
VPC Reference
In this example, we'll use the default VPC. You can modify this to reference any VPC in your environment.
CloudWatch Log Group
Create a log group with a descriptive name (including the VPC ID as suffix) and a retention period:
resource "aws_cloudwatch_log_group" "vpc_flow_log" {
name = "vpcflowlogGroup-${data.aws_vpc.default.id}"
retention_in_days = 30 # Configurable: 1 day to 10 years, or never expire
}
Retention can be set from 1 day to 10 years (3653 days), or set to 0 for indefinite retention. Choose based on your compliance and cost requirements.
IAM Role
Create an IAM role that allows the VPC Flow Logs service to assume it via STS:
resource "aws_iam_role" "vpc_flow_log_role" {
name = "vpc-flow-log-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}]
})
}
IAM Policy
Attach a policy granting permissions to write to CloudWatch Logs:
resource "aws_iam_role_policy" "vpc_flow_log_policy" {
name = "vpc-flow-log-policy"
role = aws_iam_role.vpc_flow_log_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Effect = "Allow"
Resource = "*"
}]
})
}
VPC Flow Log
Create the Flow Log connecting all components:
resource "aws_flow_log" "vpc_flow_log" {
iam_role_arn = aws_iam_role.vpc_flow_log_role.arn
log_destination = aws_cloudwatch_log_group.vpc_flow_log.arn
traffic_type = "ALL" # Options: ACCEPT, REJECT, or ALL
vpc_id = data.aws_vpc.default.id
}
Traffic Type Options
- ACCEPT - Only accepted traffic (passed security groups and NACLs)
- REJECT - Only rejected traffic (blocked by security groups or NACLs)
- ALL - Both accepted and rejected traffic
Capturing ALL traffic generates more log data and higher costs. For cost optimization, consider capturing only REJECT traffic for security monitoring, or enable on specific subnets rather than the entire VPC.
Timing and Limitations
Flows are captured, analyzed, and stored within roughly 10-minute capture windows. The log group will be generated and first flow records will appear approximately 15 minutes after creating the Flow Log.
Traffic NOT Captured in Flow Logs
- Traffic to Amazon DNS servers (including privately hosted zones)
- Windows license activation activity for Amazon-provided licenses
- Instance metadata queries (169.254.169.254)
- DHCP requests and responses
- Traffic to the reserved IP address for the default VPC router
Troubleshooting
- No logs appearing - Wait at least 15 minutes after creation. Verify the IAM role has correct permissions and trust policy.
- "Access Denied" errors - Check the IAM policy includes all required CloudWatch Logs actions. Verify the trust policy allows vpc-flow-logs.amazonaws.com.
- Missing expected traffic - Remember that certain traffic types are not logged (see limitations above). Verify you're capturing the right traffic type (ACCEPT/REJECT/ALL).
- High costs - Flow logs can generate significant data. Consider reducing scope to specific subnets or ENIs, or filtering to REJECT only.
- Terraform destroy fails - Ensure no log streams exist with data before destroying the log group, or use
force_destroy = true.