Sensible Daten in Magento-Projekten aus Git heraushalten
git
HEAD
Git · Sicherheit · Magento 2 · Secrets Management
Sensible Daten in Magento-Projekten aus Git heraushalten
env.php, auth.json und Secrets sicher verwalten

Ein einziger versehentlicher Commit mit Datenbank-Zugangsdaten oder dem Crypt Key aus app/etc/env.php kann ein komplettes Magento-Projekt kompromittieren, selbst wenn das Repository später wieder privat gesetzt wird. Dieser Artikel zeigt, welche Dateien niemals in Git landen dürfen, wie eine saubere gitignore Baseline aussieht und wie Secrets Manager sowie Pre Commit Scanning das zuverlässig verhindern.

14 Min. Lesezeit env.php · auth.json · .gitignore Secrets Manager · Pre-Commit-Hooks · gitleaks

1. Warum sensible Daten in Magento-Projekten besonders gefährdet sind

Ein Magento-Projekt besteht nicht nur aus Anwendungscode, sondern auch aus generierten Konfigurationsdateien, die während der Installation automatisch erzeugt werden. Die Datei app/etc/env.php entsteht bei jedem setup:install und enthält Datenbank-Zugangsdaten, den Crypt Key sowie Cache- und Session-Backend-Konfiguration. Weil diese Datei im normalen app/etc-Verzeichnis liegt, direkt neben versionierten Konfigurationsdateien wie config.php, wird sie in der Praxis erschreckend häufig aus Versehen mitcommittet, besonders bei einem schnellen git add -A ohne vorherige Prüfung.

Magento-Repositories werden zudem oft mit mehreren Beteiligten geteilt: Agenturen, freiberuflichen Entwicklern, CI-Runnern und manchmal sogar öffentlichen GitHub-Forks für Showcases. Automatisierte Scanner durchsuchen öffentliche Repositories gezielt nach bekannten Mustern wie Magento-Crypt-Keys oder Composer-auth.json-Tokens, oft innerhalb von Minuten nach einem Push. Einmal in die Git-Historie gelangt, bleibt ein Secret auch nach dem Löschen in einem späteren Commit über git log, git blame und jeden bereits gezogenen Clone erreichbar. Genau deshalb ist Prävention hier wirkungsvoller als nachträgliches Aufräumen.

2. Was niemals in ein Magento-Repository committet werden darf

Fünf Kategorien sensibler Daten tauchen in Magento-Projekten regelmäßig versehentlich in Commits auf. Erstens app/etc/env.php mit Datenbank-Credentials und Crypt Key. Zweitens auth.json mit den Composer-Zugangsdaten für repo.magento.com und das Magento Marketplace. Drittens .env-Dateien, die in Docker-Setups oder Deployment-Skripten echte Zugangsdaten für Datenbanken, Redis oder Elasticsearch enthalten. Viertens private Schlüssel und Zertifikate, etwa SSH-Deploy-Keys oder SSL-Zertifikate für lokale HTTPS-Entwicklung. Fünftens hartcodierte API-Tokens in di.xml, ViewModels oder Cron-Jobs, etwa für Zahlungsanbieter, Versanddienste oder externe APIs.

Der Crypt Key verdient besondere Aufmerksamkeit: Magento nutzt ihn, um sensible Werte in core_config_data zu verschlüsseln, etwa gespeicherte API-Zugangsdaten von Zahlungsmodulen. Wer sowohl den Crypt Key als auch einen Datenbank-Dump in die Hände bekommt, egal ob durch ein geleaktes Repository oder ein Backup, kann diese Werte vollständig entschlüsseln. Ein geleakter Crypt Key ist deshalb kein theoretisches Risiko, sondern öffnet direkt den Weg zu Zahlungsintegrationen und weiteren Drittanbieter-Zugängen im Shop.

3. app/etc/env.php im Detail: Datenbank-Credentials und Crypt Key

