Warum AWS Secrets Manager statt Hardcoding? DB-Passwörter sicher verwalten

Ein privates Repository fühlt sich sicher an — bis ein Entwickler versehentlich einen Screenshot teilt, ein CI/CD-Token kompromittiert wird oder ein ehemaliger Kollege noch Zugriff hat. Hardcodierte Datenbankpasswörter im Anwendungscode sind einer der häufigsten Einstiegspunkte für Datenpannen, und 'das Repo ist privat' ist kein Sicherheitskonzept. AWS Secrets Manager löst genau dieses Problem mit zentralisierter Geheimnisverwaltung und automatischer Rotation.

TL;DR — Secrets Manager vs. Hardcoding im Vergleich

KriteriumHardcoding im CodeAWS Secrets Manager
AngriffsflächeJeder mit Repo-Zugriff sieht das PasswortZugriff nur über IAM-Berechtigungen zur Laufzeit
RotationManuell, fehleranfällig, selten gemachtAutomatisch, konfigurierbar, ohne Downtime
Audit-TrailKein Nachweis wer das Passwort wann verwendet hatVollständiges CloudTrail-Logging jedes API-Aufrufs
Notfall-ReaktionPasswort ändern → alle Deployments neu bauenNeues Secret erstellen → Anwendung liest automatisch
ComplianceSchwer nachweisbar (PCI-DSS, SOC2)Nachweisbare Zugriffskontrolle und Rotation

Wie Secrets Manager intern funktioniert

Bevor die Diagnose- und Einrichtungsschritte Sinn ergeben, muss das Grundprinzip klar sein: Secrets Manager ist kein einfacher Key-Value-Store. Er kombiniert verschlüsselte Speicherung, IAM-basierte Zugriffskontrolle, versionierte Geheimnisse und Lambda-gesteuerte Rotation in einem einzigen Service.

