VPC Flow Logs Analysis for Security
Implement comprehensive network traffic analysis using VPC Flow Logs for threat detection and security investigation.
VPC Flow Logs capture network traffic information for security analysis, troubleshooting, and compliance. This guide covers advanced analysis techniques for threat detection.
Configuring Flow Logs
Enhanced Format
VPCFlowLog:
Type: AWS::EC2::FlowLog
Properties:
ResourceType: VPC
ResourceId: !Ref VPC
TrafficType: ALL
LogDestinationType: s3
LogDestination: !Sub arn:aws:s3:::${FlowLogBucket}
LogFormat: >-
${version} ${account-id} ${interface-id} ${srcaddr}
${dstaddr} ${srcport} ${dstport} ${protocol} ${packets}
${bytes} ${start} ${end} ${action} ${log-status}
${vpc-id} ${subnet-id} ${instance-id} ${tcp-flags}
${type} ${pkt-srcaddr} ${pkt-dstaddr} ${region}
${az-id} ${sublocation-type} ${sublocation-id}
MaxAggregationInterval: 60
DestinationOptions:
FileFormat: parquet
HiveCompatiblePartitions: true
PerHourPartition: true
Athena Analysis
Create Table
CREATE EXTERNAL TABLE vpc_flow_logs (
version int,
account_id string,
interface_id string,
srcaddr string,
dstaddr string,
srcport int,
dstport int,
protocol int,
packets bigint,
bytes bigint,
start_time bigint,
end_time bigint,
action string,
log_status string,
vpc_id string,
subnet_id string,
instance_id string,
tcp_flags int,
type string,
pkt_srcaddr string,
pkt_dstaddr string,
region string,
az_id string,
sublocation_type string,
sublocation_id string
)
PARTITIONED BY (
date_partition string,
hour_partition string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS PARQUET
LOCATION 's3://flow-logs-bucket/AWSLogs/123456789012/vpcflowlogs/'
TBLPROPERTIES (
'projection.enabled' = 'true',
'projection.date_partition.type' = 'date',
'projection.date_partition.format' = 'yyyy/MM/dd',
'projection.date_partition.range' = '2024/01/01,NOW',
'projection.hour_partition.type' = 'integer',
'projection.hour_partition.range' = '0,23',
'storage.location.template' =
's3://flow-logs-bucket/AWSLogs/123456789012/vpcflowlogs/${date_partition}/${hour_partition}'
);
Security Queries
Detect Port Scans
SELECT
srcaddr,
COUNT(DISTINCT dstport) as unique_ports,
COUNT(*) as connection_attempts,
array_agg(DISTINCT dstport) as scanned_ports
FROM vpc_flow_logs
WHERE
action = 'REJECT'
AND date_partition >= date_format(current_date - interval '1' day, '%Y/%m/%d')
GROUP BY srcaddr
HAVING COUNT(DISTINCT dstport) > 100
ORDER BY unique_ports DESC
LIMIT 50;
Unusual Outbound Traffic
SELECT
instance_id,
dstaddr,
dstport,
SUM(bytes) as total_bytes,
SUM(packets) as total_packets,
COUNT(*) as flow_count
FROM vpc_flow_logs
WHERE
action = 'ACCEPT'
AND type = 'IPv4'
AND srcaddr LIKE '10.%' -- Internal IPs
AND dstaddr NOT LIKE '10.%' -- External destinations
AND dstport NOT IN (443, 80, 53) -- Unusual ports
AND date_partition >= date_format(current_date - interval '1' day, '%Y/%m/%d')
GROUP BY instance_id, dstaddr, dstport
HAVING SUM(bytes) > 1000000000 -- More than 1GB
ORDER BY total_bytes DESC;
Detect Lateral Movement
WITH internal_connections AS (
SELECT
srcaddr,
dstaddr,
dstport,
SUM(packets) as total_packets
FROM vpc_flow_logs
WHERE
action = 'ACCEPT'
AND srcaddr LIKE '10.%'
AND dstaddr LIKE '10.%'
AND dstport IN (22, 3389, 5985, 5986) -- SSH, RDP, WinRM
AND date_partition >= date_format(current_date - interval '1' day, '%Y/%m/%d')
GROUP BY srcaddr, dstaddr, dstport
)
SELECT
srcaddr,
COUNT(DISTINCT dstaddr) as unique_destinations,
array_agg(DISTINCT dstaddr) as target_ips,
SUM(total_packets) as total_packets
FROM internal_connections
GROUP BY srcaddr
HAVING COUNT(DISTINCT dstaddr) > 10
ORDER BY unique_destinations DESC;
Real-Time Analysis
CloudWatch Logs Insights
fields @timestamp, srcAddr, dstAddr, dstPort, action
| filter action = "REJECT"
| stats count(*) as rejected_count by srcAddr
| sort rejected_count desc
| limit 20
Lambda for Alerts
import boto3
import json
def analyze_flow_logs(event, context):
suspicious_patterns = []
for record in event['Records']:
log_data = json.loads(record['body'])
# Check for suspicious patterns
if is_port_scan(log_data):
suspicious_patterns.append({
'type': 'PORT_SCAN',
'source': log_data['srcaddr'],
'details': log_data
})
if is_data_exfiltration(log_data):
suspicious_patterns.append({
'type': 'DATA_EXFILTRATION',
'source': log_data['srcaddr'],
'destination': log_data['dstaddr'],
'bytes': log_data['bytes']
})
if suspicious_patterns:
send_security_alert(suspicious_patterns)
def is_port_scan(log):
# Implement port scan detection logic
return log.get('action') == 'REJECT' and log.get('packets', 0) < 3
def is_data_exfiltration(log):
# Implement data exfiltration detection
return log.get('bytes', 0) > 100000000 and log.get('dstport') not in [443, 80]
Working with Warqline
We are a cloud engineering consultancy and an official AWS and Google Cloud partner. If you are running this in production and want a second pair of eyes, we scope work in a free 45-minute technical call: you describe what you are running and what worries you, and we tell you what we would look at first.
Conclusion
VPC Flow Logs provide essential visibility into network traffic. Combine Athena for historical analysis, CloudWatch for real-time monitoring, and custom Lambda functions for automated threat detection.