# RunsOn

### What is RunsOn?

[RunsOn](https://runs-on.com) is the modern way to self-host GitHub Actions runners at scale on AWS, with incredible cost savings and features:

* 10x cheaper than GitHub-hosted runners
* at least 30% faster than GitHub-hosted runners
* 5x faster, *unlimited* caching with S3-local bucket
* fully self-hosted in your own AWS account
* no concurrency limits
* native x64, arm64, GPU, and Windows support
* SSH access, advanced networking, and more

RunsOn is a partner of StepSecurity and provides ready-made base images that contain the StepSecurity agent for self-hosting use.

### Getting Started with StepSecurity on RunsOn

1. Get a StepSecurity API Key
   * You need a StepSecurity Enterprise License.
   * If you don’t have a license, you can start a free trial at [StepSecurity](https://www.stepsecurity.io/start-free).
2. Configure RunsOn –&#x20;
   1. Get your StepSecurity API key (from Settings-> Self Hosted Runners-> Self Hosted VM -> RunsOn Integration)&#x20;
   2. Enter it in the RunsOn CloudFormation template.<br>

      <figure><img src="https://754495266-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQJRZY4cfEeY3I7DXTOCp%2Fuploads%2FIpC3ArpZzPFAfdURpXbo%2FScreenshot%202025-03-16%20at%202.21.27%E2%80%AFPM.png?alt=media&#x26;token=ec8efa38-3d13-4cf0-9510-72eba56b0291" alt=""><figcaption></figcaption></figure>
3. Use StepSecurity images in your workflows. Here is the list of all StepSecurity images:
   * ubuntu24-stepsecurity-x64
   * ubuntu24-stepsecurity-arm64

```yaml
jobs:
  build:
    runs-on:
      - runs-on=${{ github.run_id }}
      - runner=2cpu-linux-x64
      - image=ubuntu24-stepsecurity-x64
```

4. Visit your [StepSecurity dashboard](https://app.stepsecurity.io/login) to review the runtime insights report for network, process, and file activities.

### Example

* Here is an example [workflow](https://github.com/step-security/harden-runner/blob/main/.github/workflows/runs-on.yml) that uses StepSecurity images with RunsOn&#x20;

```yaml
name: RunsOn Tests

on: 
  workflow_dispatch:

jobs:
  test-host-outbound:
    runs-on:
      - runs-on=${{ github.run_id }}
      - runner=2cpu-linux-x64
      - image=ubuntu22-stepsecurity-x64
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@rc
        with:
          egress-policy: audit
          allowed-endpoints: >
            github.com:443
            goreleaser.com:443
            

      - name: Checkout code
        uses: actions/checkout@v3
            
      - name: Run outbound calls from host
        run: |
          start_time=$(date +%s)
          end_time=$((start_time + 90))  # 5 minutes = 300 seconds
          
          while [ $(date +%s) -lt $end_time ]; do
            curl -I https://www.google.com
            curl -I https://goreleaser.com
            sleep 10  # wait 10 seconds between calls
          done
  
  test-docker-outbound:
    runs-on:
      - runs-on=${{ github.run_id }}
      - runner=2cpu-linux-x64
      - image=ubuntu22-stepsecurity-x64
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@rc
        with:
          egress-policy: block
          allowed-endpoints: >
            archive.ubuntu.com:80
            github.com:443
            goreleaser.com:443
            production.cloudflare.docker.com:443
            docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com:443
            *.docker.io:443
            security.ubuntu.com:80
         
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Run outbound calls from within Docker container
        continue-on-error: true
        run: |
          # Start the container
          docker run --rm -d --name test-container ubuntu:latest sleep 90
          
          # Install curl in the container
          docker exec test-container apt-get update
          docker exec test-container apt-get install -y curl
          
          # Print /etc/resolv.conf from the container
          docker exec test-container cat /etc/resolv.conf
          
          # Make outbound calls
          for i in {1..9}; do
            docker exec test-container curl -I https://www.google.com
            docker exec test-container curl -I https://goreleaser.com
            sleep 10  # wait 10 seconds between calls
          done
          
          # Stop the container
          docker stop test-container

      
  test-docker-build-outbound:
    runs-on:
      - runs-on=${{ github.run_id }}
      - runner=2cpu-linux-x64
      - image=ubuntu22-stepsecurity-x64
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@rc
        with:
          egress-policy: audit
          allowed-endpoints: >
            archive.ubuntu.com:80
            auth.docker.io:443
            github.com:443
            goreleaser.com:443
            production.cloudflare.docker.com:443
            docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com:443
            registry-1.docker.io:443
            security.ubuntu.com:80
            
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Build Docker image and test outbound calls during build
        continue-on-error: true
        run: |
          # Create a Dockerfile that installs curl and makes outbound calls
          cat <<EOF > Dockerfile
          FROM ubuntu:latest
          RUN apt-get update && apt-get install -y curl
          RUN for i in {1..9}; do curl -I https://www.google.com && curl -I https://goreleaser.com; sleep 10; done
          EOF
          
          # Build the Docker image
          docker build -t test-image .
          
          # Print /etc/resolv.conf from the build container (temporary container used during build)
          container_id=$(docker create test-image)
          docker start $container_id
          docker exec $container_id cat /etc/resolv.conf
          docker stop $container_id
          docker rm $container_id

      - name: Print Docker logs with journalctl
        run: |
            sudo journalctl -u docker.service --no-pager 
        shell: bash
      
  test-long-running-docker:
    runs-on:
      - runs-on=${{ github.run_id }}
      - runner=2cpu-linux-x64
      - image=ubuntu22-stepsecurity-x64
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@rc
        with:
          egress-policy: block
          allowed-endpoints: >
            archive.ubuntu.com:80
            auth.docker.io:443
            github.com:443
            goreleaser.com:443
            production.cloudflare.docker.com:443
            registry-1.docker.io:443
            docker-images-prod.6aa30f8b08e16409b46e0173d6de2f56.r2.cloudflarestorage.com:443
            security.ubuntu.com:80
            

      - name: Checkout code
        uses: actions/checkout@v3

      - name: Run long-running Docker container with outbound calls
        continue-on-error: true
        run: |
          # Start the long-running container
          docker run --rm -d --name long-running-container ubuntu:latest bash -c "
            apt-get update && apt-get install -y curl && 
            while true; do 
              curl -I https://www.google.com; 
              curl -I https://goreleaser.com; 
              sleep 10; 
            done
          "
          
          # Print /etc/resolv.conf from the container
          docker exec long-running-container cat /etc/resolv.conf
          
          # Let the container run for 5 minutes
          sleep 90
          
          # Stop the container
          docker stop long-running-container
```

* You can view the [security insights](https://app.stepsecurity.io/github/step-security/harden-runner/actions/runs/13447286196) for this workflow run:

<figure><img src="https://754495266-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQJRZY4cfEeY3I7DXTOCp%2Fuploads%2FKjaDSMOQQhPzJmJabtRh%2FScreenshot%202025-02-25%20at%2022.45.37.png?alt=media&#x26;token=16d546ce-f33f-4b13-a11e-78615d584daf" alt="StepSecurity Insights summary page "><figcaption><p>StepSecurity Insights page</p></figcaption></figure>

### FAQ

#### How much does StepSecurity cost?

StepSecurity pricing is based on the number of contributing developers in protected repositories. See the [pricing page](https://www.stepsecurity.io/pricing) for details. RunsOn integration comes at no additional cost to your existing [RunsOn license](https://runs-on.com/pricing/#license-types).

#### Does Harden-Runner impact CI/CD performance?

No, Harden-Runner is optimized for low overhead. It monitors activity efficiently without slowing down builds.

#### Can I use the Harden-Runner community tier with RunsOn?

No, the Harden-Runner community tier only works with GitHub-hosted runners. Self-hosted runners with RunsOn will need a StepSecurity enterprise license.

### Resources

* [StepSecurity documentation](https://docs.stepsecurity.io/)
* [RunsOn documentation](https://runs-on.com/)
* [StepSecurity case studies](https://www.stepsecurity.io/case-studies)