graph LR App["Anwendung
(ECS / EC2 / Lambda)"] -->|GetSecretValue API| SM["Secrets Manager"] SM -->|IAM pruefen| IAM["IAM-Autorisierung"] IAM -->|erlaubt| KMS["KMS Entschluesselung"] KMS -->|entschluesselt| SM SM -->|JSON-Wert| App SM -->|speichert verschluesselt| Store["Verschluesselter Secret-Store"] CT["CloudTrail"] -.->|protokolliert jeden Zugriff| SM
  1. Anwendung zur Laufzeit: Die Anwendung ruft GetSecretValue über die AWS SDK auf — kein Passwort im Code.
  2. IAM-Autorisierung: Die IAM-Rolle der Anwendung (z.B. EC2 Instance Profile oder ECS Task Role) muss explizit secretsmanager:GetSecretValue für das spezifische Secret erlauben.
  3. KMS-Entschlüsselung: Secrets Manager entschlüsselt den Wert mit dem konfigurierten KMS-Schlüssel und gibt ihn zurück. Ohne kms:Decrypt-Berechtigung schlägt der Aufruf fehl — auch wenn GetSecretValue erlaubt ist.
  4. Versionierung: Jedes Secret hat Versionen mit Staging-Labels (AWSCURRENT, AWSPENDING, AWSPREVIOUS). Rotation arbeitet mit diesen Labels, ohne den alten Wert sofort zu löschen.

Warum 'privates Repo' keine Sicherheitsstrategie ist

Die Annahme ist verständlich: Das Repo ist privat, nur das Team hat Zugriff, also ist das Passwort sicher. In der Praxis scheitert dieses Modell an mehreren Stellen gleichzeitig.

Git-History ist dauerhaft. Ein Passwort, das einmal committed wurde, bleibt in der History — auch nach einem git rm. Tools wie git-secrets oder truffleHog finden solche Geheimnisse in Sekunden. Wenn das Repo jemals öffentlich wird, auch nur kurz, ist das Passwort kompromittiert.

CI/CD-Systeme klonen das Repo. Jenkins, GitHub Actions, GitLab CI — alle bekommen eine vollständige Kopie des Codes inklusive aller Geheimnisse. Jeder Build-Agent, jeder Cache, jedes Artifact-Log ist ein potenzieller Leckagepunkt.

Ein Passwort im Code ist wie ein Hausschlüssel unter der Fußmatte: Alle, die wissen wo sie suchen müssen, finden ihn — und das sind mehr Leute als man denkt.

Das eigentliche Problem: Rotation. Ein hardcodiertes Passwort wird selten geändert, weil jede Änderung ein Deployment erfordert. Das bedeutet, dasselbe Passwort läuft oft jahrelang — ein ideales Ziel für Credential-Stuffing-Angriffe.

Secrets Manager einrichten — Schritt für Schritt

Schritt 1: Secret erstellen

Ein neues Datenbankgeheimnis anlegen. Secrets Manager unterstützt strukturierte JSON-Werte, was für Datenbank-Credentials praktisch ist — Benutzername und Passwort in einem einzigen Secret-Abruf.

aws secretsmanager create-secret \
  --name prod/myapp/db \
  --description 'PostgreSQL-Credentials fuer Produktionsumgebung' \
  --secret-string '{"username":"dbadmin","password":"InitialesPasswort123!"}' \
  --region us-east-1

Die Ausgabe enthält die Secret-ARN — diese wird für IAM-Policies benötigt. Das Secret wird standardmäßig mit dem AWS-verwalteten KMS-Schlüssel für Secrets Manager verschlüsselt. Für stärkere Kontrolle kann ein kundenverwalteter KMS-Schlüssel angegeben werden.

Schritt 2: IAM-Policy für die Anwendung erstellen

Die Anwendung braucht minimale Berechtigungen — nur Lesezugriff auf genau dieses Secret. Kein Wildcard, kein Zugriff auf andere Secrets. Das ist der entscheidende Unterschied zu Umgebungsvariablen: Der Zugriff ist auf Ressourcenebene kontrollierbar.

🔽 IAM-Policy für Secrets Manager Lesezugriff (aufklappen)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LeseDBSecret",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/db-*"
    },
    {
      "Sid": "KMSEntschluesselung",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/DEIN-KMS-SCHLUESSEL-ID"
    }
  ]
}

Wichtig: Der ARN-Suffix für Secrets Manager enthält einen zufälligen 6-stelligen Anhang (z.B. prod/myapp/db-AbCdEf). Der Wildcard -* am Ende des ARN ist deshalb notwendig, um die korrekte Ressource zu matchen, ohne den exakten Suffix hardcoden zu müssen.

Schritt 3: Secret zur Laufzeit abrufen

Die Anwendung ruft das Secret beim Start oder bei Bedarf ab. Kein Passwort in Konfigurationsdateien, kein Passwort in Umgebungsvariablen, kein Passwort im Code.

aws secretsmanager get-secret-value \
  --secret-id prod/myapp/db \
  --region us-east-1 \
  --query SecretString \
  --output text

In einer Python-Anwendung sieht das typischerweise so aus:

import boto3
import json

def get_db_credentials():
    client = boto3.client('secretsmanager', region_name='us-east-1')
    response = client.get_secret_value(SecretId='prod/myapp/db')
    secret = json.loads(response['SecretString'])
    return secret['username'], secret['password']

Schritt 4: Automatische Rotation konfigurieren

Automatische Rotation ist das Kernfeature, das Secrets Manager von einfachen Secret-Stores unterscheidet. Für unterstützte Datenbanken (Amazon RDS, Amazon Aurora, Amazon Redshift, Amazon DocumentDB) stellt AWS vorgefertigte Lambda-Rotationsfunktionen bereit.