env.php wird von bin/magento setup:install automatisch generiert und enthält unter anderem den Block db mit Host, Benutzername und Passwort im Klartext, den crypt-Block mit dem Crypt Key sowie Konfiguration für Session- und Cache-Backends wie Redis. Da diese Datei umgebungsspezifisch ist und sich zwischen Entwicklung, Staging und Produktion unterscheidet, gehört sie grundsätzlich nicht ins Repository, unabhängig davon, ob das Repository privat oder öffentlich ist.

Das etablierte Pattern: Statt env.php zu versionieren, wird eine env.php.dist oder env.php.example mit Platzhaltern statt echten Werten eingecheckt. Jede Umgebung generiert ihre eigene env.php lokal oder während der Deployment-Pipeline, entweder durch erneutes setup:install oder durch ein Skript, das Platzhalter durch Werte aus Umgebungsvariablen ersetzt. Bei Magento Cloud übernimmt die Plattform diesen Schritt automatisch über die MAGENTO_CLOUD_RELATIONSHIPS-Umgebungsvariable, sodass Entwickler nie eine echte env.php in die Hand bekommen müssen.

4. auth.json: Zugangsdaten für Magento Marketplace und repo.magento.com

Composer benötigt für Magento-Projekte eine Authentifizierung gegenüber repo.magento.com, um kommerzielle Erweiterungen und den Magento-Core über den http-basic-Mechanismus herunterzuladen. Diese Zugangsdaten, Public Key und Private Key aus dem Magento-Marketplace-Account, landen standardmäßig in einer Datei namens auth.json im Projekt-Root, direkt neben composer.json. Genau dort werden sie von Entwicklern regelmäßig versehentlich mitcommittet, weil sie wie eine gewöhnliche Konfigurationsdatei aussieht.

Ein geleakter auth.json-Schlüssel erlaubt es Angreifern, im Namen des Accounts kostenpflichtige Erweiterungen zu installieren oder Download-Kontingente zu erschöpfen. Der sichere Weg: auth.json global außerhalb des Projekts in COMPOSER_HOME (üblicherweise ~/.composer/auth.json) ablegen, statt projektbezogen. In CI/CD-Pipelines wird die Datei stattdessen zur Laufzeit aus einem Secret-Store injiziert, etwa über composer config --global http-basic.repo.magento.com mit Werten aus maskierten Pipeline-Variablen, sodass sie nie im Dateisystem des Repositories existiert.

5. Eine praxistaugliche .gitignore-Baseline für Magento 2

Eine korrekte .gitignore für Magento 2 muss deutlich mehr abdecken als nur env.php. Generierte und temporäre Verzeichnisse wie var/, generated/, pub/static/ und der Großteil von pub/media/ (mit Ausnahme versionierter Platzhalterbilder) gehören ebenso ausgeschlossen wie vendor/ und node_modules/, weil beide über Composer beziehungsweise npm reproduzierbar sind und das Repository unnötig aufblähen würden. IDE-Verzeichnisse wie .idea/ und .vscode/ sind projektspezifisch und haben in einem geteilten Repository ebenfalls nichts verloren.

Der folgende Ausschnitt zeigt eine Baseline, die sich in den meisten Magento-2-Projekten direkt einsetzen lässt und bei Bedarf um projektspezifische Verzeichnisse wie Custom-Log-Pfade erweitert wird. Wichtig ist, .gitignore-Regeln bereits beim Projekt-Setup zu committen, bevor der erste setup:install-Lauf env.php und generated/ überhaupt erzeugt, sonst landen diese Dateien womöglich schon im ersten Commit.


# .gitignore: Magento 2 baseline - never commit generated files or secrets

# Sensitive configuration - contains DB credentials and the crypt key
/app/etc/env.php
/app/etc/config.local.php

# Composer authentication for repo.magento.com / Magento Marketplace
/auth.json

# Environment files with real secrets (keep only .env.example versioned)
.env
.env.*
!.env.example

