Level 2 — Secure and scale · wrap-up
Cheat sheet & self-check
Every command from this section on one page.
Install (Helm, OCI charts)
helm install arc -n arc-systems --create-namespace oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller | The controller |
helm install arc-runner-set -n arc-runners --create-namespace -f values.yaml oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set | A runner scale set |
runs-on: arc-runner-set | Workflows target the scale set by its installation name |
Inspect
kubectl get pods -n arc-systems | Controller and listener pods |
kubectl get pods -n arc-runners -w | Runner pods appearing per job |
kubectl get autoscalingrunnersets,ephemeralrunners -A | ARC's custom resources |
OIDC in a workflow
permissions: { id-token: write, contents: read } | Allow the job to request an OIDC token |
aws-actions/configure-aws-credentials (role-to-assume) | AWS: assume an IAM role |
google-github-actions/auth (workload_identity_provider) | GCP: Workload Identity Federation |
azure/login (client-id, tenant-id, subscription-id) | Azure: federated credential |
hashicorp/vault-action (method: jwt) | Vault: JWT auth role |
Subject claims to trust
repo:acme/infra:ref:refs/heads/main | Main branch of one repo |
repo:acme/infra:environment:prod | Jobs using the prod environment |
repo:acme/infra:pull_request | Pull request runs (read-only roles only) |
In the pipeline
syft ghcr.io/acme/api@$DIGEST -o spdx-json > sbom.json | Generate an SBOM |
trivy image --exit-code 1 --severity CRITICAL ghcr.io/acme/api@$DIGEST | Fail on critical vulnerabilities |
cosign sign --yes ghcr.io/acme/api@$DIGEST | Keyless signing (OIDC identity of the workflow) |
cosign attest --yes --type spdxjson --predicate sbom.json ghcr.io/acme/api@$DIGEST | Attach the SBOM as a signed attestation |
actions/attest-build-provenance (subject-name, subject-digest, push-to-registry) | GitHub artifact attestation (SLSA provenance) |
Verifying
cosign verify --certificate-identity-regexp '^https://github.com/acme/' --certificate-oidc-issuer https://token.actions.githubusercontent.com IMAGE@DIGEST | Verify a keyless signature |
gh attestation verify oci://ghcr.io/acme/api@$DIGEST --owner acme | Verify a GitHub attestation |
Isolation
Ephemeral runners (one job per runner) | No state or malware survives between jobs |
Separate runner pools/scale sets per trust level | Untrusted PRs never share runners with deploy jobs |
Runner groups → selected repositories | Limit which repos can use which runners |
Dedicated, tainted nodes for runners | Keep CI pods away from production workloads |
Workflow hygiene
uses: owner/action@<full commit SHA> | Pin third-party actions |
permissions: {} at top, grant per job | Least-privilege GITHUB_TOKEN |
Avoid pull_request_target + checkout of PR code | Classic secret-exfiltration path |
NetworkPolicy egress allow-list for runner pods | Limit where a compromised job can send data |