sequenceDiagram participant SM as Secrets Manager participant LM as Lambda Rotationsfunktion participant DB as Datenbank SM->>LM: Rotation ausloesen (createSecret) LM->>SM: Neues Passwort als AWSPENDING speichern LM->>DB: Neues Passwort in DB setzen LM->>DB: Verbindung mit neuem Passwort testen LM->>SM: AWSPENDING zu AWSCURRENT promoten SM->>SM: Altes AWSCURRENT wird AWSPREVIOUS
  1. Rotation auslösen: Secrets Manager ruft die Lambda-Rotationsfunktion auf — entweder nach einem konfigurierten Zeitplan oder manuell.
  2. AWSPENDING erstellen: Lambda generiert ein neues Passwort und speichert es unter der AWSPENDING-Version.
  3. Datenbank aktualisieren: Lambda setzt das neue Passwort direkt in der Datenbank.
  4. Testen: Lambda verifiziert, dass die Verbindung mit dem neuen Passwort funktioniert.
  5. Label wechseln: AWSPENDING wird zu AWSCURRENT, das alte AWSCURRENT wird zu AWSPREVIOUS.

Während der gesamten Rotation ist die Anwendung weiterhin erreichbar — sie liest AWSCURRENT, und das alte Passwort bleibt als AWSPREVIOUS noch kurz gültig.

aws secretsmanager rotate-secret \
  --secret-id prod/myapp/db \
  --rotation-rules AutomaticallyAfterDays=30 \
  --region us-east-1

Für RDS-Datenbanken kann die Rotation mit einer verwalteten Rotationsfunktion aktiviert werden, ohne eine eigene Lambda-Funktion schreiben zu müssen. Die genaue Konfiguration hängt vom Datenbanktyp und der Netzwerkkonfiguration ab — die offizielle AWS-Dokumentation zur Rotation enthält die aktuellen Voraussetzungen.

Das klassische Fehlermuster: 'Es funktioniert lokal, aber nicht in Produktion'

Ein typisches Szenario: Die Anwendung läuft lokal mit einem hardcodierten Passwort in einer .env-Datei. In Produktion soll Secrets Manager verwendet werden. Der Entwickler konfiguriert GetSecretValue, deployed — und bekommt einen AccessDeniedException.

Die erste Reaktion: 'Die IAM-Policy ist falsch.' Also wird die Policy auf "Resource": "*" erweitert. Immer noch derselbe Fehler.

Der tatsächliche Grund: Die ECS-Task-Definition verwendet eine alte Task-Role, die noch keine Secrets-Manager-Berechtigungen hat. Die neue Policy wurde an eine andere Rolle angehängt. Das lässt sich mit folgendem Befehl prüfen:

aws ecs describe-tasks \
  --cluster prod-cluster \
  --tasks TASK-ID \
  --region us-east-1 \
  --query 'tasks[0].taskDefinitionArn'
aws ecs describe-task-definition \
  --task-definition TASK-DEFINITION-ARN \
  --region us-east-1 \
  --query 'taskDefinition.taskRoleArn'

Dann prüfen, welche Policies an diese spezifische Rolle angehängt sind:

aws iam list-attached-role-policies \
  --role-name TASK-ROLE-NAME

Meistens stellt sich heraus: Die Policy wurde an die Execution Role angehängt, nicht an die Task Role. Bei ECS sind das zwei verschiedene Rollen mit unterschiedlichen Zwecken — die Execution Role zieht das Container-Image und sendet Logs, die Task Role ist die Identität des laufenden Containers.

Secrets Manager vs. Parameter Store — wann was?

AWS Systems Manager Parameter Store ist eine häufig genannte Alternative. Die Entscheidung ist nicht kompliziert, wenn man die Unterschiede kennt.

