Почему ротации deploy-ключа недостаточно
Боль 1: две цепочки доверия. Аутентификация пользователя и идентичность сервера в SSH разделены. После переустановки macOS, если крутить только GitHub deploy key, появится WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED — это не баг pinning, а отсутствие runbook host key.
Боль 2: big-bang в полночь. Новый Ed25519, мгновенное удаление RSA, Secret без перекрытия — десятки workflow падают одновременно.
Боль 3: UpdateHostKeys не обновляет CI. UpdateHostKeys yes помогает интерактивным клиентам. CI с StrictHostKeyChecking=yes требует две строки в Secret на время окна.
Боль 4: ControlMaster скрывает тайминг. Мультиплексные сессии держат старый контекст. См. матрицу ControlMaster и очистите ControlPath.
Боль 5: OIDC не заменяет отпечаток. Токены из OIDC-конвейеров аутентифицируют клиента, а не то, что достигнутый хост — ваш builder.
Перед ротацией: ssh-keygen -lf для всех ssh_host_*_key.pub и сверка с реестром из статьи known_hosts.
Боль 6: семантические ошибки после host key. После восстановления связи падают glob или права — сначала сеть, потом семантика загрузки.
Боль 7: compliance без ops. В аудите добавьте строку про отпечатки host key и доказательство окна перекрытия.
Матрица: двойной ключ, на месте или жёсткое переключение
Двойной ключ с перекрытием (рекомендуется). Сервер предлагает RSA и Ed25519; Secret содержит обе строки; legacy убирают после canary.
Только смена алгоритма на сервере. Один файл ключа, UpdateHostKeys для ноутбуков — CI всё равно обновляет Secret.
Жёсткое окно обслуживания. Допустимо для одного потребителя; рискованно для многих репозиториев.
Новое имя хоста. builder-v2.internal со свежим pinning и переключением DNS.
Матрица: владелец, имя Secret, конец перекрытия, rollback (архив .pub).
Бастионы: координированная ротация jump и цели.
Отдельные окна для staging и production.
Депрекация RSA host key — планируйте перекрытие дольше 24 часов при legacy-инструментах.
На удалённом Mac: Ed25519 и sshd
Ключи хоста в /etc/ssh/ssh_host_*. Генерация: ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" с админ-консоли, не в CI.
Добавьте HostKey для Ed25519 в sshd_config.d/, оставьте RSA/ECDSA на период перекрытия. sudo sshd -t, контролируемый reload.
Современные клиенты выбирают Ed25519; старые — RSA, пока сервер предлагает оба. Зафиксируйте тип в тикете через ssh -vvv.
Удаляйте legacy HostKey после зелёного canary. Архивируйте .pub.
MDM не должен затирать фрагменты sshd при синхронизации.
ssh-keyscan должен идти тем же путём, что CI — учитывайте split DNS.
Тест: ssh -o HostKeyAlgorithms=ssh-ed25519 и без ограничения.
Клиенты и CI: UpdateHostKeys и перекрытие Secret
На ноутбуках: Host builder-*, UpdateHostKeys yes, явный StrictHostKeyChecking.
В CI: StrictHostKeyChecking=yes, UserKnownHostsFile, Secret с двумя строками — см. руководство по pinning.
HashKnownHosts — приватность скриншотов; внутренняя таблица соответствия для аудита.
Версионируйте имена Secret; RSYNC_RSH через composite action.
Завершите устаревшие ControlMaster — статья keepalive.
Forks без наследования Secrets дают «случайные» сбои — широкое оповещение.
SFTP batch и rsync — один canary на оба пути.
Запрет StrictHostKeyChecking=no на default branch.
Когда OpenSSH ужесточает политику к слабым RSA host keys, миграция на Ed25519 — подготовка к клиентам, которые откажутся от старых типов. Держите RSA параллельно, пока люди и CI не подтвердят canary Ed25519.
Если вы совмещаете графический SFTP и rsync в CI, тестируйте оба пути после каждого изменения HostKey: один sshd, но кэш сессий может различаться.
Бастион и builder Mac должны попадать в одно change advisory — частичная ротация выглядит как «нестабильная сеть».
В мультиоблаке центральный реестр host key не даёт каждому региону плодить слегка разные Secrets после локального ssh-keyscan.
Операционная последовательность: сгенерировать, sshd -t, перекрыть Secret и HostKey, canary, объявить OVERLAP_END, убрать legacy — без временного StrictHostKeyChecking=no.
Проверьте, что workflow_dispatch canary включён в календарь релизов инфраструктуры, а не только в памяти старшего SRE.
При аренде Mac у провайдера уточните, кто правит sshd_config — вы или поддержка; иначе Ed25519 появится с одной стороны, а Secret останется на RSA.
Свяжите ротацию с матрицей OIDC: короткоживущие токены не освобождают от обновления known_hosts, они решают другую задачу.
Для rsync через RSYNC_RSH экспортируйте те же опции UserKnownHostsFile, что и для ssh — расхождение даёт «работает вручную, падает в CI».
После успешной ротации зафиксируйте уроки: сколько минут длилось перекрытие, сколько job упало, был ли откат — это питает следующий цикл оценки рисков.
Если в организации принят HashKnownHosts, храните таблицу hash→hostname в закрытом vault, а не в общем wiki.
Тестируйте sftp -b batch после ssh canary: batch-режим иногда использует иной набор опций, если composite action не унифицирована.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Дополнительная практика: включите в Definition of Done инфраструктурного тикета пункт «Secret и sshd_config обновлены, canary зелёный, legacy снят» — без галочки релиз приложения не стартует.
При смешанных runner macOS и Linux помните: host key привязан к целевому Mac, а не к ОС runner — один и тот же pinning для обоих.
Проверка, порядок чтения и откат
Workflow workflow_dispatch: ssh BatchMode и rsync --dry-run перед удалением legacy HostKey.
Метрики: Host key verification failed отдельно от Permission denied.
Откат: вернуть HostKey, Secret, sshd -t, архивные .pub.
Порядок: known_hosts, эта статья, ControlMaster, OIDC.
Сообщите конец перекрытия владельцам Org Secrets.
Квартальный drill на staging с откатом.
Canary по регионам egress при нескольких зонах runner.
Composite action с known_hosts_secret снижает импровизацию.
Не отключайте проверки — расширяйте HostKey и Secret параллельно, canary, затем удаляйте legacy.
Платформенным командам полезно вести host key как версионируемый артефакт с владельцем и датой конца перекрытия — наравне с lockfile инфраструктуры.
После Time Machine или клона диска проверьте /etc/ssh/ — иначе CI увидит третий неожиданный отпечаток.
В аварии не отключайте StrictHostKeyChecking — расширьте HostKey и Secret, canary, затем уберите legacy.
В runbook инцидента разделяйте «отказ проверки host key» и «permission denied после аутентификации» — иначе chmod на SFTP чинят то, что не дошло до нужного сервера.
Для подписанных iOS/macOS артефактов канал загрузки так же чувствителен, как хранилище секретов: плановая ротация лучше пятничного StrictHostKeyChecking=no.
Хостинг-провайдеры Mac объявляют окна обслуживания при смене железа — синхронизируйте GitHub Secrets и canary накануне.
Один Org Secret на много репозиториев требует общей таблицы ротации, иначе пять слегка разных ssh-keyscan-строк пройдут аудит как «пять правд».
В тикет заносите порт, DNS-алиас и согласованный алгоритм — аудиторы сравнивают политику с фактом в CI.
Self-hosted runner на долгоживущей VM тоже нуждается в изолированном UserKnownHostsFile — тестовые записи засоряют прод.
После снятия legacy RSA HostKey на сервере храните архив .pub минимум один релизный цикл для отката.
Связывайте ротацию host key с SHA256-гейтами на артефактах: один тикет — сеть и байты релиза.
При ProxyJump ротируйте бастион и цель согласованно; иначе «нестабильный SSH» маскирует частичное обновление.
Квартальный drill на staging с откатом из архива .pub тренирует команду без риска для продакшена.
Composite Action с параметрами known_hosts_secret и overlap_end_date снижает импровизацию в каждом репозитории при очередной смене ключа.
Не путайте ротацию пользовательского deploy key с host key: в одном change должны быть оба пункта, если оба меняются.
После зелёного canary удалите старую строку из Secret в тот же день, что и legacy HostKey на сервере — рассинхрон даёт окно, где CI доверяет ключу, который сервер уже не предлагает.
Для нескольких регионов egress запускайте canary в каждом — одинаковые отпечатки при согласованном DNS; расхождения указывают на прокси, а не на Mac.
OpenSSH на macOS может читать фрагменты из sshd_config.d — убедитесь, что MDM не перезапишет ваш ed25519.conf при следующей синхронизации флота.
Окно перекрытия — как совместимость API: старые клиенты и strict CI сосуществуют до задокументированной даты окончания.
WARNING на ноутбуках разработчиков — сигнал к выравниванию по runbook, а не повод стирать ~/.ssh/known_hosts без тикета.
Если builder обслуживает несколько продуктовых линий, заранее согласуйте одно OVERLAP_END — иначе одна линия удалит legacy-строку, пока другая ещё на RSA.
Логируйте в canary согласованный алгоритм (ssh -vvv) без утечки приватных ключей — достаточно типа host key и усечённого SHA256.
FAQ и хостинг Mac
Центральный реестр host key рядом с CMDB — alias, порт, тип, SHA256, Secret, конец перекрытия — убирает устаревшие вставки из wiki.
Обязателен ли Ed25519?
Рекомендуется для новых host keys; RSA можно держать в перекрытии.
UpdateHostKeys меняет Secret CI?
Нет — strict pinning требует ручных строк.
Что логировать?
Усечённые отпечатки, тикет, конец перекрытия — без пользовательских приватных ключей.
Когда помогает SFTPMAC?
Анонсированные окна обслуживания и runbook ingress без своей флотилии.
Итог: ротация на сервере и у клиентов — Ed25519 на Mac, перекрытие в Secrets, UpdateHostKeys для людей, strict pinning для CI.
Перекрытие вместо big-bang; хостинг SFTPMAC объединяет анонсы отпечатков.
