Ensure VPC Flow Logging is Enabled in all VPCs
Overview
This check verifies that VPC Flow Logs are enabled for your Virtual Private Clouds. Flow logs capture information about IP traffic going to and from network interfaces in your VPC, helping you monitor network activity and troubleshoot connectivity issues.
Risk
Without VPC Flow Logs, you lose visibility into network traffic patterns. This creates security blind spots where:
- Unauthorized access attempts to your resources may go undetected
- Data exfiltration through network channels cannot be identified
- Security incident investigations lack critical network evidence
- Anomalous traffic patterns that indicate compromise are missed
- Compliance audits may fail due to missing network monitoring
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to modify VPC settings and create IAM roles
- An existing VPC (or permission to create one)
- A destination for flow logs (CloudWatch Logs, S3 bucket, or Kinesis Data Firehose)
Required IAM permissions (for administrators)
Your IAM user or role needs these permissions:
ec2:CreateFlowLogsec2:DescribeFlowLogsec2:DescribeVpcslogs:CreateLogGrouplogs:DescribeLogGroupsiam:CreateRoleiam:PutRolePolicyiam:PassRole
AWS Console Method
-
Open the VPC Console
- Go to VPC Console in us-east-1
-
Select your VPC
- Click Your VPCs in the left sidebar
- Select the VPC you want to enable flow logs for
-
Create a flow log
- Click the Flow logs tab at the bottom of the page
- Click Create flow log
-
Configure the flow log
- Name: Enter a descriptive name (e.g.,
my-vpc-flow-logs) - Filter: Select the traffic to capture:
- All - captures accepted and rejected traffic (recommended for security)
- Accept - captures only accepted traffic
- Reject - captures only rejected traffic (minimum for security compliance)
- Maximum aggregation interval: Choose 1 minute for near real-time analysis or 10 minutes for lower costs
- Destination: Choose one of:
- Send to CloudWatch Logs (easiest for alerting and searching)
- Send to Amazon S3 (best for long-term storage and cost)
- Send to Kinesis Data Firehose (for streaming analytics)
- Name: Enter a descriptive name (e.g.,
-
Set up the destination (CloudWatch Logs)
- For Destination log group, either select an existing log group or create a new one
- For IAM role, select Create new role and give it a name, or select an existing role with the required permissions
-
Create the flow log
- Review your settings
- Click Create flow log
AWS CLI (optional)
Option 1: Send flow logs to CloudWatch Logs
Step 1: Create a CloudWatch Logs log group
aws logs create-log-group \
--log-group-name /aws/vpc/flowlogs/<your-vpc-id> \
--region us-east-1
Step 2: Create an IAM role for flow logs
Create a trust policy file:
cat > /tmp/flow-logs-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "vpc-flow-logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
Create the role:
aws iam create-role \
--role-name VPCFlowLogsRole \
--assume-role-policy-document file:///tmp/flow-logs-trust-policy.json
Step 3: Attach permissions to the role
Create a permissions policy (replace <your-account-id> and <your-vpc-id>):
cat > /tmp/flow-logs-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
],
"Resource": "arn:aws:logs:us-east-1:<your-account-id>:log-group:/aws/vpc/flowlogs/<your-vpc-id>:*"
}
]
}
EOF
Attach the policy:
aws iam put-role-policy \
--role-name VPCFlowLogsRole \
--policy-name VPCFlowLogsPolicy \
--policy-document file:///tmp/flow-logs-policy.json
Step 4: Create the flow log
Replace <your-vpc-id> and <your-account-id>:
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids <your-vpc-id> \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name /aws/vpc/flowlogs/<your-vpc-id> \
--deliver-logs-permission-arn arn:aws:iam::<your-account-id>:role/VPCFlowLogsRole \
--region us-east-1
Option 2: Send flow logs to S3
This option does not require an IAM role (S3 permissions are handled automatically):
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids <your-vpc-id> \
--traffic-type ALL \
--log-destination-type s3 \
--log-destination arn:aws:s3:::<your-bucket-name>/vpc-flow-logs/ \
--region us-east-1
CloudFormation (optional)
This template creates a flow log with CloudWatch Logs as the destination:
AWSTemplateFormatVersion: '2010-09-09'
Description: Enable VPC Flow Logs with CloudWatch Logs destination
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC ID to enable flow logs for
RetentionDays:
Type: Number
Description: Number of days to retain flow logs
Default: 30
AllowedValues:
- 1
- 3
- 5
- 7
- 14
- 30
- 60
- 90
- 120
- 150
- 180
- 365
- 400
- 545
- 731
- 1827
- 3653
TrafficType:
Type: String
Description: Type of traffic to log
Default: ALL
AllowedValues:
- ACCEPT
- REJECT
- ALL
Resources:
FlowLogsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/vpc/flowlogs/${VpcId}
RetentionInDays: !Ref RetentionDays
FlowLogsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub VPCFlowLogs-${VpcId}
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: vpc-flow-logs.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: VPCFlowLogsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogGroups
- logs:DescribeLogStreams
Resource: !GetAtt FlowLogsLogGroup.Arn
VPCFlowLog:
Type: AWS::EC2::FlowLog
Properties:
ResourceId: !Ref VpcId
ResourceType: VPC
TrafficType: !Ref TrafficType
LogDestinationType: cloud-watch-logs
LogGroupName: !Ref FlowLogsLogGroup
DeliverLogsPermissionArn: !GetAtt FlowLogsRole.Arn
Tags:
- Key: Name
Value: !Sub flowlog-${VpcId}
Outputs:
FlowLogId:
Description: VPC Flow Log ID
Value: !Ref VPCFlowLog
LogGroupArn:
Description: CloudWatch Logs log group ARN
Value: !GetAtt FlowLogsLogGroup.Arn
Deploy with:
aws cloudformation deploy \
--template-file vpc-flow-logs.yaml \
--stack-name vpc-flow-logs \
--parameter-overrides VpcId=vpc-0123456789abcdef0 \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1
Terraform (optional)
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variable "vpc_id" {
description = "VPC ID to enable flow logs for"
type = string
}
variable "traffic_type" {
description = "Type of traffic to log (ACCEPT, REJECT, ALL)"
type = string
default = "ALL"
}
variable "retention_days" {
description = "Number of days to retain flow logs in CloudWatch"
type = number
default = 30
}
# CloudWatch Log Group for VPC Flow Logs
resource "aws_cloudwatch_log_group" "flow_logs" {
name = "/aws/vpc/flowlogs/${var.vpc_id}"
retention_in_days = var.retention_days
}
# IAM Role for VPC Flow Logs
resource "aws_iam_role" "flow_logs" {
name = "VPCFlowLogs-${var.vpc_id}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
# IAM Role Policy for VPC Flow Logs
resource "aws_iam_role_policy" "flow_logs" {
name = "VPCFlowLogsPolicy"
role = aws_iam_role.flow_logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Resource = "${aws_cloudwatch_log_group.flow_logs.arn}:*"
}
]
})
}
# VPC Flow Log
resource "aws_flow_log" "main" {
vpc_id = var.vpc_id
traffic_type = var.traffic_type
log_destination_type = "cloud-watch-logs"
log_destination = aws_cloudwatch_log_group.flow_logs.arn
iam_role_arn = aws_iam_role.flow_logs.arn
tags = {
Name = "flowlog-${var.vpc_id}"
}
}
output "flow_log_id" {
description = "VPC Flow Log ID"
value = aws_flow_log.main.id
}
output "log_group_arn" {
description = "CloudWatch Logs log group ARN"
value = aws_cloudwatch_log_group.flow_logs.arn
}
Deploy with:
terraform init
terraform plan -var="vpc_id=vpc-0123456789abcdef0"
terraform apply -var="vpc_id=vpc-0123456789abcdef0"
Verification
After enabling flow logs, verify they are working:
-
In the AWS Console:
- Go to VPC > Your VPCs and select your VPC
- Click the Flow logs tab
- Verify a flow log exists with Status: Active
- Wait 5-10 minutes, then check your destination (CloudWatch Logs or S3) for data
-
Generate test traffic:
- Try to connect to an EC2 instance or make a request through the VPC
- Check the flow log destination for new entries
CLI verification commands
List flow logs for a VPC:
aws ec2 describe-flow-logs \
--filter "Name=resource-id,Values=<your-vpc-id>" \
--region us-east-1
Check for active flow logs:
aws ec2 describe-flow-logs \
--filter "Name=resource-id,Values=<your-vpc-id>" \
--query 'FlowLogs[*].{ID:FlowLogId,Status:FlowLogStatus,Destination:LogDestination,TrafficType:TrafficType}' \
--region us-east-1
Expected output shows FlowLogStatus: ACTIVE.
View recent flow log entries in CloudWatch (replace log group name):
aws logs filter-log-events \
--log-group-name /aws/vpc/flowlogs/<your-vpc-id> \
--limit 10 \
--region us-east-1
Additional Resources
- AWS Documentation: VPC Flow Logs
- AWS Documentation: Flow Log Records
- AWS Documentation: Publishing Flow Logs to CloudWatch Logs
- AWS Documentation: Publishing Flow Logs to Amazon S3
- AWS Blog: Querying VPC Flow Logs with Amazon Athena
Notes
- Data collection timing: Flow logs may take 5-10 minutes to begin capturing data after creation.
- Traffic types: For security compliance, at minimum enable logging for REJECT traffic. For full visibility, use ALL.
- Costs: Flow logs incur charges for data ingestion and storage. CloudWatch Logs charges per GB ingested; S3 charges for storage and requests. Set retention policies to manage costs.
- Aggregation interval: Choose 1 minute for faster incident response or 10 minutes for lower costs (default).
- S3 vs CloudWatch: Use S3 for long-term archival and cost-effective storage. Use CloudWatch Logs for real-time alerting and log analysis with CloudWatch Logs Insights.
- Existing flow logs: You can have multiple flow logs per VPC with different destinations or traffic filters.
- Cross-account delivery: Flow logs can be delivered to S3 buckets in different accounts with proper bucket policies.
- Default VPCs: Remember to enable flow logs on default VPCs in all regions, not just custom VPCs.