Umgebungsvariablen in Docker meistern: Konfiguration vs. Geheimnisse

Erschließen Sie sichere und flexible Docker-Deployments durch die Beherrschung von Umgebungsvariablen. Dieser umfassende Leitfaden klärt den entscheidenden Unterschied zwischen der Nutzung von Umgebungsvariablen für die allgemeine Anwendungskonfiguration und der sicheren Verwaltung sensibler Daten wie API-Schlüssel und Passwörter. Lernen Sie praktische Methoden zur Übergabe nicht-sensibler Einstellungen kennen, verstehen Sie die schwerwiegenden Risiken der Preisgabe von Secrets über Umgebungsvariablen und entdecken Sie, wie Sie Docker Secrets und Compose für ein robustes, verschlüsseltes Secret-Management einsetzen können. Erweitern Sie Ihr Docker-Wissen und schützen Sie Ihre Anwendungen.

33 Aufrufe

Mastering Environment Variables in Docker: Konfiguration vs. Secrets meistern

Docker hat die Art und Weise, wie Anwendungen erstellt, ausgeliefert und ausgeführt werden, revolutioniert und bietet eine konsistente Umgebung über verschiedene Entwicklungsphasen hinweg. Ein grundlegender Aspekt bei der Verwaltung containerisierter Anwendungen ist deren Konfiguration, und Umgebungsvariablen sind ein primärer Mechanismus hierfür. Allerdings ist nicht jede Information gleichwertig; einige Konfigurationen sind harmlos, während andere Informationen, wie API-Schlüssel oder Datenbankanmeldeinformationen, hochsensibel sind. Werden diese beiden Kategorien verwechselt, kann dies zu erheblichen Sicherheitslücken führen.

Dieser Artikel befasst sich mit dem kritischen Unterschied zwischen der Verwendung von Umgebungsvariablen für allgemeine Konfigurationen und den geeigneten, sicheren Methoden zur Verwaltung sensibler Daten, die üblicherweise als „Secrets“ (Geheimnisse) bezeichnet werden. Wir werden die verschiedenen Möglichkeiten untersuchen, Konfigurationen an Ihre Docker-Container zu übergeben, die inhärenten Risiken hervorheben, wenn Secrets als gewöhnliche Umgebungsvariablen behandelt werden, und die dedizierten Lösungen von Docker für die sichere Verwaltung von Secrets vorstellen. Am Ende werden Sie ein klares Verständnis davon haben, wann und wie Sie jeden Ansatz anwenden sollten, um sicherzustellen, dass Ihre Anwendungen sowohl flexibel als auch sicher sind.

Verständnis von Umgebungsvariablen für die Konfiguration

Umgebungsvariablen sind eine unkomplizierte und weit verbreitete Methode, um Laufzeitkonfigurationen an Anwendungen zu übergeben, einschließlich solcher, die in Docker-Containern laufen. Sie ermöglichen es Ihnen, das Verhalten einer Anwendung zu ändern, ohne das Docker-Image neu erstellen zu müssen, was Ihre Container flexibler und portabler macht. Dies ist ideal für nicht-sensible, dynamische Einstellungen wie Anwendungsportnummern, Debug-Flags oder URLs von Drittanbieterdiensten.

Methoden zur Übergabe von Konfigurationsvariablen

Docker bietet mehrere Möglichkeiten, Umgebungsvariablen in Ihren Containern festzulegen und einzuspeisen:

1. ENV-Anweisung in der Dockerfile

Die ENV-Anweisung legt eine Standard-Umgebungsvariable fest, die im Container verfügbar ist, wenn er ausgeführt wird. Dies eignet sich für Variablen, die sich wahrscheinlich nicht ändern, oder um sinnvolle Standardwerte für Ihre Anwendung bereitzustellen.

FROM alpine:latest

ENV APP_PORT=8080
ENV DEBUG_MODE=false

COPY ./app /app
WORKDIR /app
CMD ["/app/start.sh"]

Tipp: Obwohl ENV Standardwerte festlegt, können diese zur Laufzeit überschrieben werden.

2. -e oder --env-Flag mit docker run

