open atlas
↑ К треку
CI/CD-пайплайны CICD · 12 · 03

Окружения и гейты: required reviewers, wait-таймеры и защита веток

GitHub Environment ограничивает секреты и оборачивает деплой-джоб в protection rules: required reviewers форсят одобрение, wait-таймер создаёт окно выдержки, а deployment-branch-правила плюс защита веток дают лишь отревьюенному коду из main достичь production.

CICD Senior ◷ 16 min
Уровень
ОсновыJuniorMiddleSenior

В 2 часа ночи инженер запушил hotfix-ветку и, чтобы сэкономить время, навёл деплой-workflow прямо на неё. У джоба был прод-деплой-токен в области видимости, поэтому он отгрузил — прямо в прод, из неотревьюенной ветки, без второй пары глаз и без выдержки. Hotfix починил симптом и внёс баг похуже, и поскольку между «push» и «production» ничего не стояло, он достиг 100% пользователей за девяносто секунд. Ретро нашло, что реальный дефект — не плохой код; а то, что production был достижим любым, кто мог триггернуть workflow, из любой ветки, мгновенно. Фикс — поставить production за гейт, который нельзя пропустить: именованное окружение, что держит деплой-секрет, требует человеческого одобрения, которое деплоер не может выдать себе сам, принуждает короткую выдержку, чтобы плохой релиз поймать до расширения, и отказывается деплоить что-либо, кроме отревьюенного кода на main.

Окружение — ограниченная, гейтированная граница

GitHub Environment (production, staging) — две вещи разом: область для секретов и набор protection rules вокруг любого джоба, что нацелен на него. Джоб подписывается через environment: production, и в этот момент случаются три вещи. Первое: джоб получает доступ к секретам, ограниченным окружением — прод-деплой-токен живёт на окружении, а не свободно в репо, так что лишь джоб, успешно вошедший в production, может его увидеть. Второе: ран паузится до старта джоба, пока не удовлетворено каждое protection rule. Третье: деплой записывается на окружение, давая аудит-след кто-что-когда задеплоил. Инцидент из Hook невозможен в момент, когда прод-токен ограничен окружением, а окружение гейтировано, потому что больше нет пути от «триггернуть workflow» к «держать прод-кред», что не проходит через правила.

jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment: production      # ограничивает секреты + триггерит protection rules
    steps:
      - run: ./deploy.sh
        env:
          TOKEN: ${{ secrets.PROD_DEPLOY_TOKEN }}   # читаем лишь внутри `production`

Три protection rules

Каждое правило закрывает свой вид дыры. Читая инцидент из Hook, обрати внимание, какое именно правило его бы остановило — и заметь, что убирая любое из трёх, ты воссоздаёшь версию той же дыры. Правила окружения — то, что конвертирует «джоб, что может деплоить» в «управляемый деплой»:

  • Required reviewers (обязательные ревьюеры): ран блокируется, пока именованный человек или команда не одобрит деплой в UI GitHub. Критически, одобрение отдельно от код-ревью — оно гейтит акт деплоя этого рана в это окружение, и ревьюер, который и есть деплоер, обычно не может само-одобрить, так что отгрузка всегда требует второго человека. Это правило обошёл push в 2 ночи.
  • Wait timer (таймер ожидания): настраиваемая задержка (0–43 200 минут, т.е. до 30 дней), вставленная перед запуском джоба после одобрения. Короткий таймер — скажем, 10 минут — создаёт намеренное окно выдержки/отмены: очевидно-плохой релиз можно отменить до касания production, а canary перед ним имеет время отрапортовать.
  • Deployment branches (ограничение веток деплоя): ограничивают, какие ветки могут деплоить в окружение — обычно лишь main (или паттерн релизного тега). В сочетании с защитой ветки на main (обязательное PR-ревью, обязательные status checks, без прямых push) это гарантирует, что единственный код, что может достичь production — это код, отревьюенный и прошедший CI на защищённой ветке. Hotfix-ветка из Hook была бы отвергнута сразу.

Вместе три правила означают, что production не просто запаролен — он структурно недостижим, если только качество кода, человеческое суждение и таймер не прошли все три проверки. Убери любое — код прямого push, само-одобренный деплой, мгновенный взрыв — и открывается дыра, ровно та, в которую провалился инцидент.

Викторина

