Wenn eine bisher stabile CI-Pipeline plötzlich unbekannte Adressen kontaktiert, sollten diese Verbindungen nicht sofort blockiert werden. Build-Werkzeuge, Resolver für Abhängigkeiten, Testprozesse und Aktualisierungsdienste im Hintergrund können allesamt ausgehende Verbindungen erzeugen. Für eine aussagekräftige Untersuchung wird ein reproduzierbarer Build ausgewählt und innerhalb eines klar begrenzten Zeitfensters gleichzeitig erfasst, welche Prozesse laufen, wohin sie sich verbinden und wann die Verbindungen auftreten. Aus diesen Ergebnissen entsteht anschließend eine Vergleichsbasis.
Ein vergleichbares Erfassungsfenster festlegen
Wählen Sie einen Zeitraum, in dem die Abhängigkeiten bereits installiert sind, der Arbeitsbereich sauber ist und keine Jobs anderer Teams ausgeführt werden. Halten Sie Commit-ID, Build-Befehl, macOS-Version, Xcode-Version und Startzeit fest. Führen Sie bei der ersten Erfassung nur einen Job aus. Andernfalls können gemeinsam genutzte Prozesse mehrerer Pipelines eine eindeutige Zuordnung verhindern.
Empfehlenswert sind zwei Datensätze: einer für einen minimalen Build und einer für den vollständigen Testlauf. Der minimale Build macht Verbindungen bei der Auflösung von Abhängigkeiten und beim Kompilieren sichtbar. Der vollständige Testlauf deckt zusätzlich Simulatoren, Testdienste und das Hochladen von Artefakten ab. Wiederholen Sie jeden Lauf zweimal. Anhand des zweiten Durchlaufs lassen sich einmalige Downloads in der Regel von den Verbindungen eines stabilen Builds unterscheiden.
Eine Basis für ausgehende Verbindungen ist keine dauerhaft gültige IP-Liste. Sie dokumentiert vielmehr, warum ein bekannter Job in einer bekannten Phase auf eine bestimmte Art von Dienst zugreift.
Verbindungen anhand von drei Beweisebenen beobachten
Prozesse und bestehende Verbindungen
Mit lsof lässt sich feststellen, welche Prozesse zum Zeitpunkt der Erfassung noch Verbindungen unterhalten. Die Ausgabe numerischer Adressen verhindert, dass durch Reverse-Lookups zusätzlicher DNS-Verkehr entsteht.
sudo lsof -nP -iTCP -sTCP:ESTABLISHED \
| awk 'NR == 1 || $1 ~ /xcode|swift|git|ruby|node|curl/'
Filtern Sie nicht ausschließlich nach Prozessnamen und verwerfen Sie nicht die ursprünglichen Ergebnisse. Speichern Sie zunächst den vollständigen Snapshot und erstellen Sie daraus anschließend eine übersichtliche Teilmenge. Build-Skripte können Downloads über Systemwerkzeuge starten, deren Namen keinen projektspezifischen Begriff enthalten.
Datenverkehr und kurzlebige Verbindungen
nettop bietet eine nach Prozessen zusammengefasste Echtzeitansicht. tcpdump zeichnet dagegen auch TCP-Handshakes auf, die bereits nach wenigen Dutzend Millisekunden beendet sind. Bei einer Ausführung über eine Remote-Verbindung sollten nur ausgehende SYN-Pakete und keine Nutzdaten erfasst werden. So gelangen weniger Geschäftsdaten in die Protokolle.
nettop -P -L 1
sudo tcpdump -i any -nn -l \
'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
Prüfen Sie vor der Paketerfassung die entfernte Adresse der aktuellen SSH-Sitzung. Ein fehlerhafter Filter kann erhebliche Mengen an Rauschen erzeugen. Die Beobachtungsbefehle selbst verändern jedoch keine Firewall-Regeln.
Ein archivierbares Erfassungspaket erstellen
Das folgende Skript speichert Systeminformationen, Routingdaten, Verbindungssnapshots und die Handshakes eines Zeitraums von 60 Sekunden. Bereiten Sie den Build vor der Ausführung so weit vor, dass er unmittelbar gestartet werden kann. Starten Sie nach dem Skript den Build in einer zweiten Sitzung.
#!/bin/zsh
set -euo pipefail
OUT="${1:-$HOME/ci-egress-$(date -u +%Y%m%dT%H%M%SZ)}"
mkdir -p "$OUT"
date -u > "$OUT/time.txt"
sw_vers > "$OUT/system.txt"
xcodebuild -version > "$OUT/xcode.txt"
route -n get default > "$OUT/default-route.txt"
scutil --dns > "$OUT/dns.txt"
sudo lsof -nP -i > "$OUT/lsof-before.txt"
sudo tcpdump -i any -nn \
'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0' \
-w "$OUT/outbound-syn.pcap" &
CAPTURE_PID=$!
sleep 60
sudo kill -INT "$CAPTURE_PID"
wait "$CAPTURE_PID" || true
sudo lsof -nP -i > "$OUT/lsof-after.txt"
nettop -P -L 1 > "$OUT/nettop.txt"
printf '%s
' "$OUT"
Dauert der Build länger als 60 Sekunden, sollte nicht eine einzelne Paketerfassung beliebig verlängert werden. Erfassen Sie stattdessen die Phasen „Abhängigkeiten auflösen“, „Kompilieren“, „Testen“ und „Archivieren“ separat. Mit phasenbezogenen Ergebnissen lässt sich leichter feststellen, in welchem Schritt eine neue Verbindung entstanden ist.
Ziele zu einer Kommunikationsbasis zusammenfassen
Eine unbekannte IP-Adresse allein ist noch kein Anzeichen für eine Anomalie. Klassifizieren Sie die Verbindung zunächst anhand des Prozesses, des Ports, der Build-Phase und der Projektkonfiguration. Dynamische Auslieferungsnetze können ihre Adressen häufig wechseln. Deshalb sollte sich die Basis vor allem auf den Zweck und auf überprüfbare Domainnamen stützen. IP-Adressen dienen lediglich als Beleg für die jeweilige Erfassung.
Führen Sie für unbekannte Prozesse zusätzlich ps -o pid,ppid,user,start,command -p PID aus und untersuchen Sie anschließend den Elternprozess. Tritt eine Verbindung nur einmal auf, vereinheitlichen Sie die Zeitangaben der Paketerfassung und des CI-Protokolls auf UTC und gleichen Sie sie miteinander ab, statt sich auf Erinnerungen zu verlassen.
Häufige Fehlinterpretationen und Sicherheitsgrenzen
Der häufigste Fehler besteht darin, eine dynamische IP-Adresse als dauerhafte Identität zu behandeln. Ein weiteres Problem ist die ausschließliche Erfassung von lsof nach Abschluss des Builds. Kurzlebige Verbindungen sind zu diesem Zeitpunkt bereits verschwunden. Der dritte Fehler ist die unmittelbare Aktivierung von Sperrregeln auf einem Remote-Knoten. Wurden solche Regeln nicht über eine lokale Konsole geprüft, können sie gleichzeitig SSH, DNS oder den Download von Abhängigkeiten unterbrechen.
Die sicherere Reihenfolge lautet: beobachten, klassifizieren, reproduzieren und prüfen – erst danach sollten Beschränkungen umgesetzt werden. Wenn ausgehende Verbindungen eingeschränkt werden müssen, sind zunächst die bestehende Verwaltungsverbindung und die DNS-Pfade beizubehalten. Bereiten Sie außerdem einen Befehl zum Zurücksetzen vor und testen Sie die Änderung an einem einzelnen, unkritischen Job. Firewall-Regeln, Proxy-Konfigurationen und Build-Skripte müssen versioniert werden und dürfen nicht ausschließlich lokal auf dem Knoten verbleiben.
Die Basis in regelmäßige Prüfungen integrieren
Wiederholen Sie dieselbe Erfassung nach jeder Änderung an der Toolchain, den Bezugsquellen für Abhängigkeiten oder dem Upload-Ablauf. Vergleichen Sie dabei nicht die Anzahl der IP-Zeilen, sondern neu hinzugekommene Kombinationen aus „Prozess—Ziel—Phase“. Für erlaubte Verbindungen müssen Verantwortliche, Zweck und Bedingungen für eine erneute Prüfung dokumentiert werden. Nicht erklärbare Verbindungen dürfen nicht allein aufgrund einer Anmerkung dauerhaft freigegeben werden.
Bewahren Sie abschließend das Erfassungsskript, die Rohdateien, die Klassifikationstabelle und die zugehörige Commit-ID auf. Bei ungewöhnlichen Downloads, langsameren Builds oder dem Verdacht auf einen Abfluss von Zugangsdaten kann das Team seine Untersuchung dann mit den tatsächlichen Unterschieden beginnen, anstatt erneut zu erraten, wie normaler Datenverkehr aussieht.
Häufig gestellte Fragen
Sollten erfasste Ziel-IP-Adressen direkt in eine Freigabeliste übernommen werden?
Nein. Download- und Plattformdienste verwenden häufig dynamische oder gemeinsam genutzte Adressen. Ziele sollten zuerst nach Zweck und Domäne klassifiziert werden.
Warum unterscheiden sich die Ergebnisse von lsof und tcpdump?
lsof zeigt nur Verbindungen, die im Moment der Abfrage noch offen sind. tcpdump erfasst auch Verbindungsaufbauten, die innerhalb des Messfensters bereits beendet wurden.
Builds auf exklusiven physischen Apple-Silicon-Knoten ausführen
Konfigurieren Sie den Knoten nach Modell, Region und Mietdauer. Maßgeblich ist der in der Konsole in Echtzeit angezeigte Verfügbarkeitsstatus.