Beim Starten eines einzelnen Containers können Sie das -e oder --env-Flag verwenden, um Umgebungsvariablen direkt zu übergeben. Dies ist üblich für Ad-hoc-Tests oder um spezifische Einstellungen bereitzustellen, die von den Dockerfile-Standardwerten abweichen.

docker run -d -p 80:8080 --name my_app_instance \n  -e APP_PORT=80 \n  -e DEBUG_MODE=true \n  my_app_image:latest

3. env_file in Docker Compose

Für die Verwaltung mehrerer Umgebungsvariablen, insbesondere über mehrere Dienste hinweg, die in einer docker-compose.yml-Datei definiert sind, ist die Option env_file sehr praktisch. Sie ermöglicht das Laden von Variablen aus einer oder mehreren .env-Dateien, wodurch Ihre docker-compose.yml übersichtlicher bleibt.

docker-compose.yml:

version: '3.8'
services:
  webapp:
    image: my_app_image:latest
    ports:
      - "80:8080"
    env_file:
      - ./config/app.env

./config/app.env:

APP_PORT=8080
DEBUG_MODE=false
API_ENDPOINT=https://api.example.com/v1

4. environment-Schlüssel in Docker Compose

Alternativ können Sie Umgebungsvariablen direkt im Abschnitt environment eines Dienstes in docker-compose.yml definieren. Dies wird oft für eine geringe Anzahl von Variablen oder für Variablen bevorzugt, die für einen einzelnen Dienst spezifisch sind.

version: '3.8'
services:
  webapp:
    image: my_app_image:latest
    ports:
      - "80:8080"
    environment:
      APP_PORT: 8080
      DEBUG_MODE: false

Die Tücken bei der Verwendung von Umgebungsvariablen für Secrets

Obwohl Umgebungsvariablen hervorragend für die Konfiguration geeignet sind, sind sie grundsätzlich nicht sicher für die Verwaltung sensibler Daten (Secrets) wie Datenbankpasswörter, API-Schlüssel oder private SSH-Schlüssel. Dies ist eine kritische Sicherheitslücke, die oft übersehen wird, insbesondere in Entwicklungsumgebungen.

Warum Umgebungsvariablen unsicher für Secrets sind:

  1. Sichtbarkeit über docker inspect: Jeder, der Zugriff auf den Docker-Host hat, kann die Umgebungsvariablen eines laufenden Containers mithilfe von docker inspect <container_id> leicht einsehen. Das bedeutet, dass Ihre Secrets im Klartext sichtbar sind.

    ```bash

    Beispiel für die Offenlegung eines Secrets (BITTE NICHT IN DER PRODUKTION TUN)

    docker run -d -e DB_PASSWORD=mysecretpassword --name insecure_app nginx:latest

    Jeder kann das Passwort sehen

    docker inspect insecure_app | grep DB_PASSWORD
    ```

  2. Prozess-Schnüffeln (Process Snooping): Innerhalb des Containers können andere Prozesse oder Benutzer (falls mehrere Benutzer existieren) Umgebungsvariablen lesen, insbesondere wenn die Anwendung als Root oder mit erhöhten Rechten ausgeführt wird.

  3. Protokollierung und Verlauf: Umgebungsvariablen können versehentlich in Protokolle, CI/CD-Pipeline-Verläufe oder die Shell-Historie gelangen, was zu unbeabsichtigter Offenlegung führt.

  4. Image-Schichten (Image Layers): Wenn Sie ENV in einer Dockerfile mit einem Secret verwenden, wird dieses Secret in eine Image-Schicht eingebettet und bleibt dort, selbst wenn Sie versuchen, es in einer späteren Schicht mit unset zu entfernen. Dies macht das Secret aus dem Image selbst abrufbar.

  5. Versehentliches Teilen: .env-Dateien oder docker-compose.yml-Dateien, die Secrets enthalten, werden oft versehentlich in Versionskontrollsysteme eingecheckt oder unangemessen geteilt, was zu einer weitreichenden Offenlegung führt.

Warnung: Die Behandlung sensibler Informationen als reguläre Umgebungsvariablen ist ein häufiger Sicherheitsfehler. Gehen Sie immer davon aus, dass Umgebungsvariablen auf dem Host und innerhalb des Containers öffentlich sichtbar sind.

Sichere Verwaltung von Secrets in Docker

