Relay — Headless VPN auth
AWS Client VPN requires a browser for SAML. That's fine on a laptop — impossible on a CI runner. Relay bridges the gap.
The problem with SAML in headless environments
AWS Client VPN uses the CRV1 challenge-response protocol. Phase 1 returns a URL that must be opened in a browser — the user authenticates via their IdP and the resulting SAMLResponse completes Phase 2 to bring up the tunnel.
CI runners have no browser
GitHub Actions, GitLab CI, Jenkins — headless containers. No display, no way to complete the SAML flow interactively.
Storing credentials is an anti-pattern
Injecting SAML tokens as CI secrets couples your pipeline to credentials that expire and rotate. Every rotation breaks builds.
Existing workarounds fail at scale
Pre-generated tokens expire in minutes. Spinning up a full desktop VM just for VPN auth wastes money and adds minutes to every build.
How Relay works
The relay is a lightweight broker between the headless agent (CI runner) and the human operator (desktop or Android client). No inbound ports required. No secrets stored anywhere in the pipeline.
Agent registers
CI runner starts openlawsvpn-cli -relay <token> -daemon and connects a WebSocket to the relay. No inbound port needed.
App authenticates
Developer opens the Android or desktop app, sees the agent listed as standby, taps Connect. The app runs Phase 1 + full SAML browser flow.
Relay delivers credentials
App sends the completed SAMLResponse to the relay via HTTPS. Relay pushes it to the waiting agent over the WebSocket.
Tunnel up
Agent executes Phase 2, VPN is established. CI build continues. App shows the agent as connected and can disconnect remotely at any time.
See it in action
A real screencast: a GitHub Actions workflow starts the relay agent, the Android app approves the SAML flow, and the tunnel comes up — with zero credentials stored in the pipeline.
What the screencast shows
- A GitHub Actions VPN Integration workflow is triggered manually. The runner is a headless Ubuntu container with no display.
- The step Start relay agent runs
openlawsvpn-cli -relay $RELAY_TOKEN -daemon -pidfile /tmp/vpn.pid. It blocks, waiting for an operator to approve auth. - On an Android phone, the openlawsvpn app's Relay screen shows the runner as standby. The operator taps Connect.
- The app runs the Phase 1 SAML browser flow in Chrome Custom Tab. The user authenticates with their SSO credentials.
- The app posts the completed SAMLResponse to the relay. Relay pushes it to the waiting agent over WebSocket.
- The CI step exits 0 —
TUNNEL UP · tun=172.16.77.1 · daemon started (pid 12483). The pipeline continues. - Subsequent steps requiring access to internal services over the VPN succeed.
- On cleanup, the app shows the agent as connected and the operator can disconnect it remotely.
Try it now — no account required
The public demo token lets you test the full relay flow immediately against the live relay backend. No registration, no credit card.
Demo token: default
Run on any Linux host (or CI runner) with openlawsvpn-cli installed:
openlawsvpn-cli -relay default -daemon
Then open the Android app → Relay tab → enter token default → tap Save & Refresh. Your agent appears in the list. Tap Connect to complete the SAML flow.
Demo limits: 10-minute session maximum · 5 concurrent agents · shared public namespace. For longer sessions or private organisation tokens, vote for extended plans on GitHub.
GitHub Actions example
- name: Start relay agent
env:
RELAY_TOKEN: ${{ secrets.RELAY_TOKEN }}
run: |
sudo openlawsvpn-cli \
-relay "$RELAY_TOKEN" \
-daemon \
-pidfile /tmp/vpn.pid \
-logfile /tmp/vpn.log
- name: Check internal service health
run: curl -f https://internal.example.com/health
- name: Disconnect VPN
if: always()
run: |
kill "$(cat /tmp/vpn.pid)" || true
Store your relay token as a repository secret RELAY_TOKEN.
No VPN credentials, no AWS keys, no SAML tokens in CI.
Use cases
GitHub Actions / GitLab CI
Integration tests, database migrations, internal API calls — any CI step that needs your private VPC. A team member approves from their phone before the run begins.
Remote development VMs
Cloud dev boxes and jump hosts behind NAT can't open a browser. Relay lets you bring up the tunnel on any remote machine with a single CLI command.
Kubernetes init containers
Run the relay agent as a VPN init container in your pod spec. The tunnel is ready before your application container starts.
IoT and edge gateways
Embedded Linux devices can register as relay agents. A fleet manager approves tunnels from a single mobile session, granting temporary VPN access to field devices.
Ready to try it?
Install the client, then run with -relay default to test immediately — no account required.