Последнее обновление: 11 сентября 2026 года. Данные сверены с официальной документацией GitHub и Apple.

15 июля 2026 года GitHub изменил формат subject для репозиториев, созданных после этой даты: в нём используются идентификаторы владельца и репозитория. Это подтверждено в официальном справочнике GitHub Actions OIDC. Поэтому, если GitHub Actions OIDC внезапно перестал работать, сначала получите фактический OIDC-токен и проверьте iss, aud, sub, repository_id и owner_id. Затем обновите условие доверия в облаке. Не возвращайтесь сразу к постоянным облачным ключам. Apple-подпись и ключ App Store Connect при этом должны оставаться на изолированном доверенном Mac-узле.

Кому предназначен материал

Вы управляете GitHub Actions, облачными ролями и политиками федеративной идентификации в корпоративной среде.
Вы отвечаете за self-hosted runner, Xcode, удалённый Mac и производственный выпуск приложений.
Вы планируете переименование, перенос репозитория или внедрение единого OIDC-шаблона для организации.

01

Сначала измерьте фактическое утверждение идентичности

Почему GitHub Actions OIDC внезапно перестал входить в облако

В большинстве таких инцидентов файл workflow не менялся. Ошибка появляется на границе между двумя системами: GitHub выпускает токен с одним sub, а облачная роль принимает только другое значение. Переименование или перенос репозитория также может привести к переходу на неизменяемый subject, поэтому старое условие доверия перестаёт совпадать.

OIDC-токен GitHub содержит несколько разных утверждений:

  • iss — издатель токена;
  • aud — назначение, для которого он выпущен;
  • sub — субъект, на основании которого обычно строится условие доверия;
  • repository_id — числовой идентификатор репозитория;
  • owner_id — идентификатор владельца;
  • сведения о ветке, Environment или reusable workflow, если они входят в выбранный шаблон.

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

GitHub отдельно документирует запросы к OIDC-интерфейсу и получение метаданных токена в справочнике OIDC REST API. Используйте тестовый репозиторий и удаляйте значение id_token после разбора. Полный JWT не должен попадать в тикет, чат или систему логирования.

Сравнение форматов subject и диагностических выводов

Вариант Что проверять в токене Типичный вывод для исправления
Старый формат Имя организации, имя репозитория, ветка или Environment Политика может всё ещё ссылаться на прежний sub
Неизменяемый формат owner_id, repository_id, ветка или Environment Обновляйте доверие по фактическому subject, а не по названию
Пользовательский шаблон Порядок и состав полей, заданные организацией Сверяйте шаблон GitHub с политикой облачной роли
Ошибка aud Аудитория токена и ожидаемое значение сервиса Проблема не в переименовании, а в несовпадении назначения
Ошибка iss или подписи Издатель и проверка ключей Проверяйте провайдер идентичности, а не workflow

Таблица помогает отделить изменение декларации от другой ошибки авторизации. Если sub совпадает, но отличается aud, расширять разрешённые субъекты опасно: вы исправите не тот параметр.

Важно. OIDC-токен GitHub и временный токен облачного провайдера — разные объекты. Первый подтверждает происхождение задачи, второй выдаётся после успешной проверки доверия. Не храните ни один из них как постоянный секрет.

Минимальная процедура извлечения

  1. Создайте отдельную диагностическую ветку или тестовый репозиторий.
  2. Выдайте разрешение id-token: write только нужной задаче, а не всей организации.
  3. Запросите токен через стандартный OIDC-механизм GitHub Actions.
  4. Разберите заголовок и полезную нагрузку локально, не отправляя JWT во внешние сервисы.
  5. Запишите только имена полей и замаскированные значения.
  6. Сопоставьте iss, aud, sub, repository_id и owner_id с текущей политикой доверия.
  7. Сохраните результат в закрытом инциденте вместе с хэшем версии workflow.

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

02

Сопоставьте доверие облака с источником изменения

Что менять после переименования или переноса репозитория