# Generated and cached application code
/generated/
/var/
/pub/static/
/pub/media/*
!/pub/media/.htaccess

# Dependencies (reproducible via composer/npm, do not version)
/vendor/
/node_modules/

# Private keys and certificates
*.pem
*.key
*.crt
id_rsa*

# IDE and editor directories
/.idea/
/.vscode/

# OS artifacts
.DS_Store
Thumbs.db

6. Umgebungsvariablen statt hartcodierter Konfiguration

Statt Zugangsdaten fest in env.php oder Modul-Konfiguration zu schreiben, liest man sie zur Laufzeit über getenv() oder $_ENV aus Umgebungsvariablen, die pro Umgebung unterschiedlich gesetzt werden, ohne dass sich der Code ändert. Dieses Pattern trennt Konfiguration konsequent von Code, ein Prinzip, das auch die Twelve-Factor-App-Methodik als Grundregel für portable Anwendungen definiert. Auf Magento Cloud übernehmen die automatisch bereitgestellten MAGENTO_CLOUD_*-Variablen genau diese Rolle für Datenbank- und Cache-Zugänge.

In selbst gehosteten Umgebungen lässt sich derselbe Ansatz mit einem kleinen Wrapper-Skript nachbauen, das env.php beim Deployment aus einer Vorlage generiert und dabei Platzhalter durch Werte aus der Prozessumgebung ersetzt. Wichtig dabei: Die Umgebungsvariablen selbst dürfen nicht in Deployment-Skripten oder Dockerfiles im Klartext stehen, sondern müssen aus einem geschützten Bereich stammen, etwa den Secrets eines CI/CD-Systems oder einem Secrets Manager, sonst verlagert man das Problem nur von einer Datei in die nächste.


<?php
/**
 * bin/generate-env.php - build app/etc/env.php from environment variables.
 * Never commit the real env.php; this script runs during deployment only.
 */
declare(strict_types=1);

$required = ['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASSWORD', 'CRYPT_KEY'];
foreach ($required as $var) {
    if (getenv($var) === false) {
        fwrite(STDERR, "Missing required environment variable: {$var}\n");
        exit(1);
    }
}

$config = [
    'db' => [
        'connection' => [
            'default' => [
                'host' => getenv('DB_HOST'),
                'dbname' => getenv('DB_NAME'),
                'username' => getenv('DB_USER'),
                'password' => getenv('DB_PASSWORD'),
            ],
        ],
    ],
    'crypt' => [
        'key' => getenv('CRYPT_KEY'),
    ],
    'cache' => [
        'frontend' => [
            'default' => [
                'backend' => 'Cm_Cache_Backend_Redis',
                'backend_options' => [
                    'server' => getenv('REDIS_HOST') ?: '127.0.0.1',
                    'port' => getenv('REDIS_PORT') ?: '6379',
                ],
            ],
        ],
    ],
];

file_put_contents(
    __DIR__ . '/../app/etc/env.php',
    "<?php\nreturn " . var_export($config, true) . ";\n"
);

7. Secrets Manager: Vault, AWS Secrets Manager und CI/CD-Secret-Stores

Reine Umgebungsvariablen lösen das Problem des Commits, aber nicht die Fragen nach Rotation, Zugriffskontrolle und Audit-Trail. Ein dedizierter Secrets Manager wie HashiCorp Vault oder AWS Secrets Manager schließt diese Lücke: Zugangsdaten werden zentral verwaltet, zeitlich begrenzt ausgegeben und lassen sich rotieren, ohne dass Anwendungscode oder Deployment-Skripte angepasst werden müssen. AWS Secrets Manager kann beispielsweise Datenbank-Passwörter für RDS automatisch und regelmäßig rotieren, während Vault dynamische, kurzlebige Datenbank-Credentials pro Anwendungsinstanz ausstellt.

