WAF++ WAF++
Back to WAF++ Homepage

Best Practice: Secrets Management

Kontext

Secrets – Datenbankpasswörter, API-Keys, TLS-Zertifikate, OAuth-Client-Secrets – sind das sensibelste Artefakt in jeder Cloud-Architektur. Gleichzeitig ist Secrets Management das am häufigsten falsch implementierte Sicherheitskonzept.

Reale Konsequenzen schlechten Secrets Managements:

  • GitHub Secret Leaks: Tausende Repositories enthalten aktive AWS Access Keys in der Commit-Historie – auch nach Löschung der Dateien über git log

  • CI/CD Credential Exposure: Build-Logs mit echo $DATABASE_PASSWORD werden in Artifact-Storage abgelegt und sind für alle CI-Nutzer sichtbar

  • Shared Service Credentials: Ein Datenbankpasswort wird an 5 Entwickler und 3 Services verteilt – Rotation bricht alle gleichzeitig, wird deshalb nie durchgeführt

  • Hardcoded in Docker Images: ENV-Variablen in Dockerfiles landen im Image-Layer und sind in jeder Image-Kopie sichtbar

Zugehörige Controls

Warum Secrets Management kritisch ist

Ein einziger exponierter AWS Access Key mit umfangreichen Berechtigungen kann innerhalb von Minuten zu:

  • Vollständiger Datenexfiltration (S3, RDS-Snapshots)

  • Crypto-Mining auf allen EC2-Instanzen (Kostenpotenzial: Tausende Euro pro Tag)

  • Erstellung von Backdoor-IAM-Users für persistenten Zugang

  • Löschung kritischer Ressourcen (DynamoDB-Tables, S3-Buckets)

führen. AWS selbst erkennt exponierte Keys in öffentlichen GitHub-Repositories durch die GitHub Secret Scanning Integration – aber Reaktion kommt oft zu spät.

Tool-Vergleich: Secrets Manager, SSM Parameter Store, HashiCorp Vault

Kriterium AWS Secrets Manager SSM Parameter Store HashiCorp Vault

Kosten

~0,40 USD pro Secret pro Monat + API-Aufrufe

Standard kostenlos; Advanced: ~0,05 USD pro Parameter

Open Source kostenlos; Enterprise-Features kostenpflichtig

Automatische Rotation

Nativ für RDS, DocumentDB, Redshift; Custom Lambda für alle anderen

Nicht nativ; Custom-Skripte erforderlich

Nativ für Datenbanken, Cloud-Credentials, SSH

Dynamic Secrets

Nicht nativ

Nicht nativ

Nativ – Schlüsselfeature

Cross-Account Zugriff

Resource-based Policy; IAM

IAM mit Account-spezifischen ARNs

Token-basiert; Cloud-agnostisch

Audit Log

CloudTrail

CloudTrail

Vault Audit Log (detaillierter)

KMS-Integration

Nativ; CMK pro Secret konfigurierbar

Nativ für SecureString

Transit Engine; eigene Verschlüsselung

Multi-Cloud

AWS-only

AWS-only

Cloud-agnostisch

Empfehlung

Für AWS-native Workloads; Datenbankpasswörter mit auto-rotation

Für Konfigurationswerte und weniger sensitive Secrets

Für Multi-Cloud, Dynamic Secrets, komplexe Hierarchien

Secret-Rotation

Automatische Rotation mit AWS Secrets Manager

resource "aws_secretsmanager_secret" "db_password" {
  name        = "production/payment-service/db-password"
  description = "PostgreSQL-Passwort für den Payment-Service"

  # CMK-Verschlüsselung – kein AWS-managed Key
  kms_key_id = aws_kms_key.secrets_cmk.arn

  # Recovery Window: mindestens 7 Tage (WAF-SEC-060)
  recovery_window_in_days = 30

  tags = {
    owner       = "platform-team"
    workload    = "payment-service"
    data-class  = "confidential"
    environment = "production"
  }
}

resource "aws_secretsmanager_secret_rotation" "db_password" {
  secret_id           = aws_secretsmanager_secret.db_password.id
  rotation_lambda_arn = aws_lambda_function.rds_rotation.arn

  rotation_rules {
    automatically_after_days = 30  # Rotation alle 30 Tage
  }
}

AWS-managed Rotation für RDS

Für RDS, Aurora, DocumentDB, ElastiCache und Redshift bietet AWS vorgefertigte Rotation-Lambda-Funktionen ohne Custom Code:

resource "aws_secretsmanager_secret" "rds_master" {
  name       = "production/payment-db/master-credentials"
  kms_key_id = aws_kms_key.secrets_cmk.arn

  recovery_window_in_days = 30

  tags = {
    owner      = "platform-team"
    data-class = "confidential"
  }
}

