08 янв. 2026 г.·7 мин чтения

OIDC для CI/CD: замените долгоживущие облачные ключи в пайплайнах

OIDC для CI/CD позволяет GitHub Actions и GitLab обращаться к AWS и Google Cloud без сохранённых ключей. Узнайте шаги настройки, проверки и типичные ошибки.

OIDC для CI/CD: замените долгоживущие облачные ключи в пайплайнах

Почему сохранённые облачные ключи создают проблемы

Команды часто кладут облачные учётные данные туда, где это кажется достаточно безопасным. Добавляют AWS access key в секреты GitHub Actions, хранят JSON сервисного аккаунта Google в переменных GitLab CI/CD, копируют креды в файлы окружения раннера или прокидывают их через менеджер секретов в билд‑задания.

Такое решение работает, но создаёт скрытый риск. Секрет пайплайна может утечь через отладочные логи, скопированные конфиги, форкнутый проект, резервную копию или ноутбук разработчика, который использовал тот же ключ для теста.

Более серьёзная проблема — как долго может длиться ущерб. Если кто‑то получил статический облачный ключ, им можно часто пользоваться неделями или месяцами. Запуск пайплайна длится минуты, но украденный ключ остаётся действующим долго после завершения работы.

Ротация вручную кажется простой, пока не столкнётся с реальной работой. Одна команда обновляет секрет в GitHub, но забывает про staging‑раннер. Другая ротирует AWS‑пользователя, но пропускает старую плановую задачу. Люди откладывают это, потому что никто не хочет ломать деплой в пятницу.

Статические секреты тоже размножаются. Один ключ начинается в одном репозитории, потом попадает в скопированные шаблоны пайплайнов, локальные тестовые скрипты, аварийные заметки, заброшенные проекты и общие хранилища. Через некоторое время никто не знает, где осталась последняя рабочая копия. Это само по себе проблема безопасности.

Короткоживущий доступ решает ту часть, которая больнее всего. Если задача получает креденшиалы только на один запуск, окно утечки становится намного меньше. Злоумышленник не сможет повторно использовать прошлый месячный секрет, если этот секрет уже не существует.

Именно поэтому OIDC для CI/CD — это не просто уборка. Он сокращает разброс секретов, уменьшает боль ротации и позволяет пайплайну запрашивать у облака временный доступ только когда задача действительно в нём нуждается.

Как OIDC меняет поток входа

С OIDC для CI/CD задача запрашивает у платформы CI токен идентичности при старте. GitHub Actions или GitLab создаёт этот токен для конкретного задания и подписывает его. В токене есть клеймы, которые описывают, кто его выдал, для кого он предназначен и какой репозиторий, ветка, тег или pipeline его создал.

AWS или Google Cloud не принимают такой токен вслепую. Облако проверяет издателя, затем audience, затем subject и другие клеймы, которые вы используете в политике — например имя репозитория, ветку, окружение или путь проекта. Если эти значения соответствуют вашим правилам, облако возвращает временные креденшиалы. Если не соответствуют — задача ничего не получает.

В AWS задача обычно получает временную сессию роли. В Google Cloud Workload Identity Federation меняет CI‑токен на временный access token или даёт доступ сервисного аккаунта. В любом случае креденшиал истекает быстро, так что окно воздействия при утечке намного меньше, чем у долгоживущего облачного секрета.

Вот в чём суть. Задача не хранит сохранённый секрет в настройках репозитория, переменных CI или конфиге раннера. Она доказывает свою личность во время выполнения и получает доступ только на эту сессию.

Старую модель можно сравнить с пайплайном, который носит постоянный бейдж в кармане. OIDC работает скорее как ресепшн: задача показывает свежий подписанный пропуск, облако проверяет детали и выдаёт бейдж, который перестаёт работать вскоре после завершения запуска. Это небольшое изменение убирает множество мест хранения секретов и последующей уборки.

Что подготовить перед настройкой

OIDC для CI/CD проще внедрять, когда вы заранее сопоставите доступ. Многие команды начинают с облачной стороны, а потом получают роли слишком широкими или правила доверия, которые никто не понимает через неделю.

Начните с простого инвентаря. Выпишите каждый репозиторий и отметьте задания, которые действительно нуждаются в доступе к облаку. Во многих пайплайнах тесты, линтинг и локальные сборки не требуют облачной идентичности. Обычно кандидатами являются публикация образа, применение инфры и шаги деплоя.

Для каждой задачи запишите четыре вещи: какой репозиторию она принадлежит, какой конкретный шаг требует доступа, нужны ли права чтения, записи или деплоя, и какая ветка или тег может её триггерить. Это небольшое упражнение экономит время позже.

