Lambda Environment Variables: Konfiguration, KMS-Verschlüsselung und Best Practices

Du hast einen Datenbankendpunkt, der sich je nach Umgebung ändert — Entwicklung, Staging, Produktion — und willst ihn nicht direkt in den Funktionscode schreiben. Lambda Environment Variables lösen genau dieses Problem, aber der Teufel steckt im Detail: Wann reichen die Standard-Verschlüsselung aus, wann brauchst du einen eigenen KMS-Schlüssel, und wie liest du die Werte zur Laufzeit korrekt aus?

TL;DR: Lambda Environment Variables auf einen Blick

Aspekt Detail
Speicherort Funktionskonfiguration, nicht im Deployment-Paket
Standard-Verschlüsselung AWS-verwalteter Schlüssel (aws/lambda) — automatisch, kein Setup nötig
Eigener KMS-Schlüssel Kundenverwalteter CMK — explizite IAM-Berechtigung erforderlich
Laufzeitzugriff Über Betriebssystem-Umgebungsvariablen (z. B. process.env, os.environ)
Maximale Größe 4 KB gesamt für alle Variablen — Limits und Preise immer in der offiziellen AWS-Dokumentation prüfen
Sichtbarkeit im Klartext Standardmäßig im Konsolenbereich sichtbar — Hilfsverschlüsselung mit eigenem CMK empfohlen

Wie Lambda Environment Variables funktionieren

Lambda injiziert die konfigurierten Schlüssel-Wert-Paare als Betriebssystem-Umgebungsvariablen in den Ausführungskontext, bevor dein Handler-Code aufgerufen wird. Das bedeutet: Die Werte sind bereits vorhanden, wenn deine init-Phase läuft — du kannst sie also sicher außerhalb des Handlers lesen, um teure Initialisierungen zu cachen.

Wichtig zu verstehen: Lambda verschlüsselt alle Environment Variables im Ruhezustand. Ohne eigene Konfiguration verwendet der Dienst einen AWS-verwalteten Schlüssel im Namespace aws/lambda. Dieser Schlüssel liegt vollständig unter AWS-Kontrolle — du hast keine Möglichkeit, Schlüsselrichtlinien anzupassen oder die Nutzung in CloudTrail granular zu verfolgen. Sobald du einen kundenverwalteten CMK (Customer Managed Key) konfigurierst, dreht sich das Verhältnis um: Du kontrollierst den Schlüssel, die Rotation und die Zugriffsrichtlinie.

graph LR A["Lambda-Konfiguration
Environment Variables"] --> B["KMS-Verschlüsselung
at rest"] B --> C["Execution Context
Kaltstart"] C --> D["KMS Decrypt
kms:Decrypt"] D --> E["OS-Umgebungsvariablen
injiziert"] E --> F["Handler-Code
os.environ / process.env"] style A fill:#232F3E,color:#FF9900 style B fill:#232F3E,color:#FF9900 style C fill:#1A6B3C,color:#ffffff style D fill:#8B0000,color:#ffffff style E fill:#1A6B3C,color:#ffffff style F fill:#232F3E,color:#FF9900
  1. Konfigurationszeit: Environment Variables werden in der Funktionskonfiguration gespeichert und mit dem gewählten KMS-Schlüssel verschlüsselt.
  2. Deployment: Lambda entschlüsselt die Variablen beim Start des Execution Context und injiziert sie als OS-Umgebungsvariablen.
  3. Handler-Aufruf: Dein Code liest die Werte über die Standard-Laufzeit-API (z. B. os.environ['DB_ENDPOINT']).
  4. KMS-Aufruf (nur bei CMK): Lambda ruft kms:Decrypt auf — dieser Aufruf erscheint in CloudTrail und kann über die Schlüsselrichtlinie eingeschränkt werden.

Environment Variables setzen — CLI und Konsole

Der direkteste Weg ist die AWS CLI. Hier setzt du eine Variable beim Erstellen der Funktion:

aws lambda create-function \
  --function-name meine-funktion \
  --runtime python3.12 \
  --role arn:aws:iam::123456789012:role/MeineLambdaRole \
  --handler app.handler \
  --zip-file fileb://function.zip \
  --environment 'Variables={DB_ENDPOINT=db.example.internal,APP_ENV=production}'

Für eine bereits existierende Funktion verwendest du update-function-configuration. Achtung: Dieser Befehl ersetzt alle bestehenden Environment Variables vollständig — kein Merge, kein Patch.

aws lambda update-function-configuration \
  --function-name meine-funktion \
  --environment 'Variables={DB_ENDPOINT=db.example.internal,APP_ENV=production,LOG_LEVEL=INFO}'

Aktuelle Konfiguration prüfen:

aws lambda get-function-configuration \
  --function-name meine-funktion \
  --query 'Environment'

KMS-Verschlüsselung mit eigenem CMK konfigurieren

Wenn der Datenbankendpunkt als sensitiv gilt — oder du Compliance-Anforderungen hast, die Schlüsselnachweise in CloudTrail erfordern — brauchst du einen kundenverwalteten CMK. Die Standardverschlüsselung reicht dann nicht aus, weil du weder Schlüsselrotation noch Zugriffsrichtlinien kontrollierst.

Schritt 1: CMK erstellen

aws kms create-key \
  --description 'CMK fuer Lambda Environment Variables' \
  --key-usage ENCRYPT_DECRYPT \
  --origin AWS_KMS

Gib dem Schlüssel einen lesbaren Alias:

aws kms create-alias \
  --alias-name alias/lambda-env-key \
  --target-key-id <KEY_ID_AUS_VORHERIGEM_BEFEHL>

Schritt 2: Lambda-Ausführungsrolle berechtigen

Die Ausführungsrolle der Lambda-Funktion muss kms:Decrypt auf dem CMK ausführen dürfen. Ohne diese Berechtigung startet die Funktion nicht — Lambda kann die Variablen nicht entschlüsseln.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LambdaKMSDecrypt",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/<DEIN-KEY-ID>"
    }
  ]
}