resource "aws_secretsmanager_secret_version" "rds_master_initial" {
  secret_id = aws_secretsmanager_secret.rds_master.id
  secret_string = jsonencode({
    username = "payment_svc"
    password = random_password.db_initial.result
    engine   = "postgres"
    host     = aws_db_instance.payment.address
    port     = 5432
    dbname   = "payment"
  })
}

# Rotation über AWS-managed Lambda – keine Custom Lambda erforderlich
resource "aws_secretsmanager_secret_rotation" "rds_master" {
  secret_id           = aws_secretsmanager_secret.rds_master.id
  rotation_lambda_arn = "arn:aws:lambda:eu-central-1:${data.aws_caller_identity.current.account_id}:function:SecretsManagerRDSPostgreSQLRotationSingleUser"

  rotation_rules {
    automatically_after_days = 30
  }
}

Dynamic Secrets Konzept

Dynamic Secrets sind Credentials, die per Session on-demand generiert und nach einer festgelegten Zeit automatisch ungültig werden. HashiCorp Vault implementiert dieses Konzept nativ für Datenbanken:

Ablauf Dynamic Secrets (HashiCorp Vault Database Engine):

1. Payment-Service startet → Authentifiziert sich bei Vault via Kubernetes Auth
2. Vault generiert temporären Datenbankbenutzer:
   - Username: v-k8s-payment-abcd1234
   - Password: zufällig generiert
   - TTL: 1 Stunde (danach automatisch gelöscht)
3. Payment-Service verbindet zur Datenbank mit diesen Credentials
4. Nach 1 Stunde: Vault löscht den Datenbankbenutzer automatisch
5. Payment-Service erneuert Credentials 15 Minuten vor Ablauf

Vorteile:

  • Kein dauerhaftes Passwort – nichts zu stehlen und langfristig zu missbrauchen

  • Vollständiger Audit-Trail: jeder Datenbankzugang ist einem Service-Token zuordenbar

  • Rotation ist inhärent – Credentials sind per Design kurzlebig

Secrets in CI/CD: GitHub OIDC + AWS STS

Statische AWS Access Keys in CI/CD sind eines der größten Risiken. Die Alternative: GitHub OIDC erlaubt GitHub Actions, temporäre AWS-Credentials ohne statische Keys zu erhalten:

# OIDC Provider für GitHub registrieren
resource "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = ["sts.amazonaws.com"]

  thumbprint_list = [
    "6938fd4d98bab03faadb97b34396831e3780aea1",
    "1c58a3a8518e8759bf075b76b750d4f2df264fcd"
  ]
}

# IAM-Rolle für den Deployment-Workflow
resource "aws_iam_role" "github_deployment" {
  name = "github-actions-payment-service-deploy"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Federated = aws_iam_openid_connect_provider.github.arn
      }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringEquals = {
          "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
        }
        StringLike = {
          # Nur der main-Branch des spezifischen Repositories
          "token.actions.githubusercontent.com:sub" = "repo:acme-corp/payment-service:ref:refs/heads/main"
        }
      }
    }]
  })
}

GitHub Actions Workflow-Konfiguration (kein statischer Key):

name: Deploy Payment Service

on:
  push:
    branches: [main]

permissions:
  id-token: write   # OIDC Token anfordern
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-payment-service-deploy
          aws-region: eu-central-1
          # Kein aws-access-key-id oder aws-secret-access-key erforderlich

      - name: Deploy to ECS
        run: |
          aws ecs update-service \
            --cluster production \
            --service payment-service \
            --force-new-deployment

Anti-Patterns

Anti-Pattern Warum gefährlich

Secrets in Umgebungsvariablen im Dockerfile

Landen in Image-Layers; sichtbar in docker inspect; kein Rotation-Mechanismus

Secrets in Terraform-State

State-File enthält alle Werte im Klartext; S3-Backend braucht CMK-Verschlüsselung

Secrets in Git (auch nach git rm)

In der Commit-Historie erhalten; via git log -p jederzeit extrahierbar

Passwörter nie rotieren, weil Rotation Aufwand macht

Kompromittierte Credentials bleiben ewig gültig; GDPR Art. 32 und BSI C5 fordern periodische Rotation

Secrets teilen zwischen Staging und Production

Leak in Staging kompromittiert Production; keine Audit-Trennung möglich

Monitoring und Drift-Prüfung

  • wafpass check --pillar security --controls WAF-SEC-060 – prüft Secrets Manager Konfiguration

  • AWS Config Rule secretsmanager-rotation-enabled-check – prüft Rotation-Status

  • AWS Config Rule secretsmanager-using-cmk – prüft CMK-Verschlüsselung

  • GuardDuty CredentialAccess:IAMUser/AnomalousBehavior – Credential-Missbrauch

  • GitHub Advanced Security Secret Scanning – exponierte Keys in Repositories

  • trufflehog / gitleaks in Pre-Commit-Hook – verhindert Commits mit Secrets