Раннее разделение прав для сборки и деплоя важно. Задача сборки может только пушить образ или выгружать артефакт. Задача деплоя меняет живые системы, поэтому должна использовать другую роль AWS или другой сервисный аккаунт Google Cloud с более строгими правилами доверия.

Это важнее, чем кажется. Если токен одной задачи утечёт в логах или workflow поменяется по ошибке, ущерб будет меньше, когда роль покрывает одну узкую задачу.

Будьте конкретны, кто может принимать каждую роль. Решите, будет ли это main, защищённые ветки, теги релизов или плановые pipeline. Например, можно позволить main деплоить в staging, разрешить только подписанным release‑тегам деплой в продакшен и не давать облачный доступ feature‑веткам.

Проверьте первый rollout вне продакшена. Выберите один репозиторий с низким риском и один не‑продакшен аккаунт или проект. Запустите pipeline, посмотрите выданную идентичность и убедитесь, что запрещённые действия корректно блокируются. Хорошая OIDC‑настройка должна блокировать неверную ветку, тег или задачу без драм.

Команды, работающие с несколькими репозиториями или окружениями, часто добиваются лучших результатов, если делают дизайн скучным: мало ролей, понятные правила доверия и постепенный rollout на staging. Такой подход делает переход от статических кредов спокойнее.

Подключение GitHub Actions к AWS

GitHub Actions может входить в AWS без сохранённых секретов. AWS доверяет токену, который GitHub выдаёт для одного задания, затем даёт этой задаче временную сессию роли. Если правила доверия жёсткие, workflow из неверного репозитория или ветки не сможет им воспользоваться.

Начните в AWS IAM с добавления GitHub как OpenID Connect провайдера. AWS использует этого провайдера, чтобы проверять токен, который GitHub Actions отправляет во время запуска.

Затем создайте IAM‑роль, которую workflow будет принимать. Политика доверия важнее, чем многие команды ожидают. Не давайте права всем репозиториям в вашей организации. Ограничьте роль конкретным репозиторием и, по возможности, конкретной веткой или шаблоном тега, который должен деплоить.

На практике правило доверия обычно делает четыре вещи: позволяет GitHub OIDC‑провайдера как федеративного принципала, требует audience, который ожидает AWS, матчит subject‑клейм на один репозиторий и сужает доступ до refs/heads/main или другой утверждённой ветки.

Это уже убирает много рисков. Pull request из форка, тестовый репозиторий или случайная ветка не должны иметь доступа к production.

Дальше добавьте только те права AWS, которые действительно нужны задаче. Если workflow только пушит контейнер в ECR, дайте ему права ECR. Если он выгружает артефакт в S3, дайте доступ только к тому бакету и пути. Избегайте широких прав администратора ради первого запуска.

В GitHub workflow запросите ID‑токен и затем предположьте роль. Задаче нужен id-token: write, чтобы GitHub мог выпустить токен, и обычно contents: read, чтобы читать репозиторий. Затем используйте ARN роли AWS в шаге аутентификации.

Прежде чем запускать команды деплоя, протестируйте с простой проверкой идентичности. Выполните aws sts get-caller-identity и подтвердите, что аккаунт, роль и имя сессии соответствуют ожиданиям. Эта команда быстро ловит большинство ошибок настройки.

Для безопасного первого релиза направьте один не‑продакшен workflow на новую роль, проверьте проверку идентичности и затем удалите старые статические ключи из секретов репозитория. Такой порядок делает изменение небольшим и легко откатываемым, если правило доверия окажется слишком строгим.

Подключение GitLab к AWS

Split Build and Deploy Access
Separate roles and permissions before one broad policy causes trouble.

GitLab может получать временные AWS креденшиалы во время задачи, что позволяет перестать хранить access key в CI‑переменных. Самое важное здесь — доверие. Решите, какие клеймы GitLab должен принимать в AWS, и держите этот диапазон узким.

Большинству команд стоит доверять одному проекту и одному ref. Например, разрешите mygroup/myapp на main или защищённые теги для релизов. Если вы доверяете каждой ветке в группе, любой случайный pipeline может получить ту же роль.

Создание доверия в AWS

В AWS IAM добавьте GitLab как OpenID Connect провайдера. Если вы используете GitLab.com, issuer — https://gitlab.com. Если вы запускаете собственный GitLab, используйте ваш URL GitLab. Установите audience в sts.amazonaws.com.

