Best Practice: Egress Control & Data Exfiltration Prevention
Kontext
Offener Egress ist die letzte Lücke, durch die Daten die Souveränitätsgrenze verlassen.
Typische Probleme:
-
Default Security Groups erlauben
0.0.0.0/0Outbound -
AWS-API-Aufrufe traversieren das öffentliche Internet (kein VPC Endpoint)
-
Log-Agents (Datadog, Splunk) senden Telemetrie zu US-Servern
-
DNS-Tunneling als unentdeckter Exfiltrationspfad
Zugehörige Controls
-
WAF-SOV-090 – Controlled Egress & Data Exfiltration Guardrails
Zielbild
Alle ausgehenden Verbindungen sind kontrolliert:
-
Security Groups: nur explizite, dokumentierte Egress-Regeln
-
VPC Endpoints für alle genutzten Cloud-Services
-
Network Firewall mit Domain Allow-List
-
VPC Flow Logs für forensische Rekonstruktion
-
GuardDuty für Anomalie-Erkennung
Technische Umsetzung
Security Groups: Kein Wildcard-Egress
# Sovereign Application Security Group
resource "aws_security_group" "app" {
name = "sovereign-app-${var.environment}"
description = "Application security group with controlled egress"
vpc_id = aws_vpc.main.id
# Nur spezifische ausgehende Verbindungen erlaubt
egress {
description = "HTTPS to internal services"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [aws_vpc.main.cidr_block]
}
egress {
description = "DNS resolution (internal resolver)"
from_port = 53
to_port = 53
protocol = "udp"
cidr_blocks = [aws_vpc.main.cidr_block]
}
# KEIN: egress { cidr_blocks = ["0.0.0.0/0"] }
tags = {
data-residency = "eu-only"
environment = var.environment
egress-policy = "restricted"
}
}
VPC Endpoints für Cloud-Services
# Gateway Endpoints (kostenlos, kein Data Transfer durch Internet)
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = [aws_route_table.private.id]
# Restrict to sovereign buckets only
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = "*"
Action = ["s3:*"]
Resource = "*"
Condition = {
StringEquals = {
"aws:RequestedRegion" = var.aws_region
}
}
}]
})
}
resource "aws_vpc_endpoint" "dynamodb" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.dynamodb"
vpc_endpoint_type = "Gateway"
route_table_ids = [aws_route_table.private.id]
}
# Interface Endpoints für weitere Services
resource "aws_vpc_endpoint" "kms" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.kms"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoint.id]
private_dns_enabled = true
}
resource "aws_vpc_endpoint" "ecr_api" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.ecr.api"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoint.id]
private_dns_enabled = true
}
resource "aws_vpc_endpoint" "sts" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.sts"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoint.id]
private_dns_enabled = true
}
VPC Flow Logs
resource "aws_flow_log" "sovereign" {
vpc_id = aws_vpc.main.id
traffic_type = "ALL"
iam_role_arn = aws_iam_role.flow_log.arn
log_destination = aws_cloudwatch_log_group.flow_log.arn
tags = {
data-class = "audit"
data-residency = "eu-only"
environment = var.environment
}
}
resource "aws_cloudwatch_log_group" "flow_log" {
name = "/sovereign/vpc-flow-logs/${var.environment}"
retention_in_days = 90
kms_key_id = aws_kms_key.sovereign_data.arn
}
GuardDuty für Exfiltration Detection
resource "aws_guardduty_detector" "main" {
enable = true
datasources {
s3_logs {
enable = true
}
kubernetes {
audit_logs {
enable = true
}
}
malware_protection {
scan_ec2_instance_with_findings {
ebs_volumes {
enable = true
}
}
}
}
tags = {
data-residency = "eu-only"
environment = var.environment
}
}
# Alert on high-severity GuardDuty findings
resource "aws_cloudwatch_event_rule" "guardduty_high" {
name = "sovereign-guardduty-high-severity"
description = "Alert on high/critical GuardDuty findings"
event_pattern = jsonencode({
source = ["aws.guardduty"]
detail-type = ["GuardDuty Finding"]
detail = {
severity = [{ numeric = [">=", 7] }]
}
})
}
Typische Fehlmuster
-
Default Security Group: AWS Default SG erlaubt outbound zu allem
-
NAT Gateway ohne Firewall: NAT Gateway ist kein Egress-Filter
-
S3 Public Access nicht geblockt: Daten direkt im Internet erreichbar
-
Log-Agents ohne Private Link: Datadog/Splunk über Public Internet
Metriken
-
Anzahl Security Groups mit
0.0.0.0/0Egress (Ziel: 0 ohne Dokumentation) -
Anteil VPCs mit VPC Flow Logs (Ziel: 100%)
-
Anzahl GuardDuty High-Findings pro Monat (Trend)
-
Anteil genutzter AWS Services mit VPC Endpoint (Ziel: alle Production-Services)
Reifegrad
Level 1 – Default Security Groups, offener Egress
Level 2 – Restricted Egress Ports, VPC Endpoints für S3/DynamoDB
Level 3 – Default-Deny, Network Firewall mit Domain Allow-List, VPC Flow Logs
Level 4 – GuardDuty aktiv, Anomalie-Erkennung in Flow Logs
Level 5 – Zero-Trust Network, Auto-Block, vollständige Forensik-Kapazität