Deploying Harden-Runner on GitHub-hosted runners
This guide covers the two supported ways to add Harden-Runner runtime security to GitHub-hosted runners, when to choose each, and how to automate the rollout.
If you're running self-hosted runners (VM-based, Kubernetes ARC, or third-party providers like Blacksmith, Depot, Namespace, RunsOn, or Warp Build), see the Harden-Runner overview instead. This page is specifically about GitHub-hosted runners.
The two options at a glance
Recommended for
Organizations standardizing on GitHub-hosted custom runners across many repositories
Teams not using custom runner images, or wanting per-job control
How protection is applied
Agent is baked into a custom VM image, then workflows run on that image
Action is added to each workflow job
Workflow changes
Replace runner labels (for example, ubuntu-latest to ubuntu-latest-stepsecurity)
Add a step-security/harden-runner@v2 step to each job
Automation
Label replacement via automated pull requests
Action addition via automated pull requests
Policy management
Centralized via Policy Store
Inline in the workflow file, or centralized via Policy Store with use-policy-store: true
API key required
No (configured on the image)
Only when using use-policy-store: true
Option 1: Custom VM image (preferred)
Bake the Harden-Runner agent into your GitHub-hosted custom VM image, then point your workflows at that image by replacing the runner label.
Why it's preferred:
One-time setup. Every workflow that runs on the image is monitored, with no per-job configuration.
Workflow files only need a single label change. No
uses:step to add, no inputs to maintain.Coverage is enforced at the runner level, so individual workflows can't opt out by accident.
Label replacements can be rolled out across an organization with automated pull requests.
How to set it up:
Follow the agent installation instructions on the Harden-Runner Installation page under Settings → Harden-Runner Installations → GitHub Hosted Custom VMs.
Once your custom VM image is published, replace the existing runner labels in your workflows (for example,
ubuntu-latesttoubuntu-latest-stepsecurity).Use Policy Driven PRs to roll the label replacement out across your repositories.
Option 2: Harden-Runner Action
Add the step-security/harden-runner@v2 Action as a step in each GitHub Actions job. This is the right choice when you're not using custom runner images, or when you want per-job control over policies.
When to use it:
You run workflows on standard GitHub-hosted runners (
ubuntu-latest,windows-latest,macos-latest) and don't have a custom VM image program.Different workflows in your organization need different policies and you want each defined alongside the workflow file.
You're evaluating Harden-Runner before committing to custom images.
Recommended configuration:
If you choose this option, configure the Action with use-policy-store: true. This lets you centrally manage egress policies from the Policy Store without modifying each workflow whenever the policy changes.
yaml
You can obtain the api-key from your StepSecurity dashboard. Store it as a GitHub Actions secret.
Without use-policy-store: true, policies are defined inline (egress-policy, allowed-endpoints, and so on) and must be updated in every workflow file when they change.
How to set it up:
Use Secure Workflow or Secure Repo to generate the Action snippet for an existing workflow.
Roll out the change to every workflow in your organization using automated pull requests.
Automating the rollout with Terraform
Both options can be configured and rolled out using the StepSecurity Terraform provider. The provider lets you manage your StepSecurity configuration as code, including:
Policy Store policies and attachments
Automated pull request configuration
Member access, roles, and integrations
For organizations rolling Harden-Runner out across many repositories, the Terraform provider is the most maintainable path. Configuration changes go through code review, and the full state is versioned in your infrastructure repository.
Which option should I choose?
Use the custom VM image option if any of these apply:
You already use GitHub-hosted custom VM runners, or you're willing to adopt them.
You want every workflow protected by default, with no per-job opt-in.
You'd rather change a single label per workflow than add and maintain an Action step.
Use the Harden-Runner Action option if any of these apply:
You're running on standard GitHub-hosted runners and not ready to adopt custom images.
You want per-job policy control with policies versioned alongside the workflow.
You're evaluating Harden-Runner and want to start with a small footprint before scaling up.
If you're not sure, start with the Action option to evaluate, then migrate to the custom VM image option once you're standardizing.
Last updated
Was this helpful?