Затем создайте роль для пайплайна и зафиксируйте её политику доверия на клеймах GitLab. Часто используют сопоставление по sub, например project_path:mygroup/myapp:ref_type:branch:ref:main. Это привязывает роль к одному репозиторию и одной ветке. Если вы также деплоите из тегов, создайте отдельное правило для тегов вместо расширения ветки.

Держите политику прав узкой сначала. Дайте роли только то, что действительно нужно задаче, и начните с проверки только на чтение перед любым деплоем.

Обновление задачи в GitLab

Попросите GitLab выпустить ID‑токен для задачи, запишите этот токен в файл и позвольте AWS CLI использовать его как web identity credentials.

aws-check:
  image: amazon/aws-cli:2
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: sts.amazonaws.com
  script:
    - echo "$GITLAB_OIDC_TOKEN" > /tmp/web_identity_token
    - export AWS_ROLE_ARN=arn:aws:iam::123456789012:role/gitlab-deploy
    - export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/web_identity_token
    - aws sts get-caller-identity

aws sts get-caller-identity — хороший первый тест, потому что доказывает, что предположение роли сработало без изменения чего‑либо. Когда это пройдёт, добавьте реальные команды деплоя и удалите старые CI‑секреты.

Обычно это небольшое изменение в GitLab, но оно закрывает очевидную дыру: вы удаляете секрет, который мог утечь, заставляете каждую ветку доказывать свою личность и по умолчанию делаете доступ к AWS временным.

Подключение CI к Google Cloud

В Google Cloud OIDC для CI/CD обычно реализуется через Workload Identity Federation. Ваша CI‑задача получает OIDC‑токен от GitHub Actions или GitLab, Google проверяет этот токен и затем выдаёт временные креденшиалы. Вам больше не нужно хранить JSON ключи сервисных аккаунтов в переменных проекта.

Начните с создания пула Workload Identity, затем добавьте провайдера для вашей CI‑системы. Провайдер сообщает Google, какого издателя доверять и какие клеймы читать. Для GitHub команды часто используют клеймы repository, ref и sub. Для GitLab распространены project_path, ref и sub.

Сопоставление клеймов очень важно. Если вы доверяете только издателю, любой репозиторий на этой платформе сможет попытаться получить доступ. Промапьте репозиторий или путь проекта в атрибуты Google Cloud и, если можно, сопоставьте ветку. Это позволит вам сказать "только этот репозиторий" или "только этот проект на ветке main", а не доверять всем пайплайнам.

Далее свяжите сервисный аккаунт с набором доверенных принципалов, полученных из этих атрибутов. На практике вы даёте roles/iam.workloadIdentityUser на сервисный аккаунт этому набору принципалов. Затем выдайте сервисному аккаунту только те роли, которые нужны задаче: чтение одного бакета или права деплоя для одного сервиса.

Обмен токенов происходит во время задачи. CI‑платформа выдаёт OIDC‑токен, Google Security Token Service принимает его, и задача получает временный доступ, связанный с сервисным аккаунтом. Большинство команд использует auth‑action или небольшой шаг логина, а затем запускает gcloud или SDK как обычно.

Безопасный первый тест — выполнить:

gcloud auth list

Если настройка корректна, gcloud покажет федеративный или имитируемый аккаунт вместо возврата к старому креду. После этого выполните одну команду только для чтения для сервиса, который вы собираетесь использовать. Если чтение работает и старый секрет нигде не используется, вы близки к полному переходу от статических облачных кредов.

Простой пример миграции

Check Audit Logs First
See the real identity in cloud logs before you delete old secrets.

Небольшая команда часто начинает с одной задачи деплоя и двух сохранённых секретов: AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY. Задача работает, но эти секреты месяцами сидят в настройках репозитория, и любой, кто может запустить нужный workflow, может ими воспользоваться.

Более безопасная миграция начинается с этой единственной задачи. Сохраняйте всё как есть в остальном для первого теста. Измените только способ получения облачного доступа.

Раньше:

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

После изменения workflow запрашивает у CI‑платформы OIDC‑токен и меняет его на временную AWS‑сессию. В GitHub Actions это обычно значит добавить id-token: write и принять IAM‑роль, которая доверяет только вашему репозиторию и ветке.

permissions:
  id-token: write
  contents: read

Затем заблокируйте деплой в production только для main. Политика доверия IAM проверяет клейм ветки, а сам workflow выполняет шаг деплоя только при пуше в main. Получается две блокировки вместо одной.

С форками нужно быть аккуратнее. Не давайте облачного доступа workflow, триггеримым pull_request из форков. Сборка и тест могут там выполняться, но деплой должен ждать доверенной ветки или защищённого окружения.

