Если ранее стабильный конвейер 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
Настройте узел по модели, региону и сроку аренды. Фактическая доступность отображается в панели управления в реальном времени.