Последнее обновление: 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-шаблона для организации.
Сначала измерьте фактическое утверждение идентичности
Почему 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 и временный токен облачного провайдера — разные объекты. Первый подтверждает происхождение задачи, второй выдаётся после успешной проверки доверия. Не храните ни один из них как постоянный секрет.
Минимальная процедура извлечения
- Создайте отдельную диагностическую ветку или тестовый репозиторий.
- Выдайте разрешение
id-token: writeтолько нужной задаче, а не всей организации. - Запросите токен через стандартный OIDC-механизм GitHub Actions.
- Разберите заголовок и полезную нагрузку локально, не отправляя JWT во внешние сервисы.
- Запишите только имена полей и замаскированные значения.
- Сопоставьте
iss,aud,sub,repository_idиowner_idс текущей политикой доверия. - Сохраните результат в закрытом инциденте вместе с хэшем версии workflow.
Не подставляйте в продуктивную политику строку из случайного примера документации. Для ветки, Environment и reusable workflow будут разные условия. Ошибка в одном разделителе может сделать разрешённую задачу недействительной или, наоборот, открыть доступ слишком широкому набору запусков.
02Сопоставьте доверие облака с источником изменения
Что менять после переименования или переноса репозитория
Сначала зафиксируйте текущую облачную политику. В ней может проверяться:
- полный
sub; - организация и репозиторий;
- конкретная ветка;
- Environment;
aud;- reusable workflow;
- комбинация нескольких условий.
Если репозиторий переименован, не заменяйте только текстовое имя во всех местах механически. Сначала подтвердите, какой subject реально выпускается сейчас. Если в него вошли owner_id и repository_id, политика должна учитывать новую схему. Старое имя может уже не быть достаточным идентификатором.
Разделяйте три состояния:
- новый репозиторий автоматически получает новый формат;
- существующий репозиторий добровольно переходит на неизменяемый subject;
- администратор применяет организационный пользовательский шаблон.
Перед изменением составьте список затронутых репозиториев, Environments, облачных ролей и рабочих процессов. Одно организационное правило может одновременно повлиять на несколько производственных конвейеров.
Почему изменение только workflow обычно не помогает
Workflow управляет запросом токена и разрешениями задачи. Облачный провайдер решает, доверять ли полученному утверждению. Если в workflow добавлено id-token: write, но политика по-прежнему ожидает старый sub, авторизация останется неуспешной.
Проверка должна идти в таком порядке:
- журнал неудачной задачи;
- фактический
subиaud; - провайдер OIDC в облаке;
- условие доверия целевой роли;
- разрешения роли после успешного обмена;
- ограничения ветки и Environment.
Не меняйте одновременно subject, audience, разрешения роли и секреты. Иначе после восстановления вы не сможете определить, какая именно правка устранила сбой.
Восстановление без возврата к постоянному ключу
Постоянный ключ в GitHub Secrets может быстро вернуть соединение, но увеличивает радиус компрометации. Он не связан с конкретной веткой, Environment или запуском так же строго, как короткоживущая федеративная сессия. Для корпоративного конвейера это плохой откат, если OIDC-провайдер продолжает работать.
Используйте временный обход только при наличии отдельного согласования, срока отключения и аудита. Лучше:
- восстановить правильный
sub; - сохранить ограничение
aud; - оставить доверие привязанным к нужному Environment;
- проверить отказ для неразрешённой ветки;
- удалить аварийный секрет после успешной проверки.
Ограничьте права задачи и разделите 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, но общий узел создаёт остаточные риски. После задачи на диске могут остаться исходники, архивы, логи, временные ключи и кэш зависимостей.
Примените минимум пять технических мер:
- Используйте отдельные группы Runner для тестовых, облачных и подписывающих задач.
- Запрещайте маршрутизацию публикации на общий Mac, предназначенный для сборок.
- Создайте отдельную учётную запись и отдельный Keychain для производственной подписи.
- Очищайте рабочий каталог, временные файлы и логи после каждой чувствительной задачи.
- Ограничьте SSH-доступ и не передавайте агент ключей в обычные Job.
- Перезапускайте Runner после аварийной остановки или подозрительного задания.
- Проверьте, что резервный узел не получает производственные секреты автоматически.
Для организации, которая только проверяет архитектуру, полезен отдельный пилот аренды удалённого Mac. Но аренда не устраняет требования к изоляции: вы всё равно должны определить, какие Job могут попасть на узел и какие данные удаляются после выполнения.
04Опыт эксплуатации. Общий Mac может быть приемлем для компиляции без секретов. Для подписи и публикации важнее не производительность узла, а доказуемая граница доступа, очистка рабочего пространства и возможность быстро вывести узел из маршрутизации.
Примите решение по метрикам аудита и восстановления
Минимальный набор производственных проверок
До возврата потока в штатную эксплуатацию проведите положительные и отрицательные тесты:
- Разрешённая ветка получает OIDC-токен и временный облачный доступ.
- Разрешённый Environment проходит требуемое одобрение.
- Неразрешённая ветка получает отказ.
- Внешний pull request не получает производственные секреты.
- Reusable workflow допускается только при совпадении ожидаемого источника.
- Тестовый Mac Runner не видит Keychain подписывающего узла.
- После перезапуска Runner задача корректно возвращается в допустимую группу.
- При отказе основного узла публикация не переключается на неподготовленный общий 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 до уровня всей организации.