Für die meisten Magento-Teams reicht der Einstieg über die Secret-Stores der eigenen CI/CD-Plattform, etwa GitHub Actions Secrets oder maskierte, geschützte GitLab-CI-Variablen. Diese werden zur Build- oder Deploy-Zeit als Umgebungsvariablen injiziert und tauchen in Logs standardmäßig maskiert auf. Der Umstieg auf Vault oder AWS Secrets Manager lohnt sich meist erst, wenn mehrere Umgebungen, Teams oder Microservices dieselben Zugangsdaten mit unterschiedlichen Berechtigungsstufen benötigen.


# .gitlab-ci.yml excerpt: inject secrets at deploy time, never store them in the repo
deploy_production:
  stage: deploy
  variables:
    DB_HOST: $PROD_DB_HOST
    DB_NAME: $PROD_DB_NAME
    DB_USER: $PROD_DB_USER
    DB_PASSWORD: $PROD_DB_PASSWORD      # masked + protected CI/CD variable
    CRYPT_KEY: $PROD_CRYPT_KEY          # masked + protected CI/CD variable
  script:
    - php bin/generate-env.php
    - php bin/magento setup:upgrade --keep-generated
    - php bin/magento cache:flush
  environment:
    name: production
  only:
    - main
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual

8. Pre-Commit-Hooks und Scanning: git-secrets, gitleaks & Co.

Prävention durch Disziplin allein reicht in der Praxis nicht aus, weil ein einziger unaufmerksamer Moment genügt, um ein Secret in die Historie zu bringen. Tools wie gitleaks und git-secrets scannen Diffs automatisiert auf bekannte Muster, etwa AWS-Zugangsschlüssel, private RSA-Schlüssel-Header, Magento-Crypt-Key-Formate oder generische hochentropische Strings, die wie Tokens aussehen. Als Pre-Commit-Hook eingebunden, blockieren sie den Commit bereits lokal, bevor sensible Daten überhaupt das eigene System verlassen.

Für Magento-Teams empfiehlt sich zusätzlich ein Scan im CI-Pipeline-Schritt, unabhängig vom lokalen Hook, weil nicht jeder Entwickler Hooks zuverlässig installiert oder sie mit --no-verify umgeht. Ein gitleaks-Schritt in der Pipeline, der bei einem Fund den Build fehlschlagen lässt, fängt genau diese Fälle ab. Regelbasierte Konfigurationsdateien lassen sich zusätzlich um projektspezifische Muster erweitern, etwa den charakteristischen Aufbau einer auth.json oder eigene interne API-Key-Formate.


#!/usr/bin/env bash
# .git/hooks/pre-commit - block commits containing leaked secrets
set -euo pipefail

echo "Running gitleaks on staged changes..."

if ! command -v gitleaks &> /dev/null; then
  echo "[WARN] gitleaks not installed, skipping local scan (CI will still catch it)"
  exit 0
fi

# Scan only the staged diff, not the entire history
if ! gitleaks protect --staged --redact --verbose; then
  echo "[BLOCKED] Potential secret detected in staged changes."
  echo "Remove the secret, or add a documented exception to .gitleaks.toml."
  exit 1
fi

# Extra guard: never allow auth.json or env.php to be staged at all
if git diff --cached --name-only | grep -qE '(^|/)auth\.json$|app/etc/env\.php$'; then
  echo "[BLOCKED] auth.json or env.php must never be committed."
  exit 1
fi

exit 0

9. Best Practices im Vergleich und Vorgehen bei bereits gepushten Secrets

Die folgende Tabelle stellt die häufigsten sensiblen Datentypen in Magento-Projekten dem jeweils falschen und dem korrekten Umgang gegenüber.

Datei / Datentyp Niemals so Richtiger Ansatz Warum es wichtig ist
app/etc/env.php Klartext im Repository committen In .gitignore, nur env.php.dist mit Platzhaltern versionieren DB-Zugriff und Crypt Key sofort kompromittiert
auth.json (Composer) Im Projekt-Root committen Global in COMPOSER_HOME oder per CI-Secret injizieren Marketplace-Zugang und Kostenrisiko bei Missbrauch
.env / Docker-Compose-Secrets Mit echten Werten einchecken .env.example mit Platzhaltern versionieren, echte .env ignorieren Datenbank- und Service-Zugangsdaten bleiben lokal
Private Keys / Zertifikate Ins Repository legen In Secrets Manager oder Deployment-Pipeline verwalten SSH- und SSL-Kompromittierung verhindern
API-Tokens in di.xml/PHP Hartcodiert im Quellcode Über Umgebungsvariablen oder Secrets Manager laden Rotation ohne Code-Änderung möglich

