A
Arun's Blog
← Back to all posts

VPC Flow Logs via Terraform

VPCTerraformSecurityMonitoring
TL;DR

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)
Pro Tip

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

VPC Flow Logs 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
}
Note

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
Important

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.