Сначала зафиксируйте текущую облачную политику. В ней может проверяться:

  • полный sub;
  • организация и репозиторий;
  • конкретная ветка;
  • Environment;
  • aud;
  • reusable workflow;
  • комбинация нескольких условий.

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

Разделяйте три состояния:

  • новый репозиторий автоматически получает новый формат;
  • существующий репозиторий добровольно переходит на неизменяемый subject;
  • администратор применяет организационный пользовательский шаблон.

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

Почему изменение только workflow обычно не помогает

Workflow управляет запросом токена и разрешениями задачи. Облачный провайдер решает, доверять ли полученному утверждению. Если в workflow добавлено id-token: write, но политика по-прежнему ожидает старый sub, авторизация останется неуспешной.

Проверка должна идти в таком порядке:

  1. журнал неудачной задачи;
  2. фактический sub и aud;
  3. провайдер OIDC в облаке;
  4. условие доверия целевой роли;
  5. разрешения роли после успешного обмена;
  6. ограничения ветки и Environment.

Не меняйте одновременно subject, audience, разрешения роли и секреты. Иначе после восстановления вы не сможете определить, какая именно правка устранила сбой.

Восстановление без возврата к постоянному ключу

Постоянный ключ в GitHub Secrets может быстро вернуть соединение, но увеличивает радиус компрометации. Он не связан с конкретной веткой, Environment или запуском так же строго, как короткоживущая федеративная сессия. Для корпоративного конвейера это плохой откат, если OIDC-провайдер продолжает работать.

Используйте временный обход только при наличии отдельного согласования, срока отключения и аудита. Лучше:

  • восстановить правильный sub;
  • сохранить ограничение aud;
  • оставить доверие привязанным к нужному Environment;
  • проверить отказ для неразрешённой ветки;
  • удалить аварийный секрет после успешной проверки.
03

Ограничьте права задачи и разделите Mac-уровни

Почему широкая маска subject — опасное «исправление»

Условие вроде «любой репозиторий организации» может устранить ошибку сопоставления, но одновременно дать облачную роль нежелательным workflow. Особенно рискованны pull request из непроверенных источников, тестовые ветки и reusable workflow с неясным владельцем.

Сформируйте три списка:

  • разрешённые субъекты — конкретные репозитории, ветки, Environments или утверждённые workflow;
  • запрещённые источники — внешние pull request, экспериментальные ветки, неутверждённые окружения;
  • доказательства проверки — журналы, версия политики, результат отрицательного теста и одобрение владельца ресурса.

На уровне workflow проверьте минимальные права:

  • id-token: write только для Job, который обменивает токен;
  • contents: read, если запись в репозиторий не нужна;
  • отсутствие доступа к секретам в задаче, которая обрабатывает недоверенный код;
  • обязательное одобрение для производственного Environment;
  • отдельные условия для сборки и публикации.

Документ GitHub о безопасном использовании self-hosted runner предупреждает о повышенном риске для узлов, которые выполняют недоверенный код. Поэтому self-hosted runner нельзя считать просто более быстрым исполнителем задач. Он является границей доступа к локальной файловой системе, SSH-агенту, Keychain и кэшу сборки.

OIDC не заменяет Apple-секреты

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

  • сертификат Apple Distribution;
  • сертификат Developer ID;
  • закрытый ключ подписи;
  • ключ App Store Connect API;
  • профиль и разрешения, необходимые для выпуска приложения.

Apple описывает создание ключей для App Store Connect API в официальной документации Apple Developer. Отдельно описаны управляемые Apple облачные сертификаты. Эти механизмы нельзя смешивать с OIDC-потоком GitHub.

Для производства разделите задачи на уровни:

  • уровень 1 — недоверенный код: проверка, тесты и статический анализ без доступа к подписывающим секретам;
  • уровень 2 — облачный доступ: получение временного токена через OIDC для конкретной роли;
  • уровень 3 — сборка Xcode: доступ к необходимым инструментам и артефактам;
  • уровень 4 — подпись и публикация: изолированный доверенный Mac с отдельным Keychain и контролем Environment.

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

