Runner governance
Политики для GitHub-hosted, larger и self-hosted runners: groups, labels, network access, ephemeral runners, ARC, private networking, patching и isolation boundaries.
Runner governance
Runner governance — это правила, по которым организация решает, где выполняются jobs, кто может использовать конкретный runner pool, какой код туда допускается и какие сети доступны во время выполнения. В GitHub Actions runner — не просто «машинка для CI». Это граница доверия: на нём оказываются checkout кода, временные файлы, dependency cache, build artifacts, GITHUB_TOKEN, иногда cloud credentials через OIDC и секреты облаков и secrets из Environments и protection rules.
Хорошее управление runners начинается с простого вопроса: этот job должен быть изолирован от инфраструктуры или, наоборот, ему нужен доступ внутрь private network? Ответ обычно определяет выбор между GitHub-hosted runners, larger runners и Self-hosted runners.
flowchart TD
A[Workflow job] --> B{runs-on}
B --> C[GitHub-hosted runner
fresh VM per job]
B --> D[Larger runner
managed VM + groups/static IP/private networking]
B --> E[Self-hosted runner
owned by your org]
E --> F[Runner group policy
selected repos/workflows]
E --> G[Labels
linux/x64/gpu/deploy-prod]
E --> H[Isolation boundary
VM, pod, network, disk cleanup]
H --> I[Ephemeral runner / ARC scale set]
H --> J[Persistent runner
requires patching and cleanup]
D --> K[Private network access
only when explicitly scoped]
I --> K
J --> KТри класса runners
Стандартный GitHub-hosted runner — самый безопасный default для обычного CI. GitHub обычно даёт job свежую изолированную среду: для большинства GitHub-hosted runners это новая VM, которая уничтожается после job; single-CPU runners являются исключением и запускаются в контейнере на общей VM. Это хорошо для тестов, линтеров, сборки пакетов без доступа к внутренней сети. Недостатки тоже понятны: образы обновляются GitHub, поэтому софт на ubuntu-latest может меняться; публичные IP-диапазоны не всегда удобно allowlist’ить; аппаратные ресурсы ограничены выбранным типом runner.
Larger runners — GitHub-hosted runners для организаций и enterprises на GitHub Team или GitHub Enterprise Cloud, но с большим CPU/RAM/disk, GPU-вариантами, autoscaling, runner groups и Azure private networking; статические IP для larger runners требуют GitHub Enterprise Cloud и применяются к Linux/Windows runners. Это хороший промежуточный слой: инфраструктуру всё ещё обслуживает GitHub, но platform team получает больше контроля над network access и capacity.
Self-hosted runner — ваша машина, VM, контейнер или Kubernetes pod, зарегистрированный в GitHub Actions. Он нужен, когда требуется кастомный hardware, приватная сеть, локальные toolchains, лицензированные SDK или строгий контроль образа. Цена контроля — вы отвечаете за ОС, runner application, patching, cleanup, network egress, disk persistence и изоляцию между jobs.
Groups и labels: маршрутизация как policy
runs-on — это не только технический selector. В production это часть access-control модели. Runner groups ограничивают, какие repositories или workflows могут использовать pool. Labels уточняют тип capacity: linux, x64, gpu, deploy-prod, arm64, arc-medium.
Пример более явного выбора runner:
jobs:
integration-tests:
runs-on:
group: ci-private
labels: [self-hosted, linux, x64, postgres]
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- run: ./scripts/integration-test.sh
deploy-prod:
runs-on:
group: prod-deploy
labels: [self-hosted, linux, x64, hardened]
environment: production
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
- run: ./scripts/deploy.shЗдесь ci-private и prod-deploy должны быть разными groups, даже если физически они живут в одном Kubernetes cluster. CI job может требовать доступ к тестовой базе, но не к production subnet. Deploy job может иметь OIDC-доступ к cloud role, но запускаться только после environment approval. Это связывает runner governance с Permissions и GITHUB_TOKEN, Deployment workflows и Cloud deploy через OIDC.
Важная мелочь: labels — не доказательство реального состояния машины. Если при регистрации вручную указать --labels linux,x64,gpu, GitHub не проверяет, что там действительно Linux, x64 и GPU. Поэтому labels должны назначаться автоматизированно из provisioning-кода, а не «на глаз» через UI.
Untrusted code и isolation boundary
Самая опасная ошибка — пустить untrusted PR на runner, который имеет доступ к внутренней сети или долгоживущим credentials. GitHub прямо рекомендует использовать self-hosted runners только с private repositories, потому что fork public repo может создать PR, который выполнит опасный код на вашей машине.
Для public repos и внешних contributors безопасный baseline такой:
name: pr-validation
on:
pull_request:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- run: npm ci
- run: npm testА вот такой паттерн требует красного флага:
on: pull_request
jobs:
test-on-private-runner:
runs-on:
group: prod-deploy
labels: [self-hosted, linux]
steps:
- uses: actions/checkout@v6
- run: ./scripts/test.shДаже если secrets не переданы явно, runner может видеть private network, локальный Docker socket, package mirror, internal metadata service, persistent workspace или credential helper. Для PR из fork лучше использовать GitHub-hosted runners и read-only permissions, а privileged automation выносить в отдельный trusted workflow. Это та же линия защиты, что и в pull_request_target и untrusted PR, только применённая к compute layer.
Network access: меньше «внутрь всего»
Runner не должен быть универсальным VPN-клиентом в вашу инфраструктуру. Делите network access по назначению:
- обычный CI: публичный интернет, package registries, no private subnet;
- integration CI: доступ только к тестовым сервисам или ephemeral environment;
- staging deploy: доступ к staging endpoints и staging secrets;
- production deploy: отдельный pool, environment approval, OIDC, минимальный egress;
- security scans: отдельный pool, потому что scanners часто требуют широких файловых и сетевых прав.
Для GitHub-hosted runners private networking можно строить через API Gateway с OIDC, WireGuard overlay или Azure VNET. Для larger runners практический плюс — Azure private networking, а в GitHub Enterprise Cloud ещё и статические IP, если нужно allowlist’ить доступ к registry, secret manager или cloud endpoint без полного self-hosting. Для self-hosted runners network policy уже ваша зона ответственности: firewall, Kubernetes NetworkPolicy, outbound proxy, DNS, deny-by-default egress и логирование.
Ephemeral runners и ARC
Долгоживущий self-hosted runner удобен, но плохо сочетается с недоверенным кодом и clean builds. Workspace, tool caches, docker layers и временные файлы могут пережить job. Даже если вы чистите директорию, это не равно полной переинициализации машины.
Production-паттерн для Kubernetes-команд — Actions Runner Controller, или ARC. ARC — Kubernetes operator для self-hosted runners; он создаёт runner scale sets, масштабирует runners под очередь jobs и может запускать ephemeral runner pods. GitHub называет ARC reference implementation для scale set APIs и рекомендует его организациям, у которых уже есть Kubernetes-инфраструктура и экспертиза.
Минимальная модель ARC такая: listener получает сигнал о job, Kubernetes создаёт ephemeral runner pod, runner регистрируется через short-lived JIT configuration, выполняет job, отправляет logs/status и удаляется. Это не магическая безопасность: pod всё ещё находится в вашем cluster. Но boundary становится понятнее: один job — один pod, policy задаётся через namespace, service account, node pool, image, admission policy и network policy.
Patching и maintenance
GitHub-hosted runners обслуживает GitHub, но это не освобождает от pinning tool versions. Если workflow зависит от конкретной версии Node, Python, Java или Xcode, задавайте её через setup-actions, а не надейтесь на текущий образ. Для стабильности CI это связано с CI pipeline, Matrix strategy и Dependency cache.
У self-hosted runners patching — часть SLA platform team. Нужно обновлять ОС, runner application, Docker/container runtime, build tools, CA certificates, cloud CLIs и base images. Отдельно держите inventory: какие repos могут использовать group, какие labels существуют, какие environments завязаны на pool, какие secrets или OIDC roles доступны jobs на этом pool.
Для larger runners governance ближе к managed infrastructure: GitHub управляет VM lifecycle, а вы управляете runner definitions, groups, access policy, image choice, static IP/private networking и concurrency/cost.
Практическая policy-модель
Хорошая runner policy обычно формулируется не в YAML, а в таблице владельцев:
Pool/group Кто использует Доступ Допуск кода
ci-public public/private repos internet only pull_request ok
ci-private selected private repos test services trusted branches + internal PR
deploy-staging service repos staging cloud main, release branches
deploy-prod selected repos prod cloud environment approval only
security-scan selected repos limited egress scheduled/trusted refsПосле этого YAML становится проверяемым следствием policy. Если job с pull_request просит prod-deploy, это баг. Если deploy job не указывает environment: production, это баг. Если self-hosted runner доступен всем repos в org, хотя ходит в production network, это не «удобство», а нарушение boundary.
See also
- GitHub-hosted runners — стандартные managed runners, образы и runtime-ограничения.
- Self-hosted runners — установка, lifecycle и эксплуатация собственных runners.
- Secure use и threat model — общая модель угроз для untrusted code, tokens, secrets и logs.
- pull_request_target и untrusted PR — privileged workflows и опасность checkout кода из PR.
- OIDC и секреты облаков — почему runner pool с cloud access должен быть tightly scoped.
- Environments и protection rules — approval и ограничения перед production deploy.
- Monitoring и troubleshooting — очереди jobs, logs, reruns и диагностика flaky runners.
- Enterprise policies и migration — org-level ограничения Actions, templates, required workflows и audit.
Внешние справки: GitHub Docs по runner groups, labels, self-hosted runners, larger runners, private networking, secure use и Actions Runner Controller.
Источники
- Managing access to self-hosted runners using groups - GitHub Docs
- Larger runners - GitHub Docs
- Actions Runner Controller - GitHub Docs
- Self-hosted runners reference - GitHub Docs
- Using labels with self-hosted runners - GitHub Docs
- Secure use reference - GitHub Docs
- Using GitHub-hosted runners - GitHub Docs
- Private networking with GitHub-hosted runners - GitHub Docs
