Wenn ein dauerhaft laufender Cloud-Mac nacheinander Builds für mehrere Repositorys ausführt, besteht die größte Gefahr nicht immer darin, dass ein Token direkt in einem Skript steht. Oft hinterlässt vielmehr ein vorheriger Job unbemerkt Zugangsdaten für den nächsten. Typische Rückstände finden sich in der globalen Git-Konfiguration, in Remote-URLs mit eingebetteten Anmeldedaten, im Anmeldeschlüsselbund oder in nicht gelöschten temporären Skripten. Ziel ist daher nicht, „nach dem Build eine Variable zu löschen“, sondern Zugangsdaten von Anfang an auf die Grenzen eines einzelnen Jobs zu beschränken.
Zuerst prüfen, wo Zugangsdaten gespeichert werden
Ändern Sie nicht sofort die Pipeline. Prüfen Sie zunächst, welche Konfiguration Git tatsächlich einliest, ohne dabei geheime Werte auszugeben. --show-origin zeigt zusätzlich die Herkunft jeder Einstellung an und macht damit systemweite, benutzerspezifische und repositorybezogene Konfigurationen unterscheidbar.
set +x
git config --show-origin --get-all credential.helper || true
git config --show-origin --get-regexp '^(credential|http)\.' || true
git config --show-origin --get-regexp '^url\..*\.insteadof$' || true
Achten Sie besonders auf drei Arten von Signalen:
- Verweist
credential.helperauf einen persistenten Schlüsselbund? - Wurde
http.extraHeaderin die globale oder repositorybezogene Konfiguration geschrieben? - Schreibt
url.*.insteadOfeine normale Adresse in eine URL mit eingebetteten Anmeldedaten um?
Auch die Remote-URL muss geprüft werden, darf aber nicht unverändert im Protokoll erscheinen. Es genügt festzustellen, ob sie dem Muster Protokoll://Benutzerinfo@Host entspricht. Wird ein solcher Aufbau erkannt, sollte der Job sofort fehlschlagen, statt die vollständige Adresse auszugeben.
remote_url="$(git remote get-url origin)"
case "$remote_url" in
*://*@*)
printf '%s
' "Remote URL contains embedded credentials" >&2
exit 1
;;
esac
Der wichtigste Grundsatz für Audit-Skripte lautet: Melden Sie nur, dass Zugangsdaten vorhanden sein könnten. Geben Sie die Zugangsdaten nicht im Build-Protokoll aus, nur um das Problem zu belegen.
Für jeden Job ein eigenes HOME erstellen
Git leitet den Pfad zur benutzerspezifischen Konfiguration aus HOME ab. Wenn alle Jobs das HOME des Runner-Benutzers gemeinsam verwenden, teilen sie damit auch .gitconfig, die Konfiguration der Credential-Helper und zahlreiche Zustände anderer Werkzeuge. Robuster ist es, für jeden Job ein temporäres HOME mit den Berechtigungen 700 anzulegen und die globale Git-Konfigurationsdatei explizit festzulegen.
set -eu
ORIGINAL_HOME="$HOME"
JOB_HOME="$(mktemp -d "${TMPDIR%/}/git-job.XXXXXX")"
chmod 700 "$JOB_HOME"
export HOME="$JOB_HOME"
export XDG_CONFIG_HOME="$JOB_HOME/.config"
export GIT_CONFIG_GLOBAL="$JOB_HOME/.gitconfig"
export GIT_TERMINAL_PROMPT=0
mkdir -p "$XDG_CONFIG_HOME"
Die systemweite Git-Konfiguration wird dadurch nicht isoliert. Deshalb muss die Helper-Kette weiterhin aktiv zurückgesetzt werden. Git unterstützt mehrere Werte für credential.helper. Ein zuerst gesetzter leerer Wert verwirft Helper, die aus Konfigurationsebenen mit niedrigerer Priorität übernommen wurden. Anschließend kann die jobeigene Implementierung ergänzt werden.
Repository und temporäres HOME getrennt halten
HOME bildet die Grenze für Zugangsdaten und Werkzeugzustände, muss aber nicht zugleich als Arbeitsbereich dienen. Der Quellcode sollte weiterhin im Workspace des Runners liegen, damit Speicherplatz kontrolliert und Build-Artefakte eingesammelt werden können. Sind beide Bereiche getrennt, löscht die Bereinigung von HOME nicht versehentlich Build-Ergebnisse, während die Bereinigung des Workspace keine benutzerspezifische Authentifizierungskonfiguration übersieht.
Bei paralleler Ausführung muss jeder Parallelisierungsslot mktemp separat aufrufen. Ein anhand des Repositorynamens festgelegtes Verzeichnis darf nicht wiederverwendet werden. Nach einem unerwarteten Abbruch könnte der nächste Job ein solches Verzeichnis übernehmen. Außerdem könnten zwei Jobs gleichzeitig dieselbe .gitconfig verändern.
Token nur auf Anfrage von Git bereitstellen
Das Token sollte über die Secret-Variablen des CI-Systems in die Umgebung injiziert werden; das Skript verweist ausschließlich auf die Variablennamen. Betten Sie das Token weder in die Clone-URL ein, noch speichern Sie den Authentifizierungs-Header dauerhaft mit git config --global http.extraHeader.
Der folgende Helper antwortet ausschließlich auf get-Anfragen von Git. In der Konfigurationsdatei steht die Logik zum Referenzieren der Variablen, nicht der Tokenwert:
: "${CI_GIT_USER:?CI_GIT_USER is required}"
: "${CI_GIT_TOKEN:?CI_GIT_TOKEN is required}"
git config --global credential.helper ""
git config --global --add credential.helper \
'!f() {
if [ "$1" = get ]; then
printf "username=%s
password=%s
" \
"$CI_GIT_USER" "$CI_GIT_TOKEN"
fi
}; f'
Befehls-Echo und interaktiven Fallback deaktivieren
Vor dem Zugriff auf geheime Variablen muss set +x ausgeführt werden. Andernfalls schreibt die Shell Befehle mit bereits expandierten Variablen in das Protokoll. GIT_TERMINAL_PROMPT=0 ist ebenso wichtig: Fehlt das Token oder ist es ungültig, muss der Job eindeutig fehlschlagen, statt an einer nicht sichtbaren interaktiven Eingabeaufforderung zu warten.
Prüfen Sie außerdem, ob der Build-Wrapper automatisch Umgebungsvariablen ausgibt. Diagnoseinformationen dürfen lediglich anzeigen, ob eine Variable gesetzt ist, beispielsweise indem geprüft wird, ob ihre Zeichenlänge größer als null ist. Der Variableninhalt, Authentifizierungs-Header und vollständige Remote-URLs dürfen nicht ausgegeben werden.
Automatisierte Aufgaben mit Schreibzugriff sollten unterschiedliche Zugangsdaten für das Lesen des Quellcodes und das Pushen von Artefakten verwenden. Ein Job, der lediglich einen Checkout ausführt, benötigt keine Schreibrechte. Auch ein Veröffentlichungsjob darf keine Berechtigungen erhalten, die über das Ziel-Repository und die erforderlichen Aktionen hinausgehen.
Mit trap alle Exit-Pfade abdecken
Ein rm -rf ausschließlich am Ende des Skripts deckt vorzeitige Fehler, durch Zeitüberschreitung verursachte Abbrüche oder manuelle Abbrüche nicht ab. Registrieren Sie deshalb unmittelbar nach dem Erstellen des temporären Verzeichnisses einen trap. Die Bereinigungsfunktion sollte zuerst die Variablen löschen und anschließend das HOME des Jobs entfernen.
cleanup_git_credentials() {
set +e
unset CI_GIT_TOKEN CI_GIT_USER
if [ -n "${JOB_HOME:-}" ] && [ -d "$JOB_HOME" ]; then
rm -rf "$JOB_HOME"
fi
}
trap cleanup_git_credentials EXIT HUP INT TERM
Die Bereinigungsfunktion muss wiederholt ausgeführt werden können, ohne einen Fehler auszulösen, wenn das Verzeichnis bereits nicht mehr existiert. Das Löschziel muss außerdem zwei Bedingungen erfüllen: Die Variable darf nicht leer sein und muss tatsächlich auf ein Verzeichnis verweisen. Verwenden Sie keine weitreichenden Befehle zum Löschen von Schlüsselbundinhalten und leeren Sie nicht den gesamten Anmeldeschlüsselbund. Er könnte weitere erforderliche Einträge für denselben Runner-Benutzer enthalten.
Falls ältere Pipelines persistente Helper verwendet haben, müssen diese zunächst präzise nach Host und Konto erfasst werden. Planen Sie anschließend eine einmalige Migration. Solange alte und neue Lösung parallel bestehen, muss jeder Job die Herkunft des aktuell verwendeten Helpers prüfen. So lässt sich verhindern, dass das temporäre HOME zwar aktiv ist, ein systemweiter Wrapper aber die alte Konfiguration erneut hineinkopiert.
Rückstandsprüfungen als Build-Gate einsetzen
Eine fehlerfrei beendete Bereinigung allein beweist nicht, dass sie erfolgreich war. Empfehlenswert ist eine nachgelagerte Prüfung außerhalb des Runners. Alternativ kann der Executor beim Zurücksetzen des Jobs folgende Punkte verifizieren:
- Das temporäre HOME wurde gelöscht.
.git/configim Workspace enthält weder Authentifizierungs-Header noch Remote-URLs mit Benutzerinformationen.- Das Jobprotokoll enthält keinen bekannten Fingerabdruck der geheimen Variablen.
- Die Herkunft der Git-Konfiguration umfasst nur die erwartete Systemkonfiguration und die temporäre Konfiguration des aktuellen Jobs.
- Ein nachfolgender leerer Job kann nicht auf die Repository-Zugangsdaten des vorherigen Jobs zugreifen.
Für ein Test-Token kann ein fester Markerwert ohne Berechtigungen verwendet werden. Führen Sie damit in einer isolierten Umgebung Fehlerszenarien aus und durchsuchen Sie anschließend Protokolle und Dateisystem. Dabei wird geprüft, ob der Marker offengelegt wurde, nicht ob ein echtes Token gültig ist. Die Fehlertests sollten mindestens einen fehlgeschlagenen Clone, den Abbruch eines Build-Befehls, den Empfang eines Beendigungssignals und die wiederholte Ausführung der Bereinigungsfunktion abdecken.
Wenn mehrere Teams denselben physischen Knoten nutzen, sollte der ausführende Benutzer als zweite Sicherheitsgrenze dienen. Das temporäre HOME verhindert Rückstände auf Jobebene. Separate Benutzer grenzen Prozesse, Dateiberechtigungen und Schlüsselbunde zwischen unterschiedlichen Vertrauensbereichen voneinander ab. Nur wenn beide Ebenen vorhanden sind, bleibt die Skriptbereinigung nicht die einzige Verteidigungslinie.
Die endgültigen Abnahmekriterien sind einfach: Vor dem Job stehen keine vererbbaren Zugangsdaten bereit, während der Ausführung werden sie nur bei Bedarf bereitgestellt, jeder Exit-Pfad löst die Bereinigung aus und der nächste Job kann nicht nachweisen, dass das vorherige Token jemals vorhanden war. Erst dann gehören die Git-Zugangsdaten tatsächlich zum Job und nicht zum dauerhaft laufenden Cloud-Mac.
Häufig gestellte Fragen
Warum reicht es nicht, die Token-Variable am Jobende zu löschen?
Der Zugang kann bereits in einem Helper, einer Remote-URL, der globalen Konfiguration oder im Schlüsselbund gespeichert sein. Jeder Speicherort muss separat geprüft werden.
Dürfen dauerhaft laufende Mac-CI-Worker den Login-Schlüsselbund teilen?
Nicht über unterschiedliche Repositories oder Vertrauensgrenzen hinweg. Nutzen Sie kurzlebige Tokens mit Minimalrechten und bei Bedarf getrennte Benutzer oder Schlüsselbünde.
Wählen Sie für Entwicklung, Builds und Remote-Desktop einen dedizierten physischen Rechner.
Vergleichen Sie drei Apple-Silicon-Konfigurationen und wählen Sie beim Bestellen Knoten, Mietdauer und zusätzliche Speicheroptionen aus.