Skip to content

Connect GitHub Actions Runners

This guide shows you how to connect GitHub Actions runners to Riptides using the GitHubActions verifier. Runners authenticate automatically using the signed OIDC token provided by GitHub Actions, with no join tokens or long-lived credentials required.

  • A running Riptides control plane (see Getting Started)
  • riptides-cli configured to access the Riptides control plane
  • A GitHub repository or organisation whose workflows you want to connect

GitHub Actions provides every runner with an OIDC token issued by https://token.actions.githubusercontent.com. The Riptides daemon requests this token from the Actions token endpoint using the ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN environment variables that GitHub injects automatically. The control plane verifies the token signature against GitHub’s public JWKS and checks the token’s claims against the Verifier’s requiredMetadata selectors - exactly like the AWS, GCP, and Azure verifiers do with instance metadata.

No managed identity, no cloud account, no secrets. The runner’s GitHub identity is the credential.

Create a Verifier that accepts runners from your GitHub organisation. Scope it with requiredMetadata - a githubactions:repository:owner selector restricts authentication to your org only.

verifier-github-actions.yaml
apiVersion: auth.riptides.io/v1alpha1
kind: Verifier
metadata:
name: github-actions
namespace: riptides-system
spec:
GitHubActions:
audience: riptides
requiredMetadata:
- githubactions:repository:owner: your-org

Apply it:

Terminal window
riptides-cli ctl apply -f verifier-github-actions.yaml

Confirm the Verifier is available:

Terminal window
riptides-cli ctl get verifiers

Expected output:

NAME STATE
github-actions Available

Narrowing to a Specific Repository, Environment, or Branch

Section titled “Narrowing to a Specific Repository, Environment, or Branch”

Add more selectors to a group to narrow further. A token must match every selector in a group to be accepted:

spec:
GitHubActions:
audience: riptides
requiredMetadata:
- githubactions:repository:owner: your-org
githubactions:repository:full_name: your-org/deploy-service # only this repository
githubactions:environment: production # only the "production" GH environment
githubactions:ref: refs/heads/main # only the main branch

To trust several orgs or repositories, add multiple groups - a token matching any group is accepted:

requiredMetadata:
- githubactions:repository:owner: org-a
- githubactions:repository:owner: org-b

Add the riptideslabs/setup-riptides action to your workflow. The job must have id-token: write permission so GitHub can issue an OIDC token.

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # required, allows GitHub to issue an OIDC token
contents: read
steps:
- uses: actions/checkout@v4
- uses: riptideslabs/setup-riptides@v1
with:
controlplane-url: https://<your-env-id>.console.riptides.io
# From here the runner has a verified SPIFFE identity and all outbound
# connections are transparently mTLS-secured by the Riptides daemon.
- name: Deploy
run: ./deploy.sh

The action installs the kernel driver and daemon, runs riptides daemon auth --plugin GitHubActions to exchange the OIDC token for a SPIFFE x509 identity certificate, and starts the daemon as a systemd service.

To follow live logs during a run:

Terminal window
sudo journalctl -u riptides -f

The audience input must match the audience field in your Verifier. The default for both is riptides.

- uses: riptideslabs/setup-riptides@v1
with:
controlplane-url: https://<your-env-id>.console.riptides.io
audience: my-custom-audience
spec:
GitHubActions:
audience: my-custom-audience
requiredMetadata:
- githubactions:repository:owner: your-org

After a workflow run, check that the runner daemon registered with the control plane:

Terminal window
riptides-cli ctl get daemons

You should see an entry like:

NAME WORKLOAD-ID STATE
a1b2c3d4-e5f6-7890-abcd-e01234567890 riptides/daemon/your-org/your-org/deploy-service/CI Connected

The daemon will disappear from this list once the job finishes and the runner is destroyed.

Create a WorkloadIdentity to assign a SPIFFE identity to processes running on your GitHub Actions runners. Scope it to the daemon’s workload ID so it only applies to runners from your repo:

workload-identity-github-actions.yaml
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: github-actions-deployer
namespace: riptides-system
spec:
workloadID: ci/github-actions/deployer
scope:
daemonGroup:
id: daemongroup/github-actions-runners
selectors:
- process:name: deploy.sh
connection:
tls:
mode: PERMISSIVE

Apply it:

Terminal window
riptides-cli ctl apply -f workload-identity-github-actions.yaml

For full details on WorkloadIdentity configuration, see the WorkloadIdentity reference.

SymptomPossible CauseResolution
setup-riptides step fails with authentication errorid-token: write permission missingAdd permissions: id-token: write to the job
Authentication error: required metadata not satisfiedToken claims don’t match any requiredMetadata groupCheck the githubactions:repository:owner (and any other) selectors match the org/repo running the workflow
Authentication error: audience mismatchAction audience input does not match Verifier’s audience fieldEnsure both are set to the same value (default: riptides)
Runner joins from an unexpected reporequiredMetadata too broadTighten the selectors (add githubactions:repository:full_name, githubactions:ref, etc.)
Daemon does not appear in riptides-cli ctl get daemonsRunner cannot reach control planeVerify network connectivity from the runner to the control plane endpoint
Daemon shows “Phased out” then disappears after a jobExpected — runners are ephemeralThe daemon is auto-removed a short time after the runner stops heart-beating; “Phased out” is a normal end-of-life state, not an error