Простой rollout достаточен: оставьте старые секреты на месте во время первого прогона, переключите одну задачу деплоя на предположение роли через OIDC, деплойте в не‑продакшен цель, проверьте, что роль деплоит только из main, и убедитесь, что pull request из форка не добирается до AWS.

Когда это несколько раз отработает, удалите старые AWS секреты из настроек репозитория или группы и запустите pipeline снова. Если деплой всё ещё работает и никто не запрашивает удалённые секреты — миграция завершена.

GitLab идёт по тому же пути: используйте OIDC, доверяйте только защищённым веткам и держите форки и недоверенные pipeline подальше от облачных ролей.

Ошибки, которые ослабляют настройку

Самая частая ошибка — считать OIDC просто заменой старого секрета. OIDC уменьшает риск только если правила доверия остаются жёсткими. Если ваша облачная роль доверяет любому репозиторию, любой ветке или любому тегу от CI‑провайдера, вы просто переместили проблему секретов, но не решили её.

Задача деплоя не должна принимать токены из pull request'ов, личных форков или случайных feature‑веток. Ограничьте доверие конкретным репозиторием, конкретной веткой или защищённым тегом и контекстом workflow, который этого требует. Немного дополнительной работы при настройке блокирует много возможного ущерба.

Ещё слабое место — область доступа. Часто дают одной задаче широкие права администратора ради быстрого старта, и этот компромисс остаётся месяцами. Задача сборки обычно только пушит образ или читает бакет. Ей не нужны права менять IAM, удалять БД или трогать production‑секреты.

Использование одной роли везде — для сборки, тестов и деплоя — создаёт ту же проблему. Разделяйте их. Сборка публикует артефакты. Тесты читают тестовые ресурсы. Деплой меняет продакшен. Если один токен утечёт в логах или стороннее действие проявит себя плохо, радиус поражения будет меньше.

Несколько проверок важны всегда. Соотнесите subject токена с ожидаемым репозиторием и веткой. Проверьте audience, чтобы токен годился только для вашей облачной настройки. Создайте отдельные роли или сервисные аккаунты для разных задач. Уберите любые запасные пути, которые всё ещё позволяют использовать старые секреты.

Последняя точка часто подводит команды. Они завершают Workload Identity Federation, видят, что всё работает, и оставляют долгоживущие облачные ключи в CI‑переменных "на всякий случай". Потом какая‑то задача продолжает использовать старые креды или кто‑то копирует их в другой проект. Как только новый путь работает, удалите старые ключи, ротируйте всё, что было раньше, и сделайте так, чтобы пайплайн падал, если появляется статический креденшиал.

Хорошие настройки OIDC обычно скучные. Именно этого вы и хотите.

Быстрая проверка перед удалением старых ключей

Review Your OIDC Trust
Review GitHub, GitLab, AWS, or Google Cloud trust rules with Oleg.

Чистый переход требует доказательств, а не догадок. Прежде чем удалить старые секреты, запустите pipeline в том месте, которое разрешено вашей политикой доверия. Если правило говорит, что только main может предполагать роль AWS или сервисный аккаунт Google, триггерните задачу с main и подтвердите, что она проходит без сохранённого облачного ключа.

Затем попытайтесь специально его сломать. Запустите ту же задачу из ветки, которой не должен быть доступ, например feature‑ветки или тестовой ветки для форков. Задача должна падать на шаге входа в облако. Такое отклонение так же важно, как и успешный прогон, потому что показывает, что правила доверия действительно ограничивают, кто может получить временные креды.

Проверьте журналы аудита облака сразу после обоих прогонов. В AWS подтвердите, что была принята ожидаемая роль. В Google Cloud убедитесь, что ожидался сервисный аккаунт через Workload Identity Federation. Вы хотите видеть реальную идентичность от вашей CI‑системы в логах, а не таинственного пользователя или старый access key.

Короткий чеклист поможет:

  • Запустить одну успешную задачу из разрешённой ветки.
  • Запустить одну заблокированную задачу из ветки вне правила доверия.
  • Просмотреть запись аудита для каждого прогона.
  • Удалить старые секреты только после успешного прохождения обоих тестов.
  • Записать правила доверия в командную документацию.

Последний шаг экономит время позже. Пропишите точные правила веток, названия репозиториев, настройки audience, имена облачных ролей или сервисных аккаунтов и любые subject‑клеймы, от которых вы зависите. Через шесть месяцев кто‑то может переименовать репозиторий, разделить монорепозиторий или добавить релизную ветку. Если правила хранятся только в голове одного инженера, настройка снова станет хрупкой.