Um die Sicherheitsmängel von Umgebungsvariablen für sensible Daten zu beheben, bietet Docker spezielle Funktionen zur Secret-Verwaltung, hauptsächlich über Docker Secrets (für Docker Swarm) und externe Tools wie Docker Compose mit der secrets-Funktionalität (die Docker Swarm Secrets nutzen oder einfach Dateien einbinden kann).

Docker Secrets (Docker Swarm Mode)

Docker Secrets ist eine in den Docker Swarm-Modus integrierte Funktion, die eine sichere Möglichkeit bietet, sensible Daten an Dienste zu übermitteln und zu speichern. Secrets sind:

  • Im Ruhezustand in den Raft-Protokollen des Swarm-Managers verschlüsselt.
  • Sicher an autorisierte Dienstaufgaben übermittelt.
  • Als im Speicher befindliche Dateien in das Dateisystem des Containers eingebunden, typischerweise unter /run/secrets/<secret_name>, anstatt als Umgebungsvariablen freigegeben zu werden.
  • Nur für Dienste zugänglich, denen explizit Zugriff gewährt wurde.

Verwendung von Docker Secrets (Swarm-Modus)

  1. Swarm initialisieren (falls noch nicht geschehen):
    bash docker swarm init

  2. Ein Secret erstellen: Secrets werden aus einer Datei oder der Standardeingabe erstellt.
    bash echo "my_secure_db_password" | docker secret create db_password_secret - echo "SG.your_api_key_here" | docker secret create sendgrid_api_key -

  3. Einen Dienst mit dem Secret bereitstellen: Dienste referenzieren Secrets anhand ihres Namens. Docker bindet das Secret in den Container ein.
    bash docker service create --name my-webapp \n --secret db_password_secret \n --secret sendgrid_api_key \n my_app_image:latest

  4. Zugriff auf Secrets im Container: Anwendungen lesen das Secret aus dem eingebundenen Dateipfad.
    ```python

In Ihrem Python-Anwendungscode (oder ähnlich für andere Sprachen)

with open('/run/secrets/db_password_secret', 'r') as f:
db_password = f.read().strip()

with open('/run/secrets/sendgrid_api_key', 'r') as f:
sendgrid_key = f.read().strip()
```

Docker Compose und Secrets (für Einzelhost oder Swarm)

Docker Compose Version 3.1+ führte einen secrets-Abschnitt ein, mit dem Sie Secrets in Ihrer docker-compose.yml definieren und darauf verweisen können. Wenn Compose im Swarm-Modus ausgeführt wird, nutzt es die nativen Secrets von Docker Swarm. Wenn es auf einem Einzelhost ohne Swarm-Modus ausgeführt wird, unterstützt Compose Secrets weiterhin, indem es Dateien vom Host sicher in den Container einbindet, allerdings ohne die Verschlüsselung im Ruhezustand, die Swarm bietet.

Verwendung von secrets in docker-compose.yml

  1. Secrets definieren: Sie können Secrets entweder definieren, indem Sie auf eine externe Datei verweisen, oder indem Sie es zu einem externen Secret machen (einem bereits erstellten Swarm Secret).

    ```yaml

    docker-compose.yml

    version: '3.8'

    services:
    webapp:
    image: my_app_image:latest
    ports:
    - "80:8080"
    secrets:
    - db_password
    - sendgrid_api_key

    secrets:
    db_password:
    file: ./secrets/db_password.txt # Pfad zu einer Datei auf dem Host, die das Passwort enthält
    sendgrid_api_key:
    external: true # Verweist auf ein bereits existierendes Docker Swarm Secret namens 'sendgrid_api_key'
    ```

  2. Lokale Secret-Dateien erstellen (wenn file verwendet wird):
    bash mkdir secrets echo "my_local_db_password" > ./secrets/db_password.txt

  3. Mit Compose bereitstellen: docker compose up -d stellt Ihre Dienste bereit und macht Secrets im Container unter /run/secrets/<secret_name> verfügbar.

    ```bash

    Im Container befindet sich der Inhalt von ./secrets/db_password.txt unter:

    /run/secrets/db_password

    ```

Das richtige Werkzeug wählen: Konfiguration vs. Secrets

