Dev box / jump box SSH over Cloudflare WARP
Private, VPN-only SSH to the vbhel jump box (also the beta-dev Docker-Compose
host, public IP 65.21.252.138). SSH is reached only through Cloudflare
WARP — once the public firewall closes port 22, the box has no public SSH
surface. Auth is WARP enrollment (any @upsquad.ai device in the upsquad
Zero Trust org).
This is the manually-managed dev-box counterpart to the GCP env access plane (ADR-0018 §2.5 / core#1282). The dev box stays outside Pulumi/GCP per ADR-0001, so this path is configured on the host + the Cloudflare API, not in IaC.
Components (all live)
| Piece | Value |
|---|---|
| Zero Trust account | b12538c0dc2fb7882da39a7cc280596c (upsquad) |
| Tunnel | devbox-ssh — id 26caa5ed-1067-4d47-8414-af9025d22882 |
| WARP route | 65.21.252.138/32 → devbox-ssh, default vnet c31e82cf-7067-4eb5-b879-42aa82ebf22e |
| Connector | systemd unit cloudflared-devbox-ssh.service on vbhel |
| Token | /etc/cloudflared/devbox-ssh.env (TUNNEL_TOKEN=…, root, mode 600) |
| warp-routing | enabled on the tunnel; no public ingress hostnames |
The connector is a dedicated tunnel, separate from the upsquad tunnel that
serves the public hostnames (research/app/upsquad.ai) — so the emergency SSH
path is not coupled to the web tunnel's lifecycle.
Connecting (engineers)
- Install the Cloudflare WARP client and enroll: Login with Cloudflare Zero
Trust, team name
upsquad(upsquad.cloudflareaccess.com), authenticate with your@upsquad.aiidentity. (Device-enrollment policy must allow@upsquad.ai— same enrollment the beta env uses.) - With WARP connected:
ssh <user>@65.21.252.138— routed edge → tunnel → connector → local sshd. - With WARP disconnected (after the firewall is closed): the same command times out. That is the intended VPN-only posture.
Closing the public SSH surface (FINAL step — do after verifying step 2)
The "bastion firewall" is the Hetzner Cloud Firewall in front of vbhel
(the host itself runs no ufw/iptables). After confirming SSH-over-WARP works for
at least one operator, remove the public inbound tcp/22 allow in the Hetzner
Cloud Console (or via hcloud firewall). Do not close 22 before a
successful WARP SSH test — there is no other ingress path and the connector's
WARP edge hop cannot be tested from the host itself.
Rollback if locked out: re-open tcp/22 in the Hetzner firewall from the
console.
Token rotation
# regenerate the connector token (Zero Trust account, scoped API token)
curl -s -X POST -H "Authorization: Bearer $CF_API_TOKEN" \
".../accounts/b12538c0.../cfd_tunnel/26caa5ed.../token" # returns new token
# write it back (never echo to a shell history / argv):
{ printf 'TUNNEL_TOKEN='; cat newtoken; echo; } | sudo tee /etc/cloudflared/devbox-ssh.env
sudo systemctl restart cloudflared-devbox-ssh.service
Health check
curl -s -H "Authorization: Bearer $CF_API_TOKEN" \
".../accounts/b12538c0.../cfd_tunnel/26caa5ed..." | jq '.result.status' # "healthy"
systemctl is-active cloudflared-devbox-ssh.service # "active"
Known cruft (unrelated)
cloudflared.service (distinct from cloudflared-devbox-ssh.service and
cloudflared-upsquad.service) is a broken leftover unit whose ExecStart
points at a missing /tmp/cloudflared binary; it flaps in auto-restart. Safe to
systemctl disable --now cloudflared.service — left untouched here because it
was pre-existing and outside this change's scope.