Trotz aller Prävention passiert es: Ein Secret wird versehentlich gepusht. In diesem Fall zählt Geschwindigkeit vor Vollständigkeit. Der wichtigste Schritt ist die sofortige Rotation der betroffenen Zugangsdaten: Datenbank-Passwort ändern, Crypt Key regenerieren und betroffene verschlüsselte Werte neu verschlüsseln, API-Keys beim jeweiligen Anbieter widerrufen, bevor überhaupt an die Git-Historie gedacht wird. Ein einfaches git rm --cached entfernt die Datei zwar aus zukünftigen Commits, das Secret bleibt aber in älteren Commits vollständig les- und wiederherstellbar.


# Immediate response when a secret was committed but not yet fully contained
# (rotating the credential itself is still the first and most important step)

# 1. Remove the file from the index, keep it locally, and ignore it going forward
git rm --cached app/etc/env.php
echo "app/etc/env.php" >> .gitignore

# 2. Commit the removal
git commit -m "Remove app/etc/env.php from version control"

# 3. If the commit was already pushed, notify the team immediately -
#    the file is still readable in the Git history for anyone with a clone
git push origin main

# Note: this does NOT remove the secret from history.
# Rewriting history (git filter-repo / BFG Repo-Cleaner) is a separate,
# more involved process covered in a dedicated article.

Das vollständige Entfernen eines Secrets aus der kompletten Git-Historie, etwa mit git filter-repo oder BFG Repo-Cleaner, ist ein eigenständiges, deutlich tieferes Thema mit eigenen Tücken bei bereits geklonten Kopien, offenen Pull Requests und Force-Pushes auf geteilten Branches. Dieser Artikel behandelt bewusst nur die Prävention; die Historie-Bereinigung ist an anderer Stelle im Blog ausführlich beschrieben.

Mironsoft

Security-Reviews, CI/CD-Pipelines und Secrets-Management für Magento-Teams

Sensible Daten zuverlässig aus eurem Repository heraushalten?

Wir prüfen bestehende Magento-Repositories auf bereits committete Secrets, richten eine saubere .gitignore-Baseline ein und implementieren Pre-Commit-Scanning sowie Secrets-Management für euer Team.

Repository-Audit

Bestehende Commits und Historie auf geleakte Zugangsdaten und Schlüssel prüfen

Secrets-Management-Setup

Vault, AWS Secrets Manager oder CI/CD-Secret-Stores für euren Stack einrichten

Pre-Commit-Scanning

gitleaks und git-secrets als verbindlichen Standard im Team etablieren

10. Zusammenfassung

Sensible Daten in Magento-Projekten aus Git herauszuhalten ist kein einmaliges Aufräumen, sondern ein durchgängiges Muster über den gesamten Projektlebenszyklus. app/etc/env.php mit Datenbank-Credentials und Crypt Key sowie auth.json mit den Marketplace-Zugangsdaten gehören von Anfang an in die .gitignore, nicht erst nachträglich. Eine vollständige, Magento-spezifische .gitignore-Baseline mit var/, generated/, pub/static/, pub/media/, vendor/, node_modules/ sowie .idea/ und .vscode/ verhindert die häufigsten Versehen bereits strukturell.

