Register a self-hosted runner and authenticate with GitHub App

Register a self-hosted runner and authenticate with GitHub App


Previously I had an article that explained what a GitHub App, what are the use cases and how to set it up. In this article, we are going to use a GitHub App to register a self-hosted runner in your organization.

What is a self-hosted runner?

A self-hosted runner is a system that you deploy and manage to execute jobs from GitHub Actions on GitHub.com

Create a GitHub App

Quick overview on how to create a GitHub App. If you want to read more then go to here

In this case we are going to create an GitHub App under the organization.

  • Go to your organization settings. Scroll down on the left menu until “Developer settings”. Choose GitHub App.

create-gh-app

  • Click “New GitHub App”
  • Under permission, you need to decide if the runner will be set up at the repository or organization level. In the case when the runner will be only on the repo level create the app with the “ Repository permissions” “Administration: Read & Write”. If it is available on the organization level then choose Organization permission: “Self-hosted runners: Read & Write”

Once the permission is set and the app is created follow the next steps:

  • Generate and Download the Private Key → Under general settings
  • Install the App on the organization

    install-app

Python script to get JWT

Next, we will copy a Python script from the GitHub documentation that will help us generate the JWT token. The documentation can be found here:

https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-python-to-generate-a-jwt

  • Use the Python Script from the Documentation to generate a JWT for the App
#!/usr/bin/env python3
import jwt
import time
import sys

# Get PEM file path
if len(sys.argv) > 1:
    pem = sys.argv[1]
else:
    pem = input("Enter path of private PEM file: ")

# Get the App ID
if len(sys.argv) > 2:
    app_id = sys.argv[2]
else:
    app_id = input("Enter your APP ID: ")

# Open PEM
with open(pem, 'rb') as pem_file:
    signing_key = jwt.jwk_from_pem(pem_file.read())

payload = {
    # Issued at time
    'iat': int(time.time()),
    # JWT expiration time (10 minutes maximum)
    'exp': int(time.time()) + 600,
    # GitHub App's identifier
    'iss': app_id
}

# Create JWT
jwt_instance = jwt.JWT()
encoded_jwt = jwt_instance.encode(payload, signing_key, alg='RS256')

print(f"JWT:  {encoded_jwt}")

Note:

  • When running the script enter the path for the PEM file, that we downloaded previously
  • Provide the APP ID, which can be found under GitHub App settings

Once you have executed the script with necessary inputs continue with the next REST calls.

  • Use the generated JWT to call the API to get an Application Access Token:
curl -i -X POST \
-H "Authorization: Bearer <JWT>" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/app/installations/<Installation Id of your App>/access_tokens \

You can find the Installation Id from the url after you installed the App

installation-id

  • More details about the API call can be found here: https://docs.github.com/en/enterprise-cloud@latest/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app

Then use the token in the response to call the endpoint to get the registration token for the runner

  • REST call to get the registration token on to register the runner on the organization level:
curl -L \
  -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/orgs/ORG/actions/runners/registration-token
  • REST call to get the registration token on to register the runner on the repository level:
curl \
  -X POST \
  -H "Authorization: token <token>" \
  -H "Accept: application/vnd.github.machine-man-preview+json" \
  https://api.github.com/repos/<owner>/<name-of-your-repo>/actions/runners/registration-token

Note:

  • More details about the api call can be found here

Configure the runner

Now that we have the registration token we can setup the runner.

Download the GitHub runner

Note: this is for MacOs. Windows and Linux is similar.

# Create a folder
$ mkdir actions-runner && cd actions-runner
# Download the latest runner package
$ curl -o actions-runner-osx-x64-2.306.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.306.0/actions-runner-osx-x64-2.306.0.tar.gz
# Optional: Validate the hash
$ echo "842bfb1d707fd7af153bb819cdc3e652bc451b9110b76fcb4b4a4ba0c4da553a  actions-runner-osx-x64-2.306.0.tar.gz" | shasum -a 256 -c
# Extract the installer
$ tar xzf ./actions-runner-osx-x64-2.306.0.tar.gz

Once the runner is downloaded and extracted use the token from the last REST call response to execute the ./config.sh from the runner and follow the steps

# Create the runner and start the configuration experience
$ ./config.sh --url https://github.com/MadKoo-Consult --token <TOKEN_FROM_RESPONSE>
# Last step, run it!
$ ./run.sh

Once you have completed all the steps, you have successfuly registered the runner on the org level.

Summary

In this article, we have learned how to register a self-hosted runner on the organization level using a GitHub App.