Features¶
Everything GitHub Actions Gateway (GAG) does today, with a link to the doc that explains each one. For the argument against Actions Runner Controller (ARC), see Why GAG?; for what is not here yet, see the roadmap.
Three badges appear below. v2 marks a
capability available only in the actions-gateway.com/v2beta1 API;
beta marks one whose API shape is still
under its first stability contract; and
partly classic-only marks one that does not
reach the ScaleSet acquisition tier every new tenant runs. No tier badge means
both tiers, and a gate removes the badge when the gap closes.
Check the version you're running
Use the version selector at the top of the page to switch between the
latest stable release
(the default) and dev, the unreleased main branch. A capability listed
under dev but not under a numbered release has not shipped in a tagged
chart yet.
Job intake and recovery¶
- Runner-scale-set acquisition: the same single-acquirer protocol ARC uses, with no many-acquirers fan-out. The default in v2.
- Quota-aware intake: a job the namespace
ResourceQuotahas no room for is never taken on, so it stays queued at GitHub until there is capacity. - Auto re-run for disrupted jobs: a worker lost to eviction, preemption, a node drain, or a bare
kubectl delete podhas its run re-run automatically, under a per-run budget. - Capacity gate for unplaceable workers: opt-in. Stop claiming jobs while the cluster cannot place the worker shape, instead of claiming and cancelling them. Off by default.
- Fast, honest ending for an abandoned run: a run whose worker is removed before it started is force-cancelled in about a second, measured live, then re-run automatically once capacity returns.
- Priority tiers per runner set: reserve a guaranteed floor of slots for expensive runner types so cheap CPU jobs cannot starve critical GPU work.
- Worker scale-up rate limiting: opt-in token bucket capping how fast workers start, distinct from the count ceiling, to smooth cold-start stampedes on shared egress.
- Scale-to-zero workers: worker pods exist only while a job runs; listeners are ~12 KiB goroutines in one shared pod, not a listener pod per runner group.
- Unmodified upstream runner images: the wrapper is injected into each worker pod at runtime (an OCI image volume on Kubernetes 1.33+, an initContainer below), so the stock
actions/runnerimage, or any derivative, runs with no rebuild.
Capacity, cost, and right-sizing¶
- Measured worker right-sizing v2 beta: per-job CPU/memory peaks sampled and turned into recommended
requests/limitsinRunnerSetstatus, with an advisorySizingDriftcondition. - Sizing profiles v2 beta: opt-in
Binpack,Throughput, andNodeShareprofiles apply the measurement at pod-build time, with clamps, a confidence fallback, and GPUs never touched. - Managed AGC right-sizing v2 beta: opt-in
agcAutoscalingstamps aVerticalPodAutoscalernext to a gateway's Actions Gateway Controller (AGC) so requests track observed usage; explicitagcResourcesbecome the floor and ceiling, and a missing VPA install degrades to an advisory condition. ResourceQuotasizing guide: turn runner shapes and concurrency ceilings into the quota numbers a platform admin sets, including what the quota actually counts.- Per-tenant cost attribution: map tenant namespaces and
app.kubernetes.io/*labels to OpenCost/Kubecost allocation queries for real dollars per tenant. - Savings calculator: the interactive cost model behind the ARC comparison.
- Node shutdown budgets: how much shutdown time GKE, EKS, AKS, RKE2, Kubespray, and OpenShift actually grant, and why proxy pools stay off spot capacity.
Tenant isolation and egress¶
- Per-tenant egress IPs: a dedicated proxy pool per tenant gives each team its own GitHub egress IPs to allow-list, with a contained blast radius.
- Standalone
EgressProxyv2 beta: the proxy becomes its own object, optionally shared, or omitted entirely for direct egress, which staysNetworkPolicy-restricted. - Cross-namespace proxy sharing v2 beta: one pool can serve several namespaces, but only those its owner names in
sharing.allowedNamespaces. Consent is provider-side, so naming a proxy from the consumer side grants nothing; unlisted stays denied, and only the proxy's public certificate crosses the namespace boundary. - FQDN egress policy: express GitHub egress by hostname instead of CIDR on Cilium, Calico, or GKE Dataplane V2.
- Auto-refreshed GitHub egress rules: the Gateway Manager Controller (GMC) re-reads GitHub's published IP ranges every 24 hours into each tenant's
NetworkPolicy, and anEgressRulesStalecondition, with a paging alert, fires when the refresh stalls past its window. - Bring your own proxy autoscaler v2 beta:
managedAutoscaling: falsehands the proxy pool to KEDA, VPA, or a custom HorizontalPodAutoscaler. - Service mesh coexistence: run alongside Istio, Linkerd, or ambient mode with injection opt-out and egress exclusions that keep the per-tenant proxy honored.
- One resource per tenant: a single
ActionsGatewayprovisions an isolated controller, proxy pool, RBAC, and network policies inside the platform-owned quota.
Security posture¶
- Secure-by-default hardening: Pod Security Admission per namespace, default-deny NetworkPolicies, and credentials kept out of environment variables, all reconciled rather than opt-in.
- Runner template library: three shipped worker pod shapes (
plain,kata-dind,privileged-dind), each applied with onekubectl apply -k, so a tenant starts from a validated template instead of transcribing a capability set by hand. Only templates CI exercises may ship, and a gate enforces it. - Kata micro-VM workers: validated on nested virtualization, and the default for GAG's own end-to-end CI, which builds a
kindcluster inside an unprivileged worker pod. - In-runner image builds: a decision table mapping BuildKit rootless, Kaniko, Sysbox, Kata, and privileged Docker-in-Docker to the right
securityProfileand PSA level. - Signed images, SBOM, and SLSA provenance: every published image is keyless-signed and carries both a Software Bill of Materials (SBOM) attestation and a Supply-chain Levels for Software Artifacts (SLSA) build-provenance attestation.
- Admission policy compatibility: a Kyverno/Gatekeeper matrix covering whether GAG pods comply with common cluster policies, plus sample enforce and exception policies.
- Optional CONNECT destination allow-listing: defense in depth, off by default. An opted-in proxy refuses a CONNECT outside the permitted set and counts each refusal as an alertable Server-Side Request Forgery (SSRF) signal. The mandatory default-deny NetworkPolicy stays the primary gate.
- Self-confining controller privileges: shipped
ValidatingAdmissionPolicyguards deny the GMC's own cluster-wide writes outside admin-marked tenant namespaces, so a compromised manager cannot touchkube-systemor any unmarked namespace. - Restart-free platform allowlists: grow the worker and infra PriorityClass allowlists and the egress-destination allowlist by editing a watched
PriorityClassAllowlistcustom resource (CR) or ConfigMap, no GMC restart; a missing, invalid, or overlapping object fails safe back to the flag baseline. - Credential redaction in logs: every GitHub response body passes one sanitizer that strips tokens, JWTs, and JIT configs before it can reach a log line, at every log level.
- Abuse detection and response: the threat model's abuse heuristics mapped to operator alerts, with compromise-response playbooks.
- Workload-identity credentials v2 beta: mint short-lived GitHub credentials through an external signer so the GitHub App private key never enters the cluster.
Observability¶
- Metrics reference: every Prometheus metric the GMC, AGC, and proxy export, scoped per tenant and runner group.
- Fleet rollups for platform admins: cross-tenant degraded, egress-stale, and quota gauges in a single pane.
- Scraping setup: wiring the mutual-TLS metrics endpoints into your Prometheus.
- Alerting and SLOs partly classic-only : ready-to-apply alert rules as code. Two SLOs and one alert read duration and latency series the ScaleSet tier does not emit yet, so they have no data there (roadmap).
- Grafana dashboards partly classic-only : a tenant dashboard and a platform dashboard, both as code. Their duration and latency panels stay empty on the ScaleSet tier for the same reason.
- Logging and tracing: structured logs and OpenTelemetry tracing across the four tiers.
Install and day-2 operations¶
- Helm install: the OCI chart, digest pinning, healthy-install verification, and a
scripts/e2e/validate-cluster.shpre-flight that fails loudly on a network-policy-less CNI. - Highly available manager: the GMC installs as two replicas with leader election, a
PodDisruptionBudget, and anti-co-location spread by default, releasing its lease on shutdown so failover takes seconds rather than a lease timeout. - Air-gapped install: relocate images and the OCI chart to a private registry with digests preserved, including pull Secrets for the runtime pods.
- GitOps install: declarative Argo CD
Applicationand FluxHelmReleaseexamples, with the CustomResourceDefinition (CRD) pruning gotcha handled. - Upgrade and rollback: versioned upgrade procedures and the rollback path for each release.
- Backup and restore: backup posture and a recovery runbook, with a Velero-specific how-to.
- Troubleshooting: symptom to diagnosis to remediation, organised by observable failure mode.
- Production runbook: the operational procedures the platform team needs on call.
- P2P image distribution: add a Spegel or Dragonfly mirror to survive ephemeral-worker pull storms.
API surface and migration¶
- The v2 API v2 beta: the recommended shape for new tenants: a decomposed
ActionsGateway+RunnerSet+RunnerTemplate, withv2beta1as the graduated storage and hub version. - Reusable runner templates v2 beta: one
RunnerTemplatereferenced by many runner sets, or a cluster-wideClusterRunnerTemplateshared across namespaces. - Multiple gateways per namespace v2 beta: scoped gateways coexist, each with its own GitHub binding and runner sets.
- GitHub Enterprise Server gateways: a gateway whose
gitHubURLnames a GHES appliance addresses that appliance on every GitHub surface, with aGitHubEgressIncompletecondition flagging an incomplete CIDR allow-list. Untested against a real GHES appliance. - GHES behind a private CA v2:
spec.githubCABundleRefnames a ConfigMap whose CA bundle is added to the trust of both the gateway's AGC and its worker pods, never replacing the system roots. Untested against a real GHES appliance. gag-migrate: a one-shot fan-out that moves a tenant offv1alpha1without changing how jobs are acquired: dry-run, review, apply.- Deprecations and the
v2.0.0removal: whatv2.0.0removes, what keeps working until then, and the pre-upgrade checklist. - Migrating from ARC: concept mapping, behavioral differences, and a worked zero-downtime migration of one runner group.
- Getting started: first-time GitHub App setup, the v2 object set, and credential rotation. There is also a recorded demo of one real job on a local kind cluster.