Как убедиться, что артефакт в GitHub Actions собрали именно вы, а не злоумышленник
Атаки на цепочку поставок давно превратились из теории в суровую реальность. Допустим, пользователь скачивает готовый бинарник из раздела Releases на GitHub. Как ему убедиться, что файл действительно собрал CI-сервер из исходного кода конкретного коммита, а не выложил хакер, получивший доступ к аккаунту разработчика?
Для решения этой задачи GitHub выкатил специальный экшен actions/attest-build-provenance. Разберем, как он работает, зачем нужны подписи Sigstore и почему при создании новых пайплайнов вам потребуется немного другой инструмент.
Куда привязать подпись
Суть подписи происхождения (provenance) довольно проста. Каждому готовому файлу нужен цифровой паспорт. Этот документ подтверждает: артефакт с определенным хэшем был собран внутри конкретного workflow, в конкретном репозитории и на конкретном коммите.
Инструмент формирует манифест по стандарту in-toto и спецификации SLSA (Supply-chain Levels for Software Artifacts). Дальше происходит самое интересное: подписание этого манифеста.
Вместо того чтобы заставлять разработчиков генерировать долгоживущие PGP-ключи и хранить их в секретах репозитория, используется архитектура Sigstore. Экшен запрашивает временный OIDC-токен у GitHub Actions и обменивает его на короткоживущий сертификат подписи.
Для публичных репозиториев подпись генерируется через публичный сервис Sigstore, а данные о ней попадают в прозрачный лог Rekor. Если репозиторий приватный, GitHub задействует собственный закрытый инстанс Sigstore (эта фича доступна на тарифе Enterprise Cloud).
Небольшой сюрприз в документации
Если вы откроете официальный репозиторий проекта, то прямо в начале README увидите важное примечание.
Начиная с четвертой версии, actions/attest-build-provenance превратился в простую обертку над базовым экшеном actions/attest. Разработчики GitHub прямо говорят: если вы поддерживаете старые пайплайны, можете оставить всё как есть. Но для новых проектов стоит сразу брать actions/attest.
Зачем GitHub сделал дополнительную прослойку? Изначально команда делала узкоспециализированный инструмент только для сборки (build provenance). Позже появилось желание подписывать не только бинарники, но и SBOM (списки зависимостей) или результаты сканирования уязвимостей. Так появился более универсальный actions/attest, а старый экшен отправился на покой в статусе синонима.
Как выглядело подключение
В старых версиях экшена логика работы в .github/workflows/build.yml сжималась до пары строк после шага сборки артефакта.
name: Build and Attest
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
attestations: write
steps:
- uses: actions/checkout@v4
- name: Build artifact
run: |
mkdir dist
echo "echo 'Hello World'" > dist/app.sh
- name: Generate build provenance
uses: actions/attest-build-provenance@v1
with:
subject-path: 'dist/app.sh'
Из важного здесь — права доступа id-token: write и attestations: write. Без первой опции workflow не сможет получить OIDC-токен для беспарольной подписи через Sigstore, а без второй — не загрузит результат в GitHub Attestations API.
Как проверить подлинность артефакта
После того как аттестация создана и привязана к репозиторию, любой пользователь или проверяющий скрипт может проверить файл локально. Для этого используется официальная утилита GitHub CLI.
Команда проверки выглядит так:
gh attestation verify app.sh --owner my-organization
Если файл не менялся и был собран в указанной организации, CLI выдаст информацию о коммите и сертификате подписи. Если же файл хотя бы минимально изменился, проверка завершится ошибкой.
Стоит ли внедрять
Если вы разрабатываете open-source библиотеку или CLI-инструмент, генерация аттестаций дает пользователям простой способ проверить безопасность ваших релизов.
С другой стороны, если у вас небольшой внутренний проект без жестких требований к безопасности цепочки поставок, усложнять CI лишними шагами может быть избыточно.
Для новых workflow сразу берите actions/attest вместо actions/attest-build-provenance. Суть работы останется той же, но вы будете использовать актуальный инструмент без устаревших оберток.