Когда оба теста пройдены, удалите статические ключи из настроек CI, переменных проектов, хранилищ секретов и любых локальных скриптов‑запасников. Оставлять их «на всякий случай» разрушает весь смысл.

Что делать дальше

Начните с одного важного пайплайна, но такого, чей простой приостановки не причинит большого вреда. Часто лучше сначала заменить секрет в staging. Замените сохранённый облачный секрет на OIDC, прогоните несколько обычных задач и запишите, что изменилось.

Отслеживайте несколько результатов, чтобы команда могла оценить изменения по фактам: сколько сохранённых секретов удалено, сколько времени занял настрой и откат, какие ошибки доверия или прав появились и показывает ли аудит‑лог ожидаемую workload‑идентичность.

Когда один workflow хорошо работает, повторяйте ту же схему, не придумывая заново для каждого окружения. Держите имена ролей, проверки клеймов и правила веток или тегов простыми и понятными. Команды реже ошибаются, когда staging и production следуют одинаковому шаблону.

Не пропускайте человеческий фактор. Проведите короткую сессию с командой о двух наиболее частых ошибках, которые они увидят: облако отклоняет входящий токен, или токен проходит, но действие падает дальше потому что роли не хватает прав. Это кажется базовым, но экономит много времени при первом реальном инциденте.

Короткая шпаргалка тоже полезна. Если вход не проходит, проверьте правило доверия, issuer, audience, subject‑клейм и условие ветки. Если вход проходит, но задача всё ещё падает, проверьте IAM‑политику или привязку ролей в Google Cloud.

Если ваша настройка охватывает GitHub Actions, GitLab, AWS и Google Cloud, полезно получить второе мнение перед массовым rollout. Oleg Sotnikov at oleg.is работает в качестве Fractional CTO и советника для стартапов, и такой обзор полезен, когда команда нуждается в помощи с ужесточением правил доверия, планированием порядка развертывания или очисткой инфраструктуры без добавления долгоживущих секретов.

Часто задаваемые вопросы

Какую проблему решает OIDC в CI/CD?

OIDC прекращает практику хранения в пайплайне долгоживущих облачных учётных данных. Задача доказывает свою личность во время запуска, а AWS или Google Cloud выдаёт короткоживущий доступ, который истекает вскоре после завершения запуска.

Нужны ли мне всё ещё сохранённые секреты AWS или Google Cloud?

Нет. После завершения настройки конвейер может запрашивать временные учётные данные вместо чтения сохранённых AWS access key или JSON сервисного аккаунта Google из секретов.

Как лучше начать миграцию?

Начните с одной безопасной задачи деплоя, обычно это staging. Сделайте первый релиз небольшим, проверьте новый путь входа и удаляйте старый секрет только после того, как задача отработает несколько раз.

Какие задачи пайплайна должны получать доступ к облаку?

Давайте доступ только тем шагам, которым он действительно нужен: пуш образов, применение инфраструктуры или деплой. Тесты, линтинг и локальные сборки обычно не требуют облачной идентичности.

Как привязать GitHub Actions к одной роли AWS?

Создайте в AWS провайдера OpenID Connect для GitHub, затем роль, которая доверяет только вашему репозиторию и утверждённой ветке или тегу. В workflow добавьте id-token: write и проверьте настройку командой aws sts get-caller-identity до деплоя.

Как GitLab входит в AWS без сохранённого секрета?

Попросите GitLab выдать ID‑токен для задачи, запишите этот токен в файл и дайте AWS CLI использовать web identity, чтобы предположить роль. Уточните правило доверия так, чтобы доступ был только у одного проекта и одного ref, например main или защищённых тегов.

Как это работает с Google Cloud?

Используйте Workload Identity Federation. CI‑задача получает OIDC‑токен от GitHub или GitLab, Google проверяет клеймы вроде repository или project_path и ref, затем задача получает временный доступ, связанный с сервисным аккаунтом.

Должны ли pull request'ы из форков получать OIDC‑доступ к облаку?

Нет. Разрешайте сборку и тесты для форков, но держите роли деплоя вне досягаемости форков. Давайте облачный доступ только доверенным веткам, защищённым тегам или защищённым окружениям.

Как проверить настройку перед удалением старых секретов?

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

Какие ошибки делают настройку OIDC небезопасной?

Частые ошибки — это чрезмерное доверие и широкие права. Разрешают любой репозиторий или ветку, используют одну широкую роль для сборки и деплоя или оставляют старые статические учётные данные в CI как запасной вариант.

OIDC для CI/CD: замените долгоживущие облачные ключи в пайплайнах | Oleg Sotnikov