一條原本穩定的 CI 流水線突然開始連線至陌生位址時,先不要立即封鎖。建置工具、相依套件解析器、測試程序與背景更新工作都可能建立出站連線。有效的排查方式,是選擇一次可重複執行的建置,在限定時間內同步記錄「哪個程序正在執行、連線前往何處、連線何時出現」,再將結果整理成基準。
先固定一次可比較的取樣時段
選擇相依套件已安裝、工作區乾淨,且沒有其他團隊工作的時段。記錄提交編號、建置命令、macOS 版本、Xcode 版本與開始時間。首次取樣只執行一項工作,避免兩條流水線共用程序後無法歸因。
建議準備兩組資料:一組執行最小建置,另一組執行完整測試。前者可顯示相依套件解析與編譯所產生的連線,後者還會涵蓋模擬器、測試服務與產物上傳。每組重複兩次,第二次通常有助於區分首次下載與穩定建置。
出站基準不是一份永久有效的 IP 清單,而是一組能說明「已知工作在已知階段為何存取某類服務」的證據。
用三層證據觀察連線
程序與現有連線
lsof 適合用來確認取樣當下仍由哪些程序維持連線。使用數字位址可避免反向解析產生額外的 DNS 流量。
sudo lsof -nP -iTCP -sTCP:ESTABLISHED \
| awk 'NR == 1 || $1 ~ /xcode|swift|git|ruby|node|curl/'
不要只依程序名稱篩選並丟棄原始結果。應先儲存完整快照,再產生方便閱讀的子集。建置指令碼可能透過系統工具下載檔案,程序名稱未必包含專案關鍵字。
流量與短暫連線
nettop 提供依程序彙總的即時檢視,tcpdump 則能保留在數十毫秒內結束的 TCP 交握。遠端執行時只擷取出站 SYN,不收集承載資料,可減少記錄中的業務資料。
nettop -P -L 1
sudo tcpdump -i any -nn -l \
'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
擷取封包前,先確認目前 SSH 工作階段的遠端位址。錯誤的篩選條件可能產生大量雜訊,但觀察命令本身不會變更防火牆規則。
產生可封存的採集套件
以下指令碼會儲存系統資訊、路由、連線快照與 60 秒的交握記錄。執行前先將建置準備至即將開始的狀態;指令碼啟動後,再於另一個工作階段執行建置。
#!/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"
若建置時間超過 60 秒,應依「解析相依套件、編譯、測試、封存」分別取樣,而不是無限延長單次封包擷取。分階段的結果更容易判斷新增連線來自哪一個步驟。
將目的地整理成通訊基準
不要因為看到陌生 IP 就判定為異常。應先結合程序、連接埠、出現階段與專案設定進行分類。動態內容傳遞網路可能頻繁更換位址,因此基準應以用途及可驗證的網域名稱為主,IP 僅保留為當次證據。
針對未知程序,繼續執行 ps -o pid,ppid,user,start,command -p PID,再檢查其父程序。若連線只出現一次,可先將封包擷取時間與 CI 記錄時間統一為 UTC 後再比對,而不是依賴人工回憶。
常見誤判與安全界線
最常見的誤判,是將動態 IP 視為穩定身分。第二個問題是只在建置結束後執行 lsof,此時短暫連線早已消失。第三個問題是在遠端節點上直接啟用拒絕規則;若規則未經本機主控台驗證,可能同時中斷 SSH、DNS 或相依套件下載。
較穩妥的順序是觀察、分類、重現、審查,最後才實施限制。確實需要收緊出站連線時,應先保留現有管理連線與 DNS 路徑,準備復原命令,並在單一非關鍵工作上驗證。防火牆規則、代理伺服器設定與建置指令碼都必須納入版本管理,不能只留存在節點本機。
將基準納入日常檢查
每次工具鏈、相依套件來源或上傳流程變更後,都應重新執行相同取樣。比較時應關注新增的「程序—目的地—階段」組合,而不是比較 IP 的行數。允許項目應清楚註明負責人、用途與複查條件;無法解釋的連線不能只靠備註永久放行。
最後應保留採集指令碼、原始檔案、分類表與對應的提交編號。如此一來,遇到異常下載、建置速度變慢或疑似憑證外洩時,團隊就能從實際差異著手排查,而不必重新猜測正常流量應該是什麼樣貌。
常見問題
可以直接把擷取到的目標 IP 寫入防火牆允許清單嗎?
不建議。依賴下載與託管服務可能使用動態或共享位址,應先依服務用途與網域分類,再選擇穩定的出口限制方式。
為什麼 lsof 與 tcpdump 記錄到的連線數量不同?
lsof 只顯示查詢當下仍存在的連線,tcpdump 則能記錄取樣期間出現過的握手,因此短連線通常只會出現在封包記錄中。
在獨享 Apple Silicon 實體節點上執行建置
依機型、區域與租用週期設定節點,實際可用狀態以控制台即時回傳結果為準。