Access Resources from GitHub Actions CI
This guide shows how to reach private Resources — a staging database, an internal API, a private package registry — from a GitHub Actions workflow. Because a CI runner is unattended, it authenticates with a service account token rather than a browser sign-in, then connects with the headless Linux Client.
Step 1: Create a service account and token
- In the admin portal, go to
Actors → Add Actor. - Select
Service Accountas the type and give it a name (e.g.github-ci). - Set an appropriate token expiration.
- Copy the token and store it somewhere safe — it's only shown once.
You can add multiple tokens to a service account (under
Actors → <account> → ⋮ → Add Token) to rotate credentials or issue a
separate token per repository, and revoke any token from the service account's
detail page. Tokens default to a 365-day lifetime.
Step 2: Grant the service account access
Add the service account to a Group, then create a Policy granting that Group access to the Resource your workflow needs. Without a Policy, the CI runner will connect but won't be able to reach anything.
Step 3: Store the token as a GitHub secret
In your repository, go to Settings → Secrets and variables → Actions and add
a new secret named FIREZONE_TOKEN containing the token from Step 1.
Step 4: Connect from your workflow
Add a step that downloads the headless Linux Client, starts it with the service account token, and waits for the tunnel to come up before the rest of your job runs:
jobs:
integration-tests:
runs-on: ubuntu-latest
steps:
- name: Start Firezone Client
env:
FIREZONE_TOKEN: ${{ secrets.FIREZONE_TOKEN }}
run: |
curl -fsSL -o firezone-client \
https://www.firezone.dev/dl/firezone-client-headless-linux/latest/x86_64
chmod +x firezone-client
# A unique ID per run keeps concurrent jobs from sharing an identity.
export FIREZONE_ID=$(head -c 32 /dev/urandom | sha256sum | cut -d' ' -f1)
export FIREZONE_NAME="github-actions-${{ github.run_id }}"
sudo --preserve-env=FIREZONE_TOKEN,FIREZONE_ID,FIREZONE_NAME \
./firezone-client &
# Give the tunnel a moment to establish before continuing.
sleep 5
- name: Run tests against the private Resource
run: |
# The Resource is now reachable by its defined address, e.g.:
psql "postgres://ci@db.internal.example.com/app" -c '\dt'
Resources are reached by the address defined in Firezone (DNS name, IP, or CIDR), exactly as you configured the Resource. Make sure the Policy from Step 2 grants this service account access, and that a Gateway in the Resource's Site is online.
The Client runs in the background for the life of the job; GitHub tears the runner down when the job finishes, so there's no explicit sign-out step. For long-lived self-hosted runners, sign out or stop the Client when you're done.
Need help? See all support options.