Umgebungsvariablen trennen Konfiguration konsequent von Code, während Secrets Manager wie Vault oder AWS Secrets Manager zusätzlich Rotation, Zugriffskontrolle und Audit-Trail liefern, wo reine Umgebungsvariablen an ihre Grenzen stoßen. Pre-Commit-Hooks mit gitleaks oder git-secrets sowie ein zusätzlicher Scan-Schritt in der CI-Pipeline fangen menschliche Fehler ab, bevor sie zum Sicherheitsvorfall werden. Und falls doch einmal ein Secret durchrutscht: Sofortige Rotation der Zugangsdaten hat immer Vorrang vor der aufwendigeren Bereinigung der Git-Historie.

Sensible Daten in Magento-Projekten: Das Wichtigste auf einen Blick

env.php & auth.json

Enthalten Datenbank-Credentials, Crypt Key und Marketplace-Zugang. Niemals versionieren, nur .dist-Vorlagen mit Platzhaltern committen.

.gitignore-Baseline

var/, generated/, pub/static/, pub/media/, vendor/, node_modules/, .idea/, .vscode/ und env.php konsequent ausschließen.

Umgebungsvariablen & Secrets Manager

Konfiguration von Code trennen, Zugangsdaten über getenv(), CI/CD-Secrets oder Vault/AWS Secrets Manager verwalten.

Scanning & Reaktion

gitleaks/git-secrets als Pre-Commit-Hook und CI-Schritt einsetzen. Bei einem Leak sofort rotieren, Historie-Bereinigung separat behandeln.

11. FAQ: Sensible Daten in Magento-Projekten aus Git heraushalten

1Welche Magento-Dateien dürfen niemals in Git landen?
Vor allem app/etc/env.php mit DB-Credentials und Crypt Key, auth.json mit den Composer-Zugangsdaten, echte .env-Dateien, private Schlüssel/Zertifikate sowie hartcodierte API-Tokens im Code.
2Was passiert, wenn der Crypt Key aus env.php geleakt wird?
Der Crypt Key entschlüsselt sensible Werte in core_config_data. Zusammen mit einem DB-Dump lassen sich diese Werte vollständig entschlüsseln, deshalb sofort regenerieren.
3Wo sollte die auth.json für Composer gespeichert werden?
Global unter COMPOSER_HOME (~/.composer/auth.json), nicht im Projekt-Root. In CI/CD zur Laufzeit aus maskierten Variablen erzeugen.
4Was gehört in eine Magento-spezifische .gitignore?
env.php, auth.json, var/, generated/, pub/static/, Großteil von pub/media/, vendor/, node_modules/, .idea/ und .vscode/, bereits vor dem ersten Setup committet.
5Wie ersetze ich hartcodierte Zugangsdaten durch Umgebungsvariablen?
Mit getenv()/$_ENV zur Laufzeit auslesen. Ein Deployment-Skript generiert env.php aus einer Vorlage, Platzhalter werden durch echte Werte ersetzt.
6Wann lohnt sich ein dedizierter Secrets Manager wie Vault?
Bei Bedarf an Rotation, feingranularer Zugriffskontrolle oder Audit-Trail über mehrere Umgebungen/Teams. Kleinere Projekte kommen mit CI/CD-Secret-Stores aus.
7Was macht gitleaks und wie unterscheidet es sich von git-secrets?
Beide scannen auf bekannte Secret-Muster. gitleaks nutzt konfigurierbare Regeln, gut für CI. git-secrets ist enger an AWS-Patterns orientiert, oft als lokaler Hook.
8Wie richte ich einen Pre-Commit-Hook für Secret-Scanning ein?
gitleaks installieren, als .git/hooks/pre-commit einbinden, gitleaks protect --staged ausführen. Zusätzlich denselben Scan als Pflichtschritt in der CI-Pipeline.
9Ich habe versehentlich env.php committet, was tun?
Sofort Zugangsdaten rotieren (DB-Passwort, Crypt Key), erst danach mit git rm --cached aus der Versionierung entfernen und .gitignore ergänzen.
10Reicht es, eine Datei nachträglich aus dem Repository zu löschen?
Nein, git rm --cached entfernt nur zukünftige Commits, ältere Commits enthalten das Secret weiter. Vollständige Entfernung braucht git filter-repo oder BFG Repo-Cleaner.