MerkmalSecrets ManagerParameter Store (SecureString)
Automatische RotationJa, nativ für unterstützte DiensteNein, muss selbst implementiert werden
KostenPro Secret und API-Aufruf (Preise variieren — aktuelle AWS-Dokumentation prüfen)Kostenlos für Standard-Parameter, Kosten für Advanced
Cross-Account-ZugriffJa, über Resource-based PolicyEingeschränkt
VersionierungAutomatisch mit Staging-LabelsManuell über Versionshistorie
AnwendungsfallDatenbankpasswörter, API-Keys mit RotationKonfigurationswerte, Feature-Flags, nicht-rotierende Secrets

Faustregel: Wenn das Geheimnis rotiert werden muss oder cross-account geteilt wird, ist Secrets Manager die richtige Wahl. Für statische Konfigurationswerte reicht Parameter Store.

Bestehende Anwendungen migrieren — ohne Downtime

Der häufigste Einwand gegen die Migration: 'Wir können nicht einfach alle Deployments gleichzeitig ändern.' Das stimmt — und Secrets Manager macht das auch nicht notwendig.

Eine sichere Migrationsstrategie läuft in drei Phasen. Zuerst das Secret in Secrets Manager anlegen, parallel zum bestehenden hardcodierten Wert. Dann die Anwendung so anpassen, dass sie versucht, das Secret aus Secrets Manager zu lesen, und bei Fehler auf den hardcodierten Wert zurückfällt. Schließlich, nach erfolgreicher Verifikation, den Fallback entfernen und das hardcodierte Passwort aus dem Code löschen.

# Pruefen ob das Secret korrekt abgerufen werden kann
aws secretsmanager get-secret-value \
  --secret-id prod/myapp/db \
  --version-stage AWSCURRENT \
  --region us-east-1
# CloudTrail-Events fuer Secret-Zugriffe pruefen
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue \
  --region us-east-1 \
  --max-results 10

CloudTrail protokolliert jeden GetSecretValue-Aufruf mit Zeitstempel, aufrufender Identität und Quell-IP. Das ist der Audit-Trail, den ein hardcodiertes Passwort niemals liefern kann.

Wrap-up: Secrets Manager ist kein Luxus

Hardcodierte Passwörter in privaten Repos sind kein akzeptables Sicherheitsmodell — nicht wegen theoretischer Risiken, sondern weil die Angriffsvektoren (Git-History, CI/CD-Systeme, kompromittierte Entwickler-Accounts) in der Praxis regelmäßig ausgenutzt werden. AWS Secrets Manager löst das Problem mit zentralisierter Speicherung, IAM-basierter Zugriffskontrolle, vollständigem Audit-Trail und automatischer Rotation.

Der Einstieg ist geringer als erwartet: Ein Secret anlegen, eine IAM-Policy anpassen, drei SDK-Zeilen im Code ändern. Die Rotation für RDS-Datenbanken lässt sich ohne eigene Lambda-Implementierung aktivieren.

Nächste Schritte:

Glossar

BegriffBedeutung
SecretEin verschlüsselt gespeicherter Wert in Secrets Manager, z.B. ein Datenbankpasswort oder API-Key
Staging LabelBezeichnung einer Secret-Version (AWSCURRENT, AWSPENDING, AWSPREVIOUS) — steuert welche Version aktiv ist
RotationAutomatischer Prozess zum Ersetzen eines Secrets durch einen neuen Wert, ohne manuelle Deployments
Task RoleIAM-Rolle, die einem laufenden ECS-Container zugewiesen ist und dessen Berechtigungen für AWS-API-Aufrufe definiert
Resource-based PolicyIAM-Policy, die direkt an eine Ressource (hier: ein Secret) angehängt wird und cross-account Zugriff ermöglicht

Related Posts

Kommentare

Beliebte Posts aus diesem Blog

EC2 ohne Internetzugang im eigenen VPC – Internet Gateway und Route Table korrekt einrichten

LSI vs. GSI in DynamoDB: Den richtigen Sekundärindex wählen

ElastiCache Redis einsetzen: Wann ein Caching-Layer deine RDS-Datenbank entlastet