Diese Policy an die Ausführungsrolle anhängen:

aws iam put-role-policy \
  --role-name MeineLambdaRole \
  --policy-name LambdaKMSDecryptPolicy \
  --policy-document file://kms-decrypt-policy.json

Schritt 3: Funktion mit CMK konfigurieren

aws lambda update-function-configuration \
  --function-name meine-funktion \
  --kms-key-arn arn:aws:kms:us-east-1:123456789012:key/<DEIN-KEY-ID> \
  --environment 'Variables={DB_ENDPOINT=db.example.internal,APP_ENV=production}'
sequenceDiagram participant Dev as Entwickler participant Lambda as Lambda Service participant KMS as AWS KMS participant Role as Ausführungsrolle Dev->>Lambda: update-function-configuration
--kms-key-arn Lambda->>KMS: kms:Encrypt (Variablen verschlüsseln) KMS-->>Lambda: Verschlüsselte Variablen Lambda-->>Dev: Konfiguration gespeichert Note over Lambda,KMS: Beim Kaltstart Lambda->>Role: Identität annehmen Lambda->>KMS: kms:Decrypt (mit Ausführungsrolle) alt Berechtigung vorhanden KMS-->>Lambda: Entschlüsselte Variablen Lambda->>Lambda: OS-Env injizieren else AccessDenied KMS-->>Lambda: AccessDeniedException Lambda-->>Lambda: Kaltstart schlägt fehl end
  1. Lambda-Konfiguration: Der CMK-ARN wird in der Funktionskonfiguration gespeichert.
  2. Verschlüsselung: Lambda ruft kms:Encrypt auf, um die Variablen zu verschlüsseln — dieser Aufruf erfolgt unter der Identität des aufrufenden Principals.
  3. Entschlüsselung beim Start: Lambda ruft kms:Decrypt mit der Ausführungsrolle auf. Fehlt die Berechtigung, schlägt der Kaltstart fehl.
  4. CloudTrail-Audit: Jeder kms:Decrypt-Aufruf erscheint im CloudTrail-Log mit der Funktions-ARN als Aufrufer-Identität.

Variablen zur Laufzeit lesen

Lambda macht die Variablen als Standard-OS-Umgebungsvariablen verfügbar. Kein SDK-Aufruf nötig — einfache Laufzeit-APIs reichen:

Python:

import os

def handler(event, context):
    db_endpoint = os.environ['DB_ENDPOINT']
    app_env = os.environ.get('APP_ENV', 'development')  # mit Fallback
    # ...

Node.js:

exports.handler = async (event) => {
    const dbEndpoint = process.env.DB_ENDPOINT;
    const appEnv = process.env.APP_ENV || 'development';
    // ...
};

Java:

String dbEndpoint = System.getenv("DB_ENDPOINT");

Environment Variables verhalten sich wie jede andere OS-Umgebungsvariable im Prozess. Der Unterschied zu einem normalen Server: Der Execution Context kann zwischen Aufrufen eingefroren und wiederverwendet werden. Variablen, die du außerhalb des Handlers initialisierst, werden beim Warm-Start nicht neu geladen — das ist ein Feature, kein Bug.

Fehlerbild aus der Praxis: Kaltstart schlägt fehl ohne klare Fehlermeldung

Ein typisches Fehlerbild: Du konfigurierst einen CMK, deployest die Funktion, und beim ersten Aufruf kommt ein generischer Fehler zurück — kein Stack-Trace, kein klarer Hinweis auf KMS. CloudWatch Logs zeigen nur Runtime exited with error: signal: killed oder eine knappe Timeout-Meldung.

Die erste Annahme ist meistens: Code-Fehler, falscher Handler-Pfad, zu wenig Memory. Alle drei falsch.

Der tatsächliche Grund: Die Ausführungsrolle hat keine kms:Decrypt-Berechtigung auf dem CMK. Lambda versucht beim Kaltstart die Variablen zu entschlüsseln, schlägt fehl, und der Execution Context startet nie vollständig. Die Fehlermeldung landet nicht im Handler-Log, weil der Handler nie aufgerufen wurde.

Diagnose über CloudTrail — nicht über CloudWatch:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=Decrypt \
  --start-time 2024-01-15T10:00:00Z \
  --end-time 2024-01-15T10:30:00Z

Dort siehst du einen AccessDenied-Eintrag mit dem genauen Principal und dem betroffenen Schlüssel. Das ist der eigentliche Fehler — CloudWatch zeigt nur das Symptom.

Fix: kms:Decrypt in der Ausführungsrolle ergänzen (siehe Schritt 2 oben) und sicherstellen, dass die KMS-Schlüsselrichtlinie die Rolle nicht explizit ablehnt. Ein Deny in der Schlüsselrichtlinie überschreibt jede IAM-Allow-Regel.

Wann Environment Variables nicht ausreichen

Environment Variables sind für Konfigurationswerte gedacht, nicht für hochsensible Credentials wie Passwörter oder API-Tokens. Für solche Werte ist AWS Secrets Manager oder AWS Systems Manager Parameter Store (SecureString) die bessere Wahl — beide bieten automatische Rotation, feinere Zugriffssteuerung und Audit-Trails auf Wertebene.

Der praktische Unterschied: Mit Environment Variables liegt der entschlüsselte Wert im Speicher des Execution Context und ist über os.environ abrufbar. Mit Secrets Manager rufst du den Wert explizit zur Laufzeit ab — du hast Kontrolle darüber, wann und wie oft der Wert gelesen wird, und kannst Rotation ohne Funktions-Redeployment durchführen.

Zusammenfassung und nächste Schritte mit Lambda Environment Variables

Lambda Environment Variables sind der richtige Weg für Konfigurationswerte wie Datenbankendpunkte, Feature-Flags und Umgebungsbezeichner. Die Standard-Verschlüsselung mit dem AWS-verwalteten Schlüssel ist für die meisten Anwendungsfälle ausreichend. Sobald du Schlüsselkontrolle, CloudTrail-Nachvollziehbarkeit oder Compliance-Anforderungen hast, wechselst du auf einen kundenverwalteten CMK — und stellst sicher, dass die Ausführungsrolle kms:Decrypt besitzt, bevor du deployest.

Glossar

Begriff Bedeutung
CMK (Customer Managed Key) Kundenverwalteter KMS-Schlüssel — du kontrollierst Richtlinie, Rotation und Zugriff
Execution Context Die Laufzeitumgebung einer Lambda-Funktion — wird bei Warm-Starts wiederverwendet
Kaltstart (Cold Start) Erster Start eines neuen Execution Context — beinhaltet Initialisierung und Entschlüsselung der Variablen
Ausführungsrolle IAM-Rolle, die Lambda beim Ausführen der Funktion annimmt — bestimmt alle API-Berechtigungen
CloudTrail AWS-Audit-Log für API-Aufrufe — einzige zuverlässige Quelle für KMS-Zugriffsfehler bei Lambda-Kaltstarts

Kommentare

Beliebte Posts aus diesem Blog

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

EC2 SSH Verbindungs-Timeout: Security Group Inbound-Regeln richtig konfigurieren