Как изолировать self-hosted runner на удалённом Mac

Сценарий с удалённым Mac удобен для Xcode и Apple toolchain, но общий узел создаёт остаточные риски. После задачи на диске могут остаться исходники, архивы, логи, временные ключи и кэш зависимостей.

Примените минимум пять технических мер:

  1. Используйте отдельные группы Runner для тестовых, облачных и подписывающих задач.
  2. Запрещайте маршрутизацию публикации на общий Mac, предназначенный для сборок.
  3. Создайте отдельную учётную запись и отдельный Keychain для производственной подписи.
  4. Очищайте рабочий каталог, временные файлы и логи после каждой чувствительной задачи.
  5. Ограничьте SSH-доступ и не передавайте агент ключей в обычные Job.
  6. Перезапускайте Runner после аварийной остановки или подозрительного задания.
  7. Проверьте, что резервный узел не получает производственные секреты автоматически.

Для организации, которая только проверяет архитектуру, полезен отдельный пилот аренды удалённого Mac. Но аренда не устраняет требования к изоляции: вы всё равно должны определить, какие Job могут попасть на узел и какие данные удаляются после выполнения.

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

04

Примите решение по метрикам аудита и восстановления

Минимальный набор производственных проверок

До возврата потока в штатную эксплуатацию проведите положительные и отрицательные тесты:

  1. Разрешённая ветка получает OIDC-токен и временный облачный доступ.
  2. Разрешённый Environment проходит требуемое одобрение.
  3. Неразрешённая ветка получает отказ.
  4. Внешний pull request не получает производственные секреты.
  5. Reusable workflow допускается только при совпадении ожидаемого источника.
  6. Тестовый Mac Runner не видит Keychain подписывающего узла.
  7. После перезапуска Runner задача корректно возвращается в допустимую группу.
  8. При отказе основного узла публикация не переключается на неподготовленный общий Mac.

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

Контрольный список допуска

Перед включением продуктивных запусков ответьте «да» на каждый пункт:

  • фактический sub получен из тестового токена;
  • iss и aud совпадают с настройками провайдера;
  • политика учитывает актуальные owner_id и repository_id, если они присутствуют;
  • условия ветки и Environment не заменены широкой маской;
  • id-token: write выдан только нужной Job;
  • облачная роль не даёт лишних операций;
  • Apple-ключи не используются как замена OIDC и не лежат в общей задаче;
  • self-hosted runner разделён по уровню доверия;
  • рабочая директория и временные данные очищаются;
  • зафиксирована процедура отзыва и аварийного возврата;
  • есть резервный доверенный узел или понятный ручной процесс выпуска.

Если хотя бы один ответ отрицательный, не увеличивайте параллелизм публикации. Сначала устраните пробел и повторите отрицательный тест.

Когда удалённый Mac оправдан, а когда нет

Постоянно общий Mac дешевле по операционным действиям, но его сложнее безопасно разделить между сборкой и подписью. Одноразовый Runner уменьшает остаточные данные, однако требует автоматизированного создания среды и проверки маршрутизации. Специализированный Mac для публикации дороже в управлении, зато проще доказать, что производственный Keychain не доступен обычным задачам.

Вам нужен выделенный узел, если:

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

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

После исправления OIDC проверьте, не оказались ли облачная роль, Runner и Apple-подпись на одной общей машине. Временный обход через широкое доверие или постоянный ключ действительно может убрать красную ошибку в CI, но оставляет скрытый доступ для других задач. Если текущая инфраструктура не позволяет разделить эти уровни, попробуйте отдельный удалённый Mac как контролируемый пилот: описание доступных Mac-конфигураций и аренды поможет оценить узел для сборки, а не подменить им вашу модель безопасности.

Перед запуском согласуйте срок пилота, список Job, порядок очистки, процедуру перезапуска Runner и условия передачи публикации на резервный узел. Такой подход обычно надёжнее, чем постоянное расширение sub до уровня всей организации.