Матрица: SSH-сертификаты, HTTPS+credential helper, связка keychain и конкурентность
Выбор транспорта для Git на общей сборочной машине — это одновременно модель идентичности и модель хранения секретов. Ниже — ось решений для малых команд: что проще внедрить без отдельного секрет-менеджера и что устойчивее при частых ротациях.
| Критерий | SSH + пользовательские сертификаты (OpenSSH CA) | HTTPS + osxkeychain / store |
Раздел связки (keychain partition) | Риск при параллельных fetch |
|---|---|---|---|---|
| Где живёт секрет | Ключ + короткий сертификат; доверие к CA на сервере Git | PAT или пароль в связке macOS / кэше helper | Отдельный keychain-файл или группа доступа для CI-сессии | Низкий при разных ключах/сертификатах на субъект; следите за ControlMaster |
| Изоляция между людьми | Сильная: разные principals, отдельные каталоги ~/.ssh |
Средняя: нужен credential.useHttpPath и/или includeIf |
Сильная при разных login-узлах или отдельных учётках ОС | Средний: гонки записи в одну связку при лавине job |
| Ротация | Выпуск нового сертификата, отзыв serial/KRL | Новый PAT, обновление записи helper, отзыв старого в GitHub/GitLab | Замена элемента связки или файла keychain по runbook | Планируйте перекрытие: сначала канареечный клон, потом отзыв |
| Минимальные права | Deploy key / fine-grained scope на уровне репозитория | Fine-grained PAT: только нужные репо и права | Те же, плюс ACL файла связки | Не смешивайте «админский» токен с CI в одной связке |
Практическое правило: для людей — SSH CA или отдельные deploy keys с коротким TTL; для автоматизации на HTTPS — отдельная учётная запись ОС или изолированный GIT_CONFIG_GLOBAL + явный путь к PAT-файлу, который заполняет оркестратор, а не руками в интерактиве.
Изоляция credential helper и учётных записей
Типичный сбой на общем Mac — одна связка на хост для всех репозиториев GitHub. Git берёт первую подходящую запись и молча применяет чужой токен. Исправление начинается с различения путей и контекстов.
1. Включите учёт пути в URL для HTTPS (обязательно при нескольких репо на одном хосте):
git config --global credential.useHttpPath true
2. Разведите конфиги по каталогам проектов (разные команды или клиенты в ~/jobs/team-a и ~/jobs/team-b):
# ~/.gitconfig
[includeIf "gitdir:~/jobs/team-a/"]
path = ~/.gitconfig-team-a
[includeIf "gitdir:~/jobs/team-b/"]
path = ~/.gitconfig-team-b
В файле ~/.gitconfig-team-a задайте user.name, user.email и при необходимости credential.helper или insteadOf для отдельного зеркала.
3. SSH для Git с отдельным ключом и сертификатом на субъект (фрагмент ~/.ssh/config):
Host github.com-team-a
HostName github.com
User git
IdentityFile ~/.ssh/team_a_ed25519
CertificateFile ~/.ssh/team_a_ed25519-cert.pub
Затем git remote set-url origin git@github.com-team-a:org/repo.git. Так вы избегаете смешения с глобальным github.com в том же ~/.ssh/config.
4. Связка ключей и «partition» на macOS. Для неинтерактивного CI предпочтительны отдельная учётная запись macOS или контейнеризованный агент с собственным HOME: системный osxkeychain привязан к сессии пользователя. Если несколько job делят одного пользователя и один keychain, документируйте, кто может перезаписать запись (и используйте разные хост-псевдонимы в SSH config, как выше). Параллельные тяжёлые git clone на один диск сочетайте с политикой очереди и лимитов I/O на узле, чтобы не усиливать гонки вокруг credential cache.
Ротация PAT и проверка без простоя
Ротация без перекрытия — частая причина «все пайплайны красные». Используйте короткий цикл: новый токен → канареечный репозиторий → массовое обновление связки → мониторинг → отзыв старого.
- Создайте новый fine-grained PAT с теми же ограничениями по репозиториям и разрешениям (только
Contents: Readдля сборки без пуша). - На узле выполните
git ls-remote https://github.com/org/canary.gitиз каталога, где действует нужный helper, под тем же окружением, что и CI. - Обновите секрет в vault/runner; для хранения в файле — атомарная замена (write temp + rename) и корректные права
chmod 600. - Запустите один полный pipeline и один интерактивный
git fetch --allпод человеческой учёткой. - Отзовите старый PAT в интерфейсе провайдера после окна наблюдения (например 24–48 ч для глобальных очередей).
Проверки после смены:
GIT_TRACE=1 GIT_CURL_VERBOSE=1 git ls-remote origin 2>&1 | head -n 40
ssh -T git@github.com-team-a
Первый вывод покажет, что запрос ушёл с ожидаемым URL; для SSH второй шаг подтверждает аутентификацию без лишних запросов пароля.
Чеклист приёмки минимальных прав
Используйте список как внутренний sign-off перед тем, как включить нового участника или новый репозиторий на общем Mac.
- Scope токена или ключа: нет прав на удаление репозитория, нет широкого
admin, если нужен только fetch; для пуша — отдельный токен и отдельный remote или защищённая ветка. - Разделение субъектов: человек ≠ CI; разные файлы конфигурации или разные SSH Host aliases.
- useHttpPath и includeIf: включены для всех интерактивных пользователей на HTTPS.
- Аудит: в провайдере видны только ожидаемые токены; дата создания PAT совпадает с runbook ротации.
- Отзыв: документ с шагами «кто отзывает PAT при увольнении» и за сколько часов до отключения учётки.
- Нагрузочный тест: два параллельных
git fetchиз разных каталогов не меняют чужой контекст (проверка поgit config --show-origin --get-regexp credential).
FAQ
Вопрос: Почему на общем Mac два разработчика «перехватывают» чужой GitHub-токен при HTTPS?
Ответ: Часто виноват общий helper без учёта пути репозитория: Git кэширует одну связку «хост + пользователь» для всех URL. Включите useHttpPath, разделите конфиги через includeIf по каталогам или перейдите на SSH с отдельными principals/ключами на человека.
Вопрос: Как безопасно крутить fine-grained PAT, не роняя ночные сборки?
Ответ: Выпустите новый токен с теми же scope, обновите секрет в согласованном месте, выполните пробный fetch на канареечном клоне, затем отзовите старый PAT после окна наблюдения.
Вопрос: Параллельные git fetch из одного home ломают кэш учётных данных — что делать?
Ответ: Разведите контексты: отдельные каталоги с includeIf, разные GIT_CONFIG_GLOBAL для job, или сериализация шагов, которые пишут в один credential store.
Итог
На общем удалённом Mac устойчивая схема Git — это не «один токен на всех», а явные транспорты (SSH с ролями или HTTPS с путём и разнесёнными конфигами), предсказуемая ротация PAT и короткий чеклист приёмки по минимальным правам. Так вы снимаете класс инцидентов «сборка пошла от чужого имени» без тяжёлого вендор-локина.
Для команд, которым нужны несколько узлов, предсказуемая ёмкость и меньше конкуренции за один и тот же keychain, откройте главную Meshmac, выберите тариф с коллаборацией на странице покупки (без входа) и при необходимости загляните в центр помощи. Другие материалы — в разделе блога.
Несколько удалённых Mac под команду: меньше очередей за одни и те же секреты и диск
Разведите SSH и credential helper по узлам: оформите тариф для совместной работы на странице покупки — без входа в аккаунт. Узлы и возможности — на главной; справка — помощь; статьи — блог.