Was in GitLab bleibt — und was nicht
Jeder Magento-Deploy arbeitet mit sensiblen Daten: SSH-Keys, Datenbank-Passwörtern, Composer-Auth-Tokens, Redis-Verbindungen und API-Keys. Die Frage, wo diese Secrets gespeichert werden, entscheidet darüber, wie angreifbar ein Deployment-Prozess im Störfall ist. GitLab CI/CD-Variablen sind ein praktischer Ausgangspunkt — aber nicht für alle Secrets die beste Wahl.
Inhaltsverzeichnis
- 1. Welche Secrets hat ein Magento-Deployment?
- 2. Was in GitLab-CI/CD-Variablen sinnvoll ist
- 3. Protected, Masked und Environment-Scope richtig einsetzen
- 4. env.php: die sensible Datei im Shared-Verzeichnis
- 5. Composer-Auth und private Repositories
- 6. Was extern liegen sollte: HashiCorp Vault und Alternativen
- 7. Vollständige Variablen-Struktur für Magento-Deployments
- 8. Vergleich der Secret-Speicherorte
- 9. Typische Fehler im Secrets Management
- 10. Zusammenfassung
- 11. FAQ
1. Welche Secrets hat ein Magento-Deployment?
Ein typisches Magento-Deployment arbeitet mit einer überraschend großen Anzahl sensibler Daten aus verschiedenen Kategorien. In der ersten Kategorie liegen Verbindungsdaten: Datenbank-Host, Datenbank-Name, Benutzername und Passwort, Redis-Connection-String, RabbitMQ-Credentials und OpenSearch-Konfiguration. Diese Daten fließen in die env.php und müssen auf dem Produktionsserver vorhanden sein, aber sie müssen nie durch die CI/CD-Pipeline hindurch — wenn die Datei bereits auf dem Server im Shared-Verzeichnis liegt.
In der zweiten Kategorie liegen Deployment-Credentials: SSH-Private-Key für den Zugang zum Produktionsserver, SSH-Known-Hosts für Fingerprint-Verifikation, Deploy-User und Deploy-Host. Diese werden nur während des Deploy-Jobs benötigt und sollten daher in GitLab-Variablen mit Protection auf Production-Branch gespeichert sein. In der dritten Kategorie liegen Build-Credentials: Composer-Auth-Token für private Repositories (Adobe Commerce, Hyvä), NPM-Token für private Packages, Magento-Marketplace-Zugangsdaten. Diese werden nur im Build-Job benötigt und sollten ebenfalls in GitLab-Variablen, aber nicht notwendigerweise mit Production-Scoping gespeichert werden.
Die wichtigste Erkenntnis: Nicht alle Secrets gehören in dieselbe Kategorie und damit nicht an denselben Ort. Datenbank-Passwörter, die nie durch die Pipeline fließen müssen, sollten auch nicht in GitLab gespeichert werden. Das minimiert die Angriffsfläche: Ein kompromittierter GitLab-Account gibt keinen Zugang zur Production-Datenbank, wenn das Datenbank-Passwort dort nie gespeichert war.
2. Was in GitLab-CI/CD-Variablen sinnvoll ist
GitLab-CI/CD-Variablen sind für Secrets geeignet, die aktiv durch die Pipeline hindurch müssen — also zur Laufzeit eines Jobs als Umgebungsvariable benötigt werden. Der SSH-Private-Key ist ein klassisches Beispiel: Der Deploy-Job braucht ihn, um eine SSH-Verbindung zum Produktionsserver aufzubauen. Ohne den Key im Job gibt es keine Verbindung. Dasselbe gilt für Composer-Auth-Tokens: Der Build-Job führt composer install aus und braucht dafür den Auth-Token für private Repositories.
Was hingegen nicht durch die Pipeline fließen muss, sollte auch nicht in GitLab-Variablen landen. Das Datenbank-Passwort ist der häufigste Fehler in dieser Kategorie: Teams speichern es in GitLab, weil es praktisch erscheint, obwohl es ausschließlich auf dem Server in der env.php benötigt wird und der Deploy-Job es nie direkt verwendet. Wenn die env.php bereits im Shared-Verzeichnis des Servers liegt und der Deploy-Job nur einen Symlink setzt, braucht GitLab das Datenbank-Passwort nie zu sehen. Je weniger Secrets in GitLab gespeichert sind, desto geringer ist der Schaden bei einem kompromittierten GitLab-Account.
3. Protected, Masked und Environment-Scope richtig einsetzen
GitLab bietet drei unabhängige Schutzmechanismen für CI/CD-Variablen, die konsequent kombiniert werden sollten. Das Protected-Flag beschränkt die Sichtbarkeit einer Variable auf Jobs, die auf Protected Branches oder Protected Tags laufen. Ein Deploy-SSH-Key mit Protected-Flag ist in einem Feature-Branch-Job nicht sichtbar, selbst wenn der Branch denselben Job-Namen hat. Das verhindert, dass Entwickler durch Manipulation der .gitlab-ci.yml in einem Feature-Branch auf Production-Secrets zugreifen können.
Das Masked-Flag verhindert, dass der Wert der Variable in Job-Logs erscheint. Es ist kein vollständiger Schutz — der Wert ist im Job-Kontext weiterhin als Umgebungsvariable vorhanden und kann von Code ausgegeben werden, der nicht durch GitLab maskiert wird. Aber es verhindert versehentliches Leaken durch set -x in Shell-Scripts oder Debug-Ausgaben. Der Environment-Scope beschränkt eine Variable auf einen bestimmten Environment-Namen (production, staging). Staging-Datenbank-Credentials bekommen den Scope staging, Production-SSH-Keys den Scope production. So ist es strukturell unmöglich, dass ein Staging-Job Production-Credentials sieht oder umgekehrt.
4. env.php: die sensible Datei im Shared-Verzeichnis
Die env.php ist in Magento die zentrale Konfigurationsdatei, die Datenbankverbindung, Cache-Backend, Session-Storage, Kryptoschlüssel und weitere kritische Konfiguration enthält. Sie liegt im Shared-Verzeichnis des Release-Modells (/var/www/magento/shared/app/etc/env.php) und wird bei jedem Release per Symlink in das neue Release-Verzeichnis eingebunden. Das ist der korrekte Ansatz: Die Datei lebt auf dem Server und wird nie durch die Pipeline transportiert.
Ein verbreitetes Anti-Pattern ist es, die env.php aus GitLab-Variablen zur Laufzeit des Deploy-Jobs zu generieren. Das bedeutet, dass alle enthaltenen Credentials — Datenbank-Passwort, Redis-Passwort, Crypt-Key — in GitLab gespeichert sein müssen. Bei einem Backup des Servers kann die env.php ohne Passwörter gesichert werden, weil der Crypt-Key separat verwaltet wird; in der GitLab-Variante liegen alle Credentials dauerhaft in GitLab. Der bessere Ansatz: env.php einmalig manuell auf dem Server erstellen, im Shared-Verzeichnis ablegen und dann nie wieder durch die Pipeline anfassen. Updates an der env.php erfolgen direkt auf dem Server, nicht über CI/CD.
5. Composer-Auth und private Repositories
Magento-Projekte mit Adobe Commerce oder Hyvä-Theme brauchen Composer-Auth-Tokens für den Zugang zu privaten Repositories. Das COMPOSER_AUTH-Format in GitLab erlaubt die Übergabe von Zugangsdaten als JSON-String, den Composer als auth.json interpretiert. Diese Variable gehört in GitLab-CI/CD-Variablen mit Masked-Flag, weil sie aktiv im Build-Job benötigt wird und die Credentials dann im Build-Container vorübergehend existieren.
# .gitlab-ci.yml — Build stage with Composer auth injection
build:magento:
stage: build
image: php:8.4-cli
variables:
# COMPOSER_AUTH is a GitLab CI/CD variable (masked, protected for build scope)
# Format: {"http-basic":{"repo.magento.com":{"username":"...","password":"..."}}}
COMPOSER_HOME: "/tmp/composer"
script:
# Inject auth.json from COMPOSER_AUTH variable — never commit auth.json to Git
- mkdir -p "$COMPOSER_HOME"
- echo "$COMPOSER_AUTH" > "$COMPOSER_HOME/auth.json"
- composer install --no-dev --prefer-dist --no-interaction --no-progress
# Remove auth.json from artifact — credentials must not persist in artifact
- rm -f "$COMPOSER_HOME/auth.json"
artifacts:
paths:
- vendor/
- generated/
expire_in: 2 hours
cache:
key: "composer-${CI_COMMIT_REF_SLUG}"
paths:
- .cache/composer/
Wichtig: Die auth.json darf niemals als Build-Artefakt gespeichert werden. Nachdem composer install abgeschlossen ist, muss sie gelöscht werden, bevor das Artefakt erstellt wird. Ein Artefakt, das auth.json enthält, würde die Credentials potenziell an jeden weitergeben, der das Artefakt herunterladen kann — in GitLab können das alle Mitglieder des Projekts sein. Das rm -f vor dem Ende des Script-Blocks stellt sicher, dass die Datei nicht im Artefakt-Pfad liegt.
6. Was extern liegen sollte: HashiCorp Vault und Alternativen
Für Teams mit strengeren Compliance-Anforderungen oder für Credentials mit sehr hohem Schadenspotenzial bei Kompromittierung — zum Beispiel Private Keys für Code-Signing oder Master-Datenbank-Credentials — bieten externe Secret-Management-Systeme wie HashiCorp Vault, AWS Secrets Manager oder Azure Key Vault eine stärkere Isolation als GitLab-CI/CD-Variablen.
GitLab unterstützt die native Integration mit HashiCorp Vault über JWT-basierte Authentifizierung: Die Pipeline authentifiziert sich bei Vault mit einem kurzlebigen JWT-Token, das GitLab für jeden Job ausstellt. Vault verifiziert die Identität des Jobs anhand von Claims wie project_id, ref und environment_name und gibt nur die Secrets aus, für die der Job konfiguriert ist. Das Secret existiert dann nur für die Dauer des Jobs als Umgebungsvariable, wird nie dauerhaft in GitLab gespeichert und ist nach dem Job-Ende nicht mehr zugänglich.
7. Vollständige Variablen-Struktur für Magento-Deployments
Die folgende Übersicht zeigt, welche Variablen in welchem Scope und mit welchen Flags für ein typisches Magento-Deployment mit Staging und Production konfiguriert werden sollten. Sie folgt dem Prinzip des minimalen Zugangs: Jede Variable ist nur dort sichtbar, wo sie wirklich gebraucht wird.
# GitLab CI/CD Variables Configuration — Magento Deployment
# Settings > CI/CD > Variables
# --- Deployment Credentials ---
# SSH_PRIVATE_KEY: Protected, Masked, Scope: production
# Private key for SSH connection to production server
# SSH_KNOWN_HOSTS: Protected, Not Masked, Scope: production
# Content of known_hosts for production server fingerprint verification
# DEPLOY_USER: Protected, Not Masked, Scope: production
# Deploy user on production server (e.g., deploy)
# DEPLOY_HOST: Protected, Not Masked, Scope: production
# Hostname or IP of production server
# DEPLOY_PATH: Protected, Not Masked, Scope: production
# Base path on server (e.g., /var/www/magento)
# --- Staging Variants ---
# SSH_PRIVATE_KEY: Protected, Masked, Scope: staging
# SSH_KNOWN_HOSTS: Protected, Not Masked, Scope: staging
# DEPLOY_USER: Protected, Not Masked, Scope: staging
# DEPLOY_HOST: Protected, Not Masked, Scope: staging
# DEPLOY_PATH: Protected, Not Masked, Scope: staging
# --- Build Credentials ---
# COMPOSER_AUTH: Protected, Masked, Scope: *
# JSON string with Composer credentials for private repos
# MAGENTO_PUBLIC_KEY: Not Protected, Masked, Scope: *
# Magento Marketplace public key
# MAGENTO_PRIVATE_KEY: Not Protected, Masked, Scope: *
# Magento Marketplace private key (= COMPOSER_AUTH password)
# --- Pipeline Configuration ---
# RELEASE_RETENTION: Not Protected, Not Masked, Scope: *
# Number of old releases to keep (e.g., 5)
# GIT_STRATEGY: Not Protected, Not Masked, Scope: *
# fetch (reuse workspace) or clone (fresh clone per job)
Drei Prinzipien leiten diese Struktur: Erstens werden Production-SSH-Keys nur im Production-Scope gespeichert — kein Staging-Job kann sie sehen. Zweitens sind alle Credentials als Masked gespeichert, um versehentliches Logging zu verhindern. Drittens enthält GitLab keine Datenbank-Passwörter oder Crypt-Keys, weil diese in der env.php auf dem Server verwaltet werden und nie durch die Pipeline fließen müssen.
8. Vergleich der Secret-Speicherorte
Verschiedene Secrets haben unterschiedliche Sicherheitsanforderungen und unterschiedliche Nutzungsmuster in der Pipeline. Die richtige Wahl des Speicherorts ergibt sich aus der Kombination dieser Faktoren.
| Secret | GitLab Variablen | Server-Datei | Externer Vault |
|---|---|---|---|
| SSH Deploy-Key | Ja (Protected, Masked) | Nicht sinnvoll | Optional bei hoher Compliance |
| Datenbank-Passwort | Nein — nicht nötig | Ja (env.php) | Bei hoher Compliance |
| Composer-Auth-Token | Ja (Masked) | Alternativ auf Build-Server | Optional |
| Magento Crypt-Key | Nein — nie nötig | Ja (env.php) | Ja (empfohlen) |
| Redis-Passwort | Nein — nicht nötig | Ja (env.php) | Bei hoher Compliance |
Die Tabelle zeigt das wichtigste Prinzip: Secrets, die nicht durch die Pipeline fließen müssen, gehören nicht in GitLab. Datenbank-Passwort, Crypt-Key und Redis-Passwort werden ausschließlich von Magento auf dem Server benötigt — nicht vom CI/CD-Prozess. Die env.php im Shared-Verzeichnis ist der richtige Ort. Nur Secrets, die der CI/CD-Prozess aktiv zur Laufzeit braucht — SSH-Key, Composer-Auth — gehören in GitLab-Variablen, mit entsprechender Protection und Maskierung.
9. Typische Fehler im Secrets Management
Der verbreitetste Fehler ist das Speichern der vollständigen env.php in einer GitLab-Variable, um sie beim Deploy auf den Server zu schreiben. Das Ergebnis: alle Datenbankpasswörter, der Crypt-Key und alle weiteren Konfigurationswerte liegen dauerhaft in GitLab, sind über die API abrufbar (für Admins) und erscheinen potentiell in Job-Logs, wenn die Variable nicht korrekt maskiert ist. Die korrekte Alternative: env.php einmalig manuell auf dem Server anlegen und dann nur per Symlink einbinden.
Ein zweiter verbreiteter Fehler ist das Fehlen des Environment-Scopes bei Credentials. Wenn SSH_PRIVATE_KEY ohne Scope gespeichert ist, ist er in jedem Job sichtbar — auch in Jobs auf Feature-Branches, die keine Verbindung zum Produktionsserver brauchen. Ein dritter Fehler ist das Einchecken von auth.json oder .env-Dateien in das Git-Repository, auch wenn nur in einem vergangenen Commit. Git-History enthält diese Dateien dauerhaft und kann mit Tools wie git log -S 'password' durchsucht werden. Secret-Scanning-Tools wie GitGuardian oder das in GitLab eingebaute Secret Detection können solche Fälle automatisch erkennen — aber erst nach dem Einchecken.
10. Zusammenfassung
Gutes Secrets Management für Magento beginnt mit einer klaren Kategorisierung: Was muss durch die Pipeline fließen (SSH-Key, Composer-Auth), was lebt auf dem Server (env.php, Crypt-Key) und was sollte in einem externen Vault liegen (hochkritische Credentials bei Compliance-Anforderungen). Je weniger Secrets in GitLab gespeichert sind, desto kleiner ist die Angriffsfläche bei einem kompromittierten Account.
GitLab-Variablen, die in der Pipeline benötigt werden, müssen mit Protected-Flag (nur auf Protected Branches sichtbar), Masked-Flag (keine Log-Ausgabe) und Environment-Scope (nur im richtigen Environment sichtbar) konfiguriert sein. Die env.php lebt im Shared-Verzeichnis auf dem Server und wird nie durch die Pipeline transportiert. Composer-Auth-Tokens werden im Build-Job injiziert und vor der Artefakt-Erstellung gelöscht. Mit diesen Grundregeln entsteht ein Deployment-Prozess, dessen Secrets-Management auch einer Sicherheitsüberprüfung standhält.
Secrets Management für Magento — Das Wichtigste auf einen Blick
Minimales GitLab-Exposure
Nur Secrets in GitLab, die aktiv in der Pipeline benötigt werden. Datenbank-Passwörter und Crypt-Keys gehören nicht dorthin.
env.php auf dem Server
Einmalig manuell anlegen, im Shared-Verzeichnis ablegen. Deploy-Job setzt nur einen Symlink — kein Secret fließt durch die Pipeline.
Protected + Masked + Scope
Alle Pipeline-Credentials mit Protected-Flag, Masked und Environment-Scope. Kein Staging-Job sieht Production-SSH-Keys.
Composer-Auth-Cleanup
auth.json nach composer install löschen, bevor das Artefakt erstellt wird. Nie in Git einchecken, nie als Artefakt speichern.