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.
Prerequisites
Section titled “Prerequisites”- A running Riptides control plane (see Getting Started)
riptides-cliconfigured to access the Riptides control plane- A GitHub repository or organisation whose workflows you want to connect
How It Works
Section titled “How It Works”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.
Step 1: Create a GitHubActions Verifier
Section titled “Step 1: Create a GitHubActions Verifier”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.
apiVersion: auth.riptides.io/v1alpha1kind: Verifiermetadata: name: github-actions namespace: riptides-systemspec: GitHubActions: audience: riptides requiredMetadata: - githubactions:repository:owner: your-orgApply it:
riptides-cli ctl apply -f verifier-github-actions.yamlConfirm the Verifier is available:
riptides-cli ctl get verifiersExpected output:
NAME STATEgithub-actions AvailableNarrowing 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 branchTo 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-bStep 2: Add the Action to Your Workflow
Section titled “Step 2: Add the Action to Your Workflow”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.shThe 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:
sudo journalctl -u riptides -fPinning the Audience
Section titled “Pinning the Audience”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-audiencespec: GitHubActions: audience: my-custom-audience requiredMetadata: - githubactions:repository:owner: your-orgVerify Runners Appear
Section titled “Verify Runners Appear”After a workflow run, check that the runner daemon registered with the control plane:
riptides-cli ctl get daemonsYou should see an entry like:
NAME WORKLOAD-ID STATEa1b2c3d4-e5f6-7890-abcd-e01234567890 riptides/daemon/your-org/your-org/deploy-service/CI ConnectedThe daemon will disappear from this list once the job finishes and the runner is destroyed.
Step 3: Assign Workload Identities
Section titled “Step 3: Assign Workload Identities”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:
apiVersion: core.riptides.io/v1alpha1kind: WorkloadIdentitymetadata: name: github-actions-deployer namespace: riptides-systemspec: workloadID: ci/github-actions/deployer scope: daemonGroup: id: daemongroup/github-actions-runners selectors: - process:name: deploy.sh connection: tls: mode: PERMISSIVEApply it:
riptides-cli ctl apply -f workload-identity-github-actions.yamlFor full details on WorkloadIdentity configuration, see the WorkloadIdentity reference.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Possible Cause | Resolution |
|---|---|---|
setup-riptides step fails with authentication error | id-token: write permission missing | Add permissions: id-token: write to the job |
Authentication error: required metadata not satisfied | Token claims don’t match any requiredMetadata group | Check the githubactions:repository:owner (and any other) selectors match the org/repo running the workflow |
Authentication error: audience mismatch | Action audience input does not match Verifier’s audience field | Ensure both are set to the same value (default: riptides) |
| Runner joins from an unexpected repo | requiredMetadata too broad | Tighten the selectors (add githubactions:repository:full_name, githubactions:ref, etc.) |
Daemon does not appear in riptides-cli ctl get daemons | Runner cannot reach control plane | Verify network connectivity from the runner to the control plane endpoint |
| Daemon shows “Phased out” then disappears after a job | Expected — runners are ephemeral | The 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 |