AWS VPC Flow Logs ile Ağ İzleme ve Trafik Analizi
AWS ortamında çalışıyorsanız, er ya da geç ağ trafiğinizin neye benzediğini anlamaya çalışacaksınız. Bir EC2 instance’ı neden o kadar çok ağ trafiği üretiyor? Hangi IP adresleri güvenlik grubu kurallarınıza takılıyor? Bu sorulara cevap verebilmenin en sağlam yolu VPC Flow Logs’u aktif hale getirmek ve doğru şekilde kullanmaktır. Bu yazıda VPC Flow Logs’u sıfırdan nasıl kuracağınızı, logları nasıl analiz edeceğinizi ve gerçek dünya senaryolarında nasıl kullanacağınızı detaylıca ele alacağız.
VPC Flow Logs Nedir ve Ne İşe Yarar?
VPC Flow Logs, VPC’nizdeki ağ arayüzlerinden geçen IP trafiği hakkında bilgi yakalamanızı sağlayan bir AWS özelliğidir. Bu loglar CloudWatch Logs veya S3’e yazılabilir. Önemli bir nokta şu: Flow Logs gerçek paket içeriklerini değil, bağlantı metadata’sını yakalar. Yani hangi IP hangi porta bağlandı, kaç byte gitti, kabul edildi mi reddedildi mi gibi bilgileri görebilirsiniz.
VPC Flow Logs’un temel kullanım senaryoları şunlardır:
- Güvenlik analizi: Kötü niyetli trafik örüntülerini tespit etmek
- Troubleshooting: Neden bağlantı kurulamıyor sorusuna cevap bulmak
- Uyumluluk: Ağ erişim loglarını saklamak gereken düzenlemeler için kanıt üretmek
- Maliyet optimizasyonu: Hangi kaynakların ne kadar veri transferi yaptığını anlamak
- Kapasite planlaması: Trafik trendlerini izlemek
Flow Log Kayıt Formatı
Bir flow log kaydı şu alanlardan oluşur (varsayılan format):
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status
Örnek bir kayıt:
2 123456789012 eni-0a1b2c3d4e5f 10.0.1.100 10.0.2.200 43210 443 6 10 4500 1620000000 1620000060 ACCEPT OK
2 123456789012 eni-0a1b2c3d4e5f 185.220.101.45 10.0.1.100 0 22 6 1 40 1620000100 1620000160 REJECT OK
İkinci kayıt bizim için çok anlamlı: 185.220.101.45 adresinden 22 numaralı porta gelen bağlantı reddedilmiş. Bu klasik bir SSH brute-force girişimi işareti olabilir.
Özelleştirilmiş format kullanmak istediğinizde ek alanlar ekleyebilirsiniz:
- vpc-id: Hangi VPC’den geldiği
- subnet-id: Subnet bilgisi
- instance-id: EC2 instance ID’si
- tcp-flags: TCP bayrakları (SYN, ACK, FIN, RST)
- type: IPv4 mü IPv6 mi
- pkt-srcaddr: Paket kaynak adresi (NAT durumlarında faydalı)
- pkt-dstaddr: Paket hedef adresi
- traffic-path: Trafiğin hangi yoldan geçtiği
VPC Flow Logs Kurulumu
AWS CLI ile Kurulum
Önce bir CloudWatch Log Group oluşturalım:
# Log Group oluştur
aws logs create-log-group
--log-group-name /vpc/flowlogs
--region eu-west-1
# Retention policy ayarla (90 gün)
aws logs put-retention-policy
--log-group-name /vpc/flowlogs
--retention-in-days 90
--region eu-west-1
Flow Logs için gerekli IAM rolünü oluşturmamız gerekiyor. Önce trust policy dosyasını hazırlayalım:
cat > flowlogs-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "vpc-flow-logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# IAM rolü oluştur
aws iam create-role
--role-name VPCFlowLogsRole
--assume-role-policy-document file://flowlogs-trust-policy.json
# Gerekli izinleri ekle
cat > flowlogs-permissions.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 VPCFlowLogsRole
--policy-name VPCFlowLogsPolicy
--policy-document file://flowlogs-permissions.json
Şimdi VPC ID’mizi alıp flow logs’u aktif hale getirelim:
# VPC ID'nizi alın
VPC_ID=$(aws ec2 describe-vpcs
--filters "Name=tag:Name,Values=production-vpc"
--query 'Vpcs[0].VpcId'
--output text
--region eu-west-1)
echo "VPC ID: $VPC_ID"
# IAM Role ARN'ini al
ROLE_ARN=$(aws iam get-role
--role-name VPCFlowLogsRole
--query 'Role.Arn'
--output text)
# Flow Logs'u aktif et
aws ec2 create-flow-logs
--resource-type VPC
--resource-ids $VPC_ID
--traffic-type ALL
--log-destination-type cloud-watch-logs
--log-group-name /vpc/flowlogs
--deliver-logs-permission-arn $ROLE_ARN
--log-format '${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}'
--region eu-west-1
S3’e Log Gönderme
CloudWatch yerine S3’e göndermek daha maliyet etkin olabilir, özellikle uzun süreli saklama için:
# S3 bucket oluştur
aws s3api create-bucket
--bucket my-vpc-flowlogs-bucket
--region eu-west-1
--create-bucket-configuration LocationConstraint=eu-west-1
# Bucket versioning aktif et
aws s3api put-bucket-versioning
--bucket my-vpc-flowlogs-bucket
--versioning-configuration Status=Enabled
# Flow logs'u S3'e yönlendir
aws ec2 create-flow-logs
--resource-type VPC
--resource-ids $VPC_ID
--traffic-type ALL
--log-destination-type s3
--log-destination "arn:aws:s3:::my-vpc-flowlogs-bucket/flowlogs/"
--log-format '${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}'
--region eu-west-1
CloudWatch Logs Insights ile Analiz
Flow loglarınız CloudWatch’ta birikmeye başladıktan sonra CloudWatch Logs Insights ile güçlü sorgular çalıştırabilirsiniz.
En Çok Trafik Üreten IP Adresleri
# Bu sorguyu CloudWatch Logs Insights konsolunda çalıştırın
# veya AWS CLI ile:
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '1 hour ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, bytes, action
| filter action = "ACCEPT"
| stats sum(bytes) as totalBytes by srcaddr
| sort totalBytes desc
| limit 20
'
--region eu-west-1
Reddedilen Bağlantıları Analiz Etmek
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '24 hours ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, dstport, protocol, action
| filter action = "REJECT"
| stats count(*) as rejectedCount by srcaddr, dstaddr, dstport
| sort rejectedCount desc
| limit 50
'
--region eu-west-1
Belirli Bir Instance’ın Trafiğini İzlemek
Diyelim ki bir EC2 instance’ının neden bu kadar fazla outbound trafik ürettiğini anlamaya çalışıyorsunuz:
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '6 hours ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, dstport, bytes, action
| filter instance-id = "i-0a1b2c3d4e5f67890"
| filter srcaddr = "10.0.1.100"
| stats sum(bytes) as totalBytes, count(*) as connectionCount by dstaddr, dstport
| sort totalBytes desc
| limit 30
'
--region eu-west-1
Gerçek Dünya Senaryoları
Senaryo 1: SSH Brute Force Tespiti
Gece sabahı bir alarm geliyor: Bir EC2 instance’ınıza yönelik anormal trafik var. Flow logs’u sorguladığınızda şunu görüyorsunuz:
# Belirli bir hedefe yönelik yoğun SSH denemelerini tespit et
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '2 hours ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, dstport, action
| filter dstport = 22
| filter action = "REJECT"
| stats count(*) as attemptCount by srcaddr
| sort attemptCount desc
| limit 10
'
--region eu-west-1
Bu sorgu size hangi kaynak IP’lerinden en fazla SSH deneme geldiğini gösterir. Eğer tek bir IP’den yüzlerce deneme görüyorsanız, bu klasik bir brute force saldırısıdır. Hemen o IP’yi Security Group’tan engelleyebilirsiniz:
# Kötü niyetli IP'yi Security Group'tan engelle
aws ec2 authorize-security-group-ingress
--group-id sg-0a1b2c3d4e5f
--protocol tcp
--port 22
--cidr 0.0.0.0/0
--region eu-west-1
# Daha doğrusu: SSH'ı sadece güvenilen IP'lere aç
# ve genel erişimi kaldır
aws ec2 revoke-security-group-ingress
--group-id sg-0a1b2c3d4e5f
--protocol tcp
--port 22
--cidr 0.0.0.0/0
--region eu-west-1
Senaryo 2: Data Exfiltration Şüphesi
Bir instance’dan beklenmedik büyük miktarda veri çıkışı olduğunu düşünüyorsunuz:
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '48 hours ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, dstport, bytes, packets
| filter srcaddr = "10.0.1.55"
| filter dstaddr not like "10."
| filter dstaddr not like "172."
| filter dstaddr not like "192.168."
| stats sum(bytes) as totalBytes by dstaddr, dstport
| sort totalBytes desc
| limit 20
'
--region eu-west-1
Bu sorgu iç ağ adresleri hariç dış adreslere giden trafiği listeler. Eğer normalde iletişim kurmaması gereken bir IP adresine büyük veri gönderiliyorsa, bunu hemen fark edersiniz.
Senaryo 3: Port Tarama Tespiti
aws logs start-query
--log-group-name /vpc/flowlogs
--start-time $(date -d '1 hour ago' +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, srcaddr, dstaddr, dstport, action
| filter action = "REJECT"
| stats count_distinct(dstport) as uniquePorts, count(*) as totalAttempts by srcaddr, dstaddr
| filter uniquePorts > 20
| sort uniquePorts desc
'
--region eu-west-1
Tek bir kaynak IP’den 20’den fazla farklı porta erişim denemesi yapılıyorsa bu büyük ihtimalle bir port taramasıdır.
Terraform ile Flow Logs Otomasyonu
Gerçek ortamlarda her şeyi elle kurmak yerine Infrastructure as Code kullanmak gerekir. İşte Terraform ile tam kurulum:
# main.tf dosyası oluştur ve şu içeriği ekle:
cat > flowlogs.tf << 'TERRAFORM'
resource "aws_cloudwatch_log_group" "vpc_flow_logs" {
name = "/vpc/flowlogs/${var.environment}"
retention_in_days = 90
tags = {
Environment = var.environment
Purpose = "VPC Flow Logs"
}
}
resource "aws_iam_role" "flow_logs" {
name = "vpc-flow-logs-role-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy" "flow_logs" {
name = "vpc-flow-logs-policy"
role = aws_iam_role.flow_logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Resource = "*"
}
]
})
}
resource "aws_flow_log" "vpc_flow_log" {
iam_role_arn = aws_iam_role.flow_logs.arn
log_destination = aws_cloudwatch_log_group.vpc_flow_logs.arn
traffic_type = "ALL"
vpc_id = var.vpc_id
log_format = "$${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}"
tags = {
Environment = var.environment
Name = "vpc-flow-logs-${var.environment}"
}
}
TERRAFORM
# Terraform'u başlat ve uygula
terraform init
terraform plan -var="environment=production" -var="vpc_id=vpc-0a1b2c3d"
terraform apply -var="environment=production" -var="vpc_id=vpc-0a1b2c3d"
Athena ile Büyük Ölçekli Analiz
S3’e yazan flow logs için CloudWatch Logs Insights yetersiz kalabilir. Bu durumda Amazon Athena kullanmak çok daha verimlidir:
# Athena'da flow logs tablosu oluştur
aws athena start-query-execution
--query-string "
CREATE EXTERNAL TABLE IF NOT EXISTS vpc_flow_logs (
version int,
account_id string,
interface_id string,
srcaddr string,
dstaddr string,
srcport int,
dstport int,
protocol bigint,
packets bigint,
bytes bigint,
start bigint,
end bigint,
action string,
log_status string,
vpc_id string,
subnet_id string,
instance_id string,
tcp_flags int
)
PARTITIONED BY (year string, month string, day string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ' '
LOCATION 's3://my-vpc-flowlogs-bucket/flowlogs/AWSLogs/123456789012/vpcflowlogs/eu-west-1/'
TBLPROPERTIES ('skip.header.line.count'='1');
"
--query-execution-context Database=default
--result-configuration OutputLocation=s3://my-athena-results/
--region eu-west-1
# Ardından en büyük veri transferlerini sorgula
aws athena start-query-execution
--query-string "
SELECT srcaddr, dstaddr, sum(bytes) as total_bytes, count(*) as flow_count
FROM vpc_flow_logs
WHERE year='2024' AND month='01' AND action='ACCEPT'
GROUP BY srcaddr, dstaddr
ORDER BY total_bytes DESC
LIMIT 50;
"
--query-execution-context Database=default
--result-configuration OutputLocation=s3://my-athena-results/
--region eu-west-1
CloudWatch Metric Filter ve Alarm Kurulumu
Kritik durumlar için otomatik alarm kurabilirsiniz. Örneğin reddedilen bağlantılar belirli bir eşiği aştığında e-posta alın:
# Reddedilen bağlantılar için metric filter oluştur
aws logs put-metric-filter
--log-group-name /vpc/flowlogs
--filter-name RejectedConnections
--filter-pattern '[version, account_id, interface_id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action="REJECT", log_status]'
--metric-transformations
metricName=RejectedConnectionCount,metricNamespace=VPCFlowLogs,metricValue=1,defaultValue=0
--region eu-west-1
# SNS topic oluştur
SNS_ARN=$(aws sns create-topic
--name vpc-security-alerts
--query 'TopicArn'
--output text
--region eu-west-1)
# E-posta subscription ekle
aws sns subscribe
--topic-arn $SNS_ARN
--protocol email
--notification-endpoint [email protected]
--region eu-west-1
# CloudWatch Alarm oluştur
aws cloudwatch put-metric-alarm
--alarm-name HighRejectedConnections
--alarm-description "5 dakikada 100'den fazla reddedilen baglanti"
--metric-name RejectedConnectionCount
--namespace VPCFlowLogs
--statistic Sum
--period 300
--threshold 100
--comparison-operator GreaterThanThreshold
--evaluation-periods 1
--alarm-actions $SNS_ARN
--region eu-west-1
Maliyet Optimizasyonu İpuçları
VPC Flow Logs kullanırken maliyetleri kontrol altında tutmak için şu noktalara dikkat edin:
- Traffic type seçimi: Tüm trafiği değil, sadece REJECT trafiğini loglamak başlangıç için yeterli olabilir.
--traffic-type REJECTile sadece reddedilen bağlantıları yakalayabilirsiniz. - Log destination: S3, CloudWatch Logs’a göre çok daha ucuzdur. Uzun vadeli saklama için mutlaka S3 tercih edin.
- S3 Lifecycle Policy: S3’teki logları 30 gün sonra Glacier’a taşıyın.
- Aggregation interval: Varsayılan 10 dakikalık aggregation yerine 1 dakikalık kullanmak daha fazla log üretir, maliyeti artırır. Gerçekten anlık izleme yapmıyorsanız 10 dakikada bırakın.
- Subnet veya ENI bazlı loglama: Tüm VPC yerine sadece kritik subnet’leri veya ENI’ları loglayabilirsiniz.
Flow log maliyetlerini düzenli kontrol edin:
# CloudWatch Logs için aylık veri miktarını kontrol et
aws cloudwatch get-metric-statistics
--namespace AWS/Logs
--metric-name IncomingBytes
--dimensions Name=LogGroupName,Value=/vpc/flowlogs
--start-time $(date -d '30 days ago' -u +%Y-%m-%dT%H:%M:%SZ)
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
--period 2592000
--statistics Sum
--region eu-west-1
Flow Logs’ta Dikkat Edilmesi Gereken Limitler
Flow Logs her şeyi yakalamaz. Şu trafikler flow logs’a dahil değildir:
- Instance metadata servisine (169.254.169.254) giden trafik
- Amazon DNS sunucusuna giden trafik (kendi DNS sunucunuzu kullanıyorsanız görünür)
- Windows activation için Amazon Windows lisans sunucusuna giden trafik
- DHCP trafiği
- Varsayılan VPC router’ına giden trafik
Bu istisnalar troubleshooting yaparken sizi yanıltabilir. Bir bağlantı var ama logda göremiyorsunuz diye paniklemeden önce bu listeyi kontrol edin.
Sonuç
VPC Flow Logs, AWS ağ altyapınızda görünürlük sağlamanın temel taşıdır. Kurulumu nispeten basit ama doğru kullanmak bir miktar öğrenme gerektiriyor. Pratik olarak önerim şu şekilde: Önce kritik production VPC’lerinizde REJECT trafiğini S3’e loglamaya başlayın, maliyetleri görün. Ardından gerekli gördüğünüz subnet’lerde ALL trafiği aktif edin. CloudWatch Logs Insights ile birkaç temel sorguyu bookmarkleyin ve işlerin yoğun olmadığı bir günde bunlarla oynayın.
Güvenlik perspektifinden bakıldığında, flow logs olmadan AWS ortamınızda gerçekte ne olduğunu bilmiyorsunuz demektir. Bir güvenlik olayı yaşandığında geriye dönük inceleme yapabilmek için logların sürekli akmasına ihtiyaç duyarsınız. Bu yüzden bu servisi bir “ihtiyaç olursa açarız” olarak değil, altyapının kalıcı bir parçası olarak konumlandırın. Alarm mekanizmaları ve Athena ile birleştiğinde elimizdeki araçlar gerçekten güçlü bir gözlemlenebilirlik katmanı oluşturuyor.
