Skip to main content

GitHub Integration Quick Start

This section describes how to configure SPIRL to provide SPIFFE identities to your GitHub actions and workflows.

In this guide we are going to use self-hosted Github Action Runners on a Kubernetes cluster.

Setup GH Actions Runner Controller on k8s

Follow Official GH documentation to setup the controller.

Installing Actions Runner Controller:

NAMESPACE="arc-systems"
helm install arc \
--namespace "${NAMESPACE}" \
--create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller

Configuring a runner scale set:

To auto mount SPIFFE Workload API socket to each runner instance we need to modify default template. Here is an example of the values.yaml file with updated template:

githubConfigUrl: "https://github.com/spirl/gh-runner-k8s-spiffe"
githubConfigSecret:
github_token: ""
minRunners: 1
runnerScaleSetName: "arc-runner-set"
template:
metadata:
# This label is used by SPIRL to mount SPIFFE Workload API socket to the runner
labels:
k8s.spirl.com/spiffe-csi: enabled
spec:
containers:
- name: runner
image: ghcr.io/actions/actions-runner:latest
command: ["/home/runner/run.sh"]

SPIRL will then automatically mount the SPIFFE Workload API socket to the runner based on that label.

Then you can install the runner with the updated template:

GITHUB_PAT="YOUR_GITHUB_PAT"
NAMESPACE="arc-runners"
INSTALLATION_NAME="arc-runner-set"
helm install "${INSTALLATION_NAME}" \
--namespace "${NAMESPACE}" \
--create-namespace \
-f values.yaml \
--set githubConfigSecret.github_token="${GITHUB_PAT}" \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set

Add k8s cluster to SPIRL-managed trust domain

Add your k8s cluster to your SPIRL-managed trust domain. For example, using SPIRL CLI:

spirlctl ci-cd cluster add production --trust-domain example.com --platform k8s --profile github.com

Create a GH Action

Create a sample GH Action in your repo. Copy/paste the content below into .github/workflows/spirl-gh-demo.yml.

name: SPIRL for GitHub Actions Demo
on:
workflow_dispatch:

jobs:
spiffecli-action-demo:
# Use the INSTALLATION_NAME (runner scale set)
runs-on: arc-runner-set
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install OIDC Client from Core Package
run: npm install @actions/core@1.10.1 @actions/http-client

- name: Get Id Token
uses: actions/github-script@v7
id: idtoken
with:
script: |
const coredemo = require('@actions/core')
let audience = 'https://spirl.com';
let id_token = await coredemo.getIDToken(audience)
coredemo.setOutput('id_token', id_token)

- name: Install curl
run: sudo apt-get update && sudo apt-get install -y curl

- name: Download spiffecli to the runner at /tmp
run: |
ARCH=$(uname -m)
if [ "$ARCH" = "aarch64" ]; then
URL="https://github.com/elinesterov/gh-action-spiffecli/releases/download/v0.0.1/spiffecli-linux-arm64"
elif [ "$ARCH" = "x86_64" ]; then
URL="https://github.com/elinesterov/gh-action-spiffecli/releases/download/v0.0.1/spiffecli-linux-amd64"
else
echo "Unsupported architecture: $ARCH"
exit 1
fi
curl -LO $URL
chmod +x spiffecli-linux-* && mv spiffecli-linux-* /tmp/spiffecli

- name: Fetch JWT SVID
run: |
IDTOKEN=${{ steps.idtoken.outputs.id_token }}
AUDIENCE="https://your-audience.com"
cd /tmp
RESULT=$(./spiffecli get jwt-svid --audiences $AUDIENCE --identity-exchange-token $IDTOKEN)
echo "JWT_SVID=$RESULT" >> $GITHUB_ENV

- name: Use JWT SVID Result
run: |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# THIS IS FOR DEMO PURPOSES ONLY
# NEVER EVER USE THIS IN PRODUCTION
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Removing the first three characters from the JWT to prevent automatic masking
# You'll need to add 'eyJ' back to the output to decode the JWT
UNSAFE_JWT="${JWT_SVID:3}"
echo "The result of the JWT SVID fetch was: $UNSAFE_JWT"

The above action sets the SPIFFE JWT issued to your job into the JWT_SVID environment variable such that it can be consumed by subsequent steps in your workflow. It will have a SPIFFE ID path based on the repo owner and repo name e.g. spiffe://example.com/github.com/github-k8s-runner-prod/mycompany/spiffe-gh-action-demo. This JWT can then be used to access any internal or external infrastructure supporting either OIDC or SPIFFE authentication.