2026 Удалённый Mac в шести регионах: учётные данные агентов Jenkins и Buildkite (машинные пользователи, OIDC, PAT) при сосуществовании с runner GitHub Actions/GitLab — чеклист FinOps мьютексов и аренды

~17 мин чтения · MACCOME

Если вы запускаете агенты macOS Jenkins или Buildkite на выделенных удалённых Mac в Сингапуре, Японии, Корее, Гонконге, восточном и западном побережье США и уже используете runner GitHub Actions или GitLab, развёрнутые на вашей инфраструктуре, боль в бюджете и аудите редко в vCPU — чаще это радиус поражения учётных данных от второго контроллера: кто держит 90-дневный PAT, какой контекст пользователя владеет связкой match и сессией ASC, и не застывают ли секреты в образах при пересборке burst-хостов. Статья задаёт три регистра — топология учётных данных, правила мьютексов, учёт аренды — и дополняет runbook поэтапной аренды Jenkins/Buildkite и чеклист меток и секретов runner: там очереди, здесь личности, OIDC и отзыв.

Шесть сбоев с учётными данными, когда «второй контроллер CI» попадает на тот же хост в шести регионах

  1. Все агенты делят один интерактивный HOME macOS: ~/.ssh для Jenkins, buildkite-agent и actions-runner под одним входом превращают безлюдную CI в нестабильно «зелёные» сборки, как только git credential-osxkeychain запрашивает ввод.
  2. Организационные PAT в ежедневных burst-образах: частая смена хостов с замороженными org-токенами расширяет зону поражения за один билдер.
  3. Нет мьютекса на расшифровку match и загрузки нотариуса: параллельные пайплайны на один репозиторий match или сессию ASC дают прерывистые 401/403, ошибочно принимаемые за «шум со стороны Apple».
  4. Несовпадение аудитории OIDC на облачной плоскости управления: слишком широкие политики доверия Buildkite или GitHub позволяют агентам получить большую поверхность токена, чем нужно задаче.
  5. Незадокументированные партиции связки ключей и порядок LaunchDaemon: после перезагрузки Jenkins стартует раньше runner и читает пустую партицию, пока кто-то не нажмёт повтор.
  6. FinOps считает ядра, но не «время жизни учётных данных × аренда»: долгоживущие ключи на ежедневных хостах выглядят дёшево в счёте и неприемлемы в календаре безопасности.

Ценность шести регионов — предсказуемая колокация и выделенный IO; расплывчатая топология учётных данных масштабирует только путаницу. Если параллельно гоняете гибридный CI Xcode Cloud, явно укажите, какая личность может трогать ASC против внутренних регистров — иначе гибридная матрица станет гибридным инцидентом.

Введите RACI по учётным данным: платформа владеет машинными пользователями и привязками OIDC, репозитории — областями workflow, безопасность — учениями на отзыв. Любая щель взрывается при включении второго контроллера.

Измерение Предпочесть долгоживущий PAT / deploy keys Предпочесть OIDC / короткие токены
Аренда Только на хостах с базовой линией от месяца и дольше с внеобразовой инъекцией секретов Подходит для ежедневного/недельного burst, если условия доверия жёсткие
Зернистость аудита Нужны дополнительные логи «кто положил PAT на какой хост»; ротация часто следует за финансовыми кварталами Облако может связать репозиторий, среду, пул — проще атрибуция на задачу
Экосистема плагинов Jenkins Многие плагины предполагают статические файлы учётных данных Требует явных правок пайплайнов; выше разовые затраты
Buildkite Хуки могут тихо экспортировать секреты Хуки только собирают; секреты из коротких токенов после обмена OIDC
GHA/GitLab runner Self-hosted runner часто хранят длинные файлы .credentials OIDC к облачному STS — мейнстрим; сначала выровняйтесь здесь
warning

Красная черта: не выпускайте долгоживущие PAT организации или корневые ключи развёртывания на ежедневных burst-хостах. Если бизнес настаивает, привяжите время жизни секретов к потолкам аренды в том же тикете согласования.

Шестишаговый runbook: от «работает» до «можем отозвать и отразить в регистре»

  1. Инвентаризация поверхностей секретов в Jenkinsfile, пайплайнах Buildkite и workflow GitHub: переменные и файлы; пометьте org-wide и repo-scoped.
  2. Назначьте разных машинных пользователей и деревья HOME — например jenkins, buildkite, runner; запретите общие интерактивные входы для CI.
  3. Мьютекс на исключительные ресурсы: расшифровка match, загрузка нотариуса, браузерные сессии ASC сериализуются; имена блокировок живут в ROUTING.md и комментариях пайплайна.
  4. Условия доверия OIDC как текст для ревью: audience, репозиторий, префикс ref, имя среды; сверка с IAM или внутренним STS.
  5. Ежеквартальное учение по отзыву: случайно отозвать один класс токенов и проверить, что все три агента деградируют ожидаемо, а не молча продолжают.
  6. Внесите срок жизни учётных данных в FinOps-лист аренды: долгоживущие только на хостах базовой линии; на burst только короткий STS — та же страница, что и таблица поэтапной аренды.
bash
# Example mutex (replace flock backend with your coordination service)
exec 9>/var/lock/match-decrypt.lock
flock -n 9 || { echo "match decrypt busy"; exit 42; }

# Example split users (LaunchDaemon sketch—do not copy paths blindly)
# UserName=buildkite vs UserName=runner — each HOME keeps its own git credential helper config

Три метрики для Grafana или заметок ревью (откалибруйте свои базelines)

  • Задачи на burst-хостах, всё ещё читающие PAT старше 30 дней: цель 0%; если недельная выборка >3%, откройте тикет исключения безопасности.
  • P95 ожидания мьютекса (секунды) только для шагов match/нотариуса; если P95 остаётся >600 с при растущей глубине очереди, добавьте хост серийного экспорта до увеличения параллелизма компиляции (порог иллюстративный).
  • Доля ошибок обмена OIDC-токенами по плоскости управления и регионам; если RTT STS растёт только для одного контура из шести регионов, чините сеть прежде чем поднимать параллелизм runner.

Почему в 2026 году «зайти по SSH и руками починить связку ключей» или универсальный замороженный .env в образе хуже, чем не вводить второй контроллер

Ручная работа со связкой не аудируется: кто последним разблокировал, осталась ли интерактивная сессия — это не доказательство для SOC2. Универсальный .env расширяет поражение от одного репозитория до любого, кто может запустить контейнер — противоположность принципу минимальных прав OIDC на задачу.

Когда Jenkins/Buildkite и runner должны сосуществовать на выделенном Apple Silicon со стабильным региональным egress и разделимыми арендами базовой линии и всплесков, облачный Mac mini MACCOME часто лучший физический якорь: узлы в Сингапуре, Японии, Корее, Гонконге, на восточном и западном побережье США с гибкими ежедневными/еженедельными/месячными/квартальными арендами. Зафиксируйте в регистре кто может сколько жить на каком хосте, прежде чем гнаться за пропускной способностью компиляции — не замораживайте 90-дневный PAT на ежедневном хосте с пятью симуляторами и тремя загрузками нотариуса.

Итог: сделайте CREDENTIAL_ROUTING.md соседом для CLONE_POLICY

Отгрузите три таблицы: машинный пользователь ↔ карта HOME, ресурсы мьютекса ↔ имена блокировок, доверие OIDC ↔ области STS. Новый сотрудник в первый день должен ответить, какую личность использует задача, какой класс токенов отзывать при сбое и почему на burst нет 90-дневного PAT.

Вместе с чеклистом секретов runner объедините «OIDC на стороне GitHub» и «партиции связки ключей macOS» в одном изменении — иначе политики доверия идеальны в облаке, а партиции на железе пусты.

FAQ

Могут ли Jenkins, Buildkite и runner GitHub Actions сосуществовать на одном хосте?

Да при разделении пользователей, партиций связки ключей и сериализации исключительных шагов; избегайте одного долгоживущего PAT на все стеки. Подробности очередей — в runbook поэтапной аренды. Публичные уровни аренды: цены аренды.

Зачем закреплять долгоживущие секреты на месячных хостах базовой линии?

Ежедневные хосты часто пересобираются; статические секреты утекают в образы или бэкапы. Baseline закрепляет аудиторскую идентичность. Контекст стоимости и операций снова: цены аренды Mac mini.