Безопасность: GITHUB_TOKEN и permissions

Делаем пайплайн безопасным: меньше прав, никаких утечек секретов.

GITHUB_TOKEN — автоматический временный токен, который GitHub создаёт для каждого прогона workflow и аннулирует по его завершении.

Встроенный токен

Не нужно заводить персональный токен, чтобы workflow мог писать в репозиторий: GitHub сам выдаёт GITHUB_TOKEN, доступный как ${{ secrets.GITHUB_TOKEN }}. Им можно публиковать пакеты, ставить статусы, комментировать PR. После прогона токен становится недействительным — украсть его «на будущее» бесполезно.

- name: Залогиниться в registry
  run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

Принцип наименьших привилегий

По умолчанию у токена могут быть широкие права. Хорошая практика — явно сузить их через permissions. Начните с минимума и добавляйте только нужное:

permissions:
  contents: read           # по умолчанию только чтение кода

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write        # этому job разрешим запись (напр., создать релиз)
      packages: write        # и публикацию пакетов
    steps:
      - uses: actions/checkout@v4

permissions на уровне workflow задаёт базу, на уровне job — переопределяет для конкретного job. Так доступ на запись есть только там, где он реально нужен.

Не логируйте секреты

Маскирование GitHub не панацея. Опасные приёмы, которых стоит избегать:

  • echo ${{ secrets.X }} в отладке — даже замаскированное, провоцирует ошибки; не выводите секреты намеренно.
  • Передача секрета как аргумента команды (виден в ps/трейсе) — кладите в env.
  • Включение set -x в скрипте, где есть секреты — трассировка раскроет значения.

Опасность чужого кода в PR

Запуск workflow на pull_request из форка — зона риска: чужой код не должен получить доступ к вашим секретам. GitHub поэтому ограничивает права GITHUB_TOKEN до read-only и не отдаёт секреты для таких прогонов. Не ослабляйте эту защиту без крайней необходимости и никогда не выполняйте недоверенный код с боевыми секретами.

Итог

  • GITHUB_TOKEN — временный встроенный токен; отдельный PAT для типовых задач не нужен.
  • Сужайте права через permissions (наименьшие привилегии), повышайте точечно на уровне job.
  • Не выводите секреты в логи и аргументы; будьте осторожны с PR из форков.
Проверьте себя
1. Что такое GITHUB_TOKEN?
AПостоянный личный токен, который нужно создавать вручную
BАвтоматический временный токен, выдаваемый на каждый прогон и аннулируемый после
CСекрет с паролем от сервера
DПеременная окружения с именем репозитория
2. Зачем задавать permissions: contents: read по умолчанию?
AЧтобы ускорить пайплайн
BРеализовать принцип наименьших привилегий: давать токену только нужные права, повышая их точечно
CЧтобы отключить кэш
DЭто обязательно для любого workflow
3. Почему GitHub ограничивает права и не отдаёт секреты для workflow, запущенных из форка по pull_request?
AЧтобы экономить минуты
BЧтобы недоверенный чужой код не получил доступ к вашим секретам и правам на запись
CИз-за лимита на размер логов
DЭто случайное ограничение
Поддержать проект