Деплой-джоб ставит `environment: production`, у которого настроены required reviewers. Почему ограничение прод-деплой-токена этим окружением (а не хранение его как secret репо) закрывает дыру hotfix'а в 2 ночи ещё до того, как кто-либо отревьюит код?

Required reviewers vs защита веток: два разных гейта

Частая путаница — считать защиту ветки и required reviewers избыточными. Они стерегут разное. Защита ветки управляет тем, какой код допущен в main — она о надёжности артефакта и срабатывает на момент merge. Required reviewers на окружении управляет тем, может ли этот конкретный ран деплоить сейчас — она об акте релиза и срабатывает на момент деплоя. Изменение может быть идеально отревьюено и смержено (защита ветки удовлетворена) и всё равно требовать намеренного, отдельно-одобренного решения толкнуть его в production в рабочие часы с кем-то наблюдающим (ревьюер окружения удовлетворён). Тебе нужны оба, потому что они падают по-разному: одна защита ветки даёт любому зелёному коммиту main авто-деплоиться без человека в петле на момент релиза; одно ревью окружения даёт человеку одобрить деплой кода, что никогда не ревьюился. Wait-таймер затем добавляет время к человеческому гейту, а deployment-branch-правила связывают двоих, гарантируя, что одобряемый ран реально происходит из защищённой ветки.

Викторина

Защита ветки на `main` уже требует PR-ревью перед merge. Зачем ещё настраивать required reviewers на окружении `production` — разве это не то же одобрение дважды?

Почему это работает

Зачем вообще разделять одобрение деплоя и код-ревью — разве одно одобрение не проще? Потому что они отвечают на разные вопросы в разное время. PR-ревью спрашивает «корректно ли это изменение?», когда код предложен; одобрение деплоя спрашивает «стоит ли релизить это, сейчас, этим пользователям?», когда артефакт вот-вот отгрузится — решение, что зависит от текущего состояния production, графика дежурств, идущего инцидента или change freeze, ничего из чего изначальный ревьюер знать не мог. Схлопывание их означает: либо ты теряешь решение на момент релиза (код авто-отгружается в момент merge), либо теряешь решение на момент merge (нет ревью диффа). Дизайн двух гейтов — то, что позволяет команде свободно мержить в защищённый main и всё же держать намеренный, человеческий, отменяемый момент перед каждым прод-релизом.

Вспомните перед уходом
  1. 01
    Объясни, как ограничение прод-деплой-секрета GitHub Environment в сочетании с required reviewers делает неотревьюенный мгновенный деплой невозможным.
  2. 02
    Почему защита ветки и required reviewers окружения не избыточны, и что каждое защищает?
Итог

GitHub Environment одновременно область секретов и гейт: джоб подписывается через environment: production, и лишь тогда может читать ограниченный окружением деплой-токен, лишь после того как ран паузится для каждого protection rule, и деплой записывается для аудита. Ограничение прод-токена окружением само по себе контроль — нет пути от триггера workflow к держанию прод-креда, что не проходит правила, и это делает инцидент неотревьюенный-hotfix-прямо-в-прод в 2 ночи структурно невозможным. Три правила компонуют цепь. Required reviewers форсят человеческое одобрение акта деплоя, отдельное от PR-код-ревью и невыдаваемое себе, так что каждый релиз требует второго человека на момент релиза. Wait-таймер — до 30 дней, но на практике короткая выдержка вроде 10 минут — вставляет окно отмены после одобрения, чтобы плохой релиз можно было отменить, а canary отрапортовать до расширения. Deployment-branch-правила ограничивают, какие ветки могут деплоить, обычно main или релизный тег, и в сочетании с защитой ветки main (обязательное ревью, обязательные checks, без прямого push) гарантируют, что лишь отревьюенный, прошедший CI код достигает production. Защита ветки и ревью окружения не избыточны: одно управляет тем, какой код входит в main на момент merge, другое — может ли ран деплоить сейчас на момент релиза, и они падают по-разному, поэтому держишь оба. Убери любое звено — код прямого push, само-одобренный деплой, мгновенный взрыв без выдержки — и ровно та дыра, в которую провалился инцидент, открывается вновь. Теперь, когда увидишь в пайплайне коллеги репозиторный секрет, напрямую подключённый к деплой-джобу, ты знаешь точно, чего не хватает и почему это важно в 2 ночи.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 6 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.