feat(ci): деплой проверяет, к тому ли хосту подключился #3079

Merged
lekss361 merged 1 commit from chore/3029-ci-access-perimeter into main 2026-08-24 16:36:51 +00:00

1 commit

Author SHA1 Message Date
bot-backend
1a37c7e0f9 feat(ci): деплой проверяет, к тому ли хосту подключился
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m10s
CI / backend-tests (pull_request) Successful in 17m38s
Сегодня подлинность хоста не проверяется нигде: deploy-tradein.yml явно
ставил StrictHostKeyChecking=no, а во всех пяти вызовах appleboy/ssh-action
не задан fingerprint. Пока Forgejo, раннеры и прод жили на одной машине,
это было почти бесплатно. После переезда 30.08 тот же канал идёт через
интернет и уносит GHCR_PAT, OPENAI_API_KEY, OBJECTIVE_API_KEY,
GLITCHTIP_BACKEND_DSN и сам DEPLOY_SSH_KEY.

Вызовов оказалось пять, а не четыре: deploy-obsidian.yml тоже ходит на
DEPLOY_HOST с DEPLOY_SSH_KEY. Отпечаток добавлен во все.

Механизм инертен по конструкции самого действия, а не нашей ветвлёнкой:
appleboy/ssh-action@v1.0.3 -> drone-ssh 1.7.3 -> easyssh-proxy v1.5.0, где
hostKeyCallback = ssh.InsecureIgnoreHostKey() и сверка включается только при
непустом Fingerprint. Незаданный секрет = сегодняшнее поведение бит в бит.

Но инертность, безопасная для мержа, опасна для самого окна: забытый секрет
означал бы зелёный деплой через интернет без всякой проверки. Поэтому перед
каждым ssh-шагом стоит преамбула, которая при пустом секрете печатает
::warning с перечислением того, что именно едет по этому каналу. Warning, а
не отказ: секрета сегодня нет ни у кого, отказ сломал бы деплой в момент
мержа.

Ручной ssh в "Resolve deployed base SHA" отпечаток принять не может, ему
отдан отдельный секрет с known_hosts по той же схеме. Заодно расхождение
ключа перестало быть неотличимым от недоступного хоста: раньше 2>/dev/null
глотал "Host key verification failed" и печаталось обычное сообщение про
фолбэк на полную пересборку. Свойство fail-safe сохранено - при любой ошибке
RAW_SHA пустеет и включается build-all.

ops/selectel-ci-access.sh - аддитивная выдача CI-доступа на Selectel по
решению владельца "сейчас только добавляем, удаляем после переезда": ставит
отдельный ключ робота с from="адрес раннера", добавляет узкое правило ufw,
не трогая общее, и печатает план сужения, который сам не выполняет. Ни одной
команды, способной отрезать текущую сессию: sshd не перезапускается, default
policy ufw не трогается, в authorized_keys только дозапись.

Отзыв старого ключа, сужение правил и уборка секретов - в #3075, после
подтверждённого переезда.

Refs #3029, #3075, #3057, #2989
2026-08-24 19:16:56 +03:00