Die Entscheidung, ob eine Umgebungsvariable für die Konfiguration oder eine dedizierte Secret-Management-Lösung verwendet werden soll, hängt von einer primären Frage ab:

Sind die Daten sensibel?

  • Wenn Ja (sensible Daten): Verwenden Sie Docker Secrets (mit Swarm) oder ein ähnliches Secret-Management-System (z. B. Kubernetes Secrets, HashiCorp Vault). Für Compose-Setups auf einem Einzelhost verwenden Sie den secrets-Abschnitt, um Dateien sicher einzubinden.
  • Wenn Nein (nicht-sensible Konfiguration): Verwenden Sie Umgebungsvariablen (über ENV in Dockerfile, -e-Flag, env_file oder environment in Compose).
Merkmal Umgebungsvariablen (für Konfiguration) Docker Secrets (für sensible Daten)
Zweck Nicht-sensible Anwendungskonfiguration Sensible Daten (Passwörter, API-Schlüssel)
Sicherheit Unsicher für sensible Daten Verschlüsselte, sichere Übertragung & Speicherung
Zugriff in App Aus os.environ gelesen (oder ähnlich) Aus /run/secrets/<secret_name> Datei gelesen
Verwaltet durch Docker-Laufzeit, Docker Compose Docker Swarm, Docker Compose

Best Practices für beides

Für Konfiguration (Umgebungsvariablen):

  • Stellen Sie sinnvolle Standardwerte in Ihrer Dockerfile mithilfe von ENV bereit. Dies macht Ihre Images „out of the box“ ausführbar und dokumentiert erwartete Variablen klar.
  • Externalisieren Sie Konfigurationen, wo immer möglich. Verwenden Sie .env-Dateien mit docker compose oder externe Konfigurationsdienste für größere Bereitstellungen.
  • Dokumentieren Sie alle Konfigurationsoptionen und ihre erwarteten Werte, möglicherweise in einer README.md oder der Anwendungsdokumentation.
  • Vermeiden Sie das Hardcodieren von Werten, die sich zwischen Umgebungen (Entwicklung, Staging, Produktion) ändern könnten.

Für Secrets (Docker Secrets und darüber hinaus):

  • Committen Sie niemals Secrets (z. B. .env-Dateien mit Secrets, db_password.txt) in Versionskontrollsysteme wie Git.
  • Rotieren Sie Secrets regelmäßig. Dies minimiert das Expositionsfenster, falls ein Secret kompromittiert wird.
  • Gewähren Sie das geringstmögliche Privileg. Geben Sie Diensten nur Zugriff auf die Secrets, die sie unbedingt benötigen.
  • Vermeiden Sie das Protokollieren von Secret-Werten. Stellen Sie sicher, dass Ihre Anwendungs- und Infrastrukturprotokollierung die Secret-Inhalte nicht ausgibt.
  • Erwägen Sie für groß angelegte, Enterprise-taugliche Bereitstellungen dedizierte Secret-Management-Lösungen wie HashiCorp Vault, AWS Secrets Manager oder Azure Key Vault, die erweiterte Funktionen wie Auditing, dynamische Secret-Generierung und Integration mit Identity and Access Management (IAM) bieten.

Fazit

Die Beherrschung von Umgebungsvariablen in Docker bedeutet mehr, als nur zu wissen, wie man sie übergibt – es bedeutet, den grundlegenden Unterschied zwischen generischer Konfiguration und sensiblen Secrets zu verstehen. Während Umgebungsvariablen eine unübertroffene Flexibilität für die Anwendungskonfiguration bieten, sind sie für sensible Daten von Natur aus unsicher.

Durch die Nutzung von Docker Secrets für sensible Informationen in einer Swarm-Umgebung oder durch die sorgfältige Verwendung der secrets-Funktion von Docker Compose für Einzelhost-Bereitstellungen können Sie die Sicherheitslage Ihrer containerisierten Anwendungen erheblich verbessern. Priorisieren Sie immer die Sicherheit, indem Sie das richtige Werkzeug für die jeweilige Aufgabe verwenden, Best Practices befolgen und sicherstellen, dass Ihre sensiblen Daten vor versehentlicher Offenlegung geschützt bleiben. Dieser disziplinierte Ansatz führt zu robusteren, wartbareren und sichereren Docker-Bereitstellungen.