Inhaltsverzeichnis18 Abschnitte
- TL;DR
- Threat Model
- Encryption at Rest
- AWS KMS: Envelope Encryption
- Terraform: KMS Key mit Rotation
- S3 Bucket Encryption mit Bucket-Key
- RDS/Redshift Encryption
- Column-Level Encryption für PII
- Encryption in Transit
- TLS 1.3 als Baseline
- Kafka TLS-Konfiguration
- ALB + ACM für HTTP
- Key Management Best Practices
- Secrets Manager Rotation
- Compliance-Mapping
- AWS Config Audits
- Häufige Fehler
- FAQ
"Wir verschlüsseln unsere Daten" ist einer der missverstandensten Sätze in Cloud-Security. Er kann S3-Default-Encryption meinen (gut) oder eine selbstgebaute Crypto-Library (gruselig). Dieser Leitfaden gibt dir die Praktiker:innen-Sicht: was verschlüsseln, wie richtig, wo die Fallen liegen und wie du verifizierst.
TL;DR
- Encryption schützt Storage und Wire — nicht kompromittierte Compute oder Identity.
- Niemals eigenes Key-Material managen. KMS mit Customer-Managed Keys + automatischer Rotation.
- Bucket-Key aktivieren, sonst trifft dich das KMS-Request-Quota.
- TLS 1.3 überall, mTLS intern.
- Column-Level Encryption für PII, die selbst vor DBAs versteckt sein muss.
- DSGVO Art. 32 = KMS + Column-Level für personenbezogene Daten.
Threat Model
| Threat | At Rest | In Transit | Beide |
|---|---|---|---|
| Gestohlener S3-Bucket | Ja | – | Ja |
| Kompromittierter Netzwerkpfad | – | Ja | Ja |
| Kompromittiertes Host-OS | – | – | – |
| Rogue DBA | – | – | – |
Encryption ist kein Allheilmittel. Kombiniere mit IAM, VPC-Boundaries und Audit-Logging.
Encryption at Rest
AWS KMS: Envelope Encryption
KMS sieht deine Daten nie — es wrappt nur den Data Encryption Key (DEK). Deine App holt einen DEK, verschlüsselt damit die Daten und speichert DEK (encrypted) zusammen mit den Daten.
Terraform: KMS Key mit Rotation
resource "aws_kms_key" "data_platform" {
description = "Data platform encryption key"
deletion_window_in_days = 30
enable_key_rotation = true
multi_region = false
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowKeyAdministration"
Effect = "Allow"
Principal = { AWS = "arn:aws:iam::${var.account_id}:role/DataPlatformAdmin" }
Action = ["kms:*"]
Resource = "*"
},
{
Sid = "AllowServiceUse"
Effect = "Allow"
Principal = { Service = ["s3.amazonaws.com", "rds.amazonaws.com", "glue.amazonaws.com"] }
Action = ["kms:GenerateDataKey", "kms:Decrypt", "kms:DescribeKey"]
Resource = "*"
}
]
})
tags = {
Purpose = "data-platform-encryption"
Rotation = "annual-automatic"
}
}
S3 Bucket Encryption mit Bucket-Key
resource "aws_s3_bucket_server_side_encryption_configuration" "data_lake" {
bucket = aws_s3_bucket.data_lake["bronze"].id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.data_platform.arn
}
bucket_key_enabled = true # Reduziert KMS-API-Kosten um 99 %
}
}
resource "aws_s3_bucket_policy" "enforce_encryption" {
bucket = aws_s3_bucket.data_lake["bronze"].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "DenyUnencryptedObjectUploads"
Effect = "Deny"
Principal = "*"
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.data_lake["bronze"].arn}/*"
Condition = { StringNotEquals = { "s3:x-amz-server-side-encryption" = "aws:kms" } }
}]
})
}
RDS/Redshift Encryption
resource "aws_db_instance" "data_warehouse" {
identifier = "data-warehouse-${var.environment}"
engine = "postgres"
engine_version = "15.4"
instance_class = "db.r6g.xlarge"
storage_encrypted = true
kms_key_id = aws_kms_key.data_platform.arn
performance_insights_enabled = true
performance_insights_kms_key_id = aws_kms_key.data_platform.arn
backup_retention_period = 30
}
Column-Level Encryption für PII
Für PII-Felder, die selbst vor DB-Admins verschlüsselt sein müssen.
encryption:
enabled: true
pii_columns:
- email
- phone_number
- national_id
- credit_card_number
strategy: deterministic # vs random (für Lookup-Joins)
key_provider: aws_kms
kms_key_id: "alias/data-platform-prod"
cache_ttl_seconds: 300
Encryption in Transit
TLS 1.3 als Baseline
TLS 1.3 eliminiert die schwachen Cipher Suites aus 1.2. Erzwinge es überall.
openssl s_client -connect my-kafka-broker:9093 -tls1_3 2>/dev/null | grep -E "Protocol|Cipher"
# Erwartet:
# Protocol : TLSv1.3
# Cipher : TLS_AES_256_GCM_SHA384
Kafka TLS-Konfiguration
listeners=PLAINTEXT://localhost:9092,SSL://0.0.0.0:9093
ssl.keystore.location=/etc/kafka/ssl/kafka.server.keystore.jks
ssl.keystore.password=${KEYSTORE_PASSWORD}
ssl.truststore.location=/etc/kafka/ssl/kafka.server.truststore.jks
ssl.client.auth=required
ssl.enabled.protocols=TLSv1.3
ssl.cipher.suites=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256
ALB + ACM für HTTP
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.data_api.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = aws_acm_certificate_validation.api.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.data_api.arn
}
}
resource "aws_lb_listener" "http_redirect" {
load_balancer_arn = aws_lb.data_api.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
Key Management Best Practices
| Key Type | Rotation | Methode |
|---|---|---|
| KMS CMK | Jährlich, automatisch | enable_key_rotation |
| DEKs | Pro Job oder pro Tag | Re-wrap mit neuer CMK |
| TLS-Zertifikate | 90 Tage (Let's Encrypt) / Jährlich (ACM) | Auto-Renew |
| DB-Master-Passwort | 90 Tage | Secrets Manager Rotation |
| API-Keys | 30–90 Tage | Manuell + CI/CD |
Secrets Manager Rotation
resource "aws_secretsmanager_secret" "db_password" {
name = "data-platform/${var.environment}/db-master-password"
kms_key_id = aws_kms_key.data_platform.arn
recovery_window_in_days = 7
}
resource "aws_secretsmanager_secret_rotation" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
rotation_lambda_arn = aws_lambda_function.db_password_rotator.arn
rotation_rules { automatically_after_days = 90 }
}
Compliance-Mapping
| Anforderung | Control | Implementierung |
|---|---|---|
| DSGVO Art. 32 | Verschlüsselung personenbezogener Daten | KMS + Column-Level für PII |
| SOC 2 CC6.1 | Logical Access Controls | KMS Key Policies + IAM |
| PCI DSS 3.4 | Cardholder-Data-Verschlüsselung | Deterministisches Column-Encryption |
| ISO 27001 A.10 | Kryptografische Controls | Key-Management-Policy |
AWS Config Audits
resource "aws_config_config_rule" "s3_encryption" {
name = "s3-bucket-server-side-encryption-enabled"
source {
owner = "AWS"
source_identifier = "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"
}
}
resource "aws_config_config_rule" "kms_rotation" {
name = "cmk-backing-key-rotation-enabled"
source {
owner = "AWS"
source_identifier = "CMK_BACKING_KEY_ROTATION_ENABLED"
}
}
Häufige Fehler
- S3-Default ≠ Customer-Managed. AWS-managed Keys geben dir keine Usage-Logs oder Rotation-Control.
- Backups mit demselben Key wie Prod. Bei Key-Kompromiss sind beide weg.
- KMS-Request-Quotas ignorieren. Ohne Bucket-Key hittest du bei 10.000 req/s das Limit.
- TLS nur am LB terminieren. Backend-to-Backend muss auch verschlüsselt sein.
- Keys in App-Code. Niemals. Secrets Manager oder Env-Injection.
FAQ
Reicht S3-Default-Encryption für DSGVO? Für Encryption-at-Rest formal ja. Für Key-Rotation-Logs und Compliance-Nachweise brauchst du Customer-Managed CMKs.
eu-central-1 oder mehrere Regionen? DSGVO-konform reicht eu-central-1 (Frankfurt). Für Cross-Region DR multi-region KMS-Keys konfigurieren.
Wie oft KMS-Keys rotieren? KMS CMK jährlich automatisch reicht meist. DEKs öfter, z. B. pro Tag oder pro Job.
Was kostet KMS in eu-central-1? 1 $/Monat pro CMK + 0,03 $ pro 10.000 Requests. Ohne Bucket-Key explodiert das.
Stand: 14. Mai 2026.
Geschrieben von
Harbinger Team
Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastrukturkritische Tech-Entscheidungen — keine Marketing- Folien, sondern echte Trade-offs aus Production-Workloads.
Hat dir das geholfen?
Jede Woche ein neuer Artikel über DACH-Cloud, Data und AI — direkt in dein Postfach. Kein Spam, kein Marketing-Sprech.
Kein Spam. 1-Klick-Abmeldung. Datenschutz bei Loops.so.