Skip to content

Security & Access

Cloudflare Access model

Three Access applications gate the fleet (terraform/modules/access/main.tf):

Application Domain Who Notes
Dashboard *.tagai.uk Admins + Users Google IdP, email OTP, or admin group
Node-RED editor *-nodered.tagai.uk Admins only GitHub org team, Google, admin group
SSH *-ssh.tagai.uk Admins only GitHub org team, Google, admin group

Admins authenticate via email or GitHub org team membership (var.github_org_team); regular users authenticate via email only. See reference/email-otp-authentication.md and reference/access-control-reference.md for the full policy/IdP detail.

There is no VPN and no exposed port on any device — every path in (SSH, Node-RED, dashboard) goes through a Cloudflare Tunnel, and every hostname is gated by an Access application before it reaches the tunnel.

SSH access

One-time setup on your machine:

brew install cloudflare/cloudflare/cloudflared
cat >> ~/.ssh/config <<EOF
Host *.tagai.uk
    ProxyCommand cloudflared access ssh --hostname %h
EOF

Then:

ssh tagai@rpi-prod-<serial>-ssh.tagai.uk

Ansible itself defaults to connecting over the device's LAN IP, not the tunnel — pass -e use_tunnel=true (or TUNNEL=true to the relevant task ansible:* command) to route through Cloudflare Access instead, for off-network management.

MQTT mTLS

Devices authenticate to EMQX with per-device client certificates, not passwords — see mqtt-emqx.md.

Secrets handling

  • Ansible Vault encrypts ansible/inventory/production/group_vars/vault.yml (password at ansible/.vault-password, never committed)
  • Tunnel credentials, MQTT certs, and SSH deploy keys are all git-ignored — see .gitignore for the exact patterns
  • docs/All connections.yaml (an MQTTX export that previously contained a plaintext MQTT password) has been removed from the repo; if you still have that password in use anywhere, rotate it in EMQX

Known caveat: Cloudflare Pages fallback domain

The team wiki (this site) is built in GitHub Actions and deployed to Cloudflare Pages by direct upload (not GitHub Pages — this repo is private and our GitHub org plan doesn't include private-repo GitHub Pages). docs.tagai.uk is a Cloudflare Pages custom domain, gated by the docs Access application same as everything else.

Every Cloudflare Pages project also gets a default <project>.pages.dev fallback domain, which is not confirmed to be gated by Cloudflare Access — Cloudflare's own "protect preview deployments" toggle is dashboard-only (not exposed via Terraform) and by Cloudflare's own documentation only covers per-deployment preview URLs, not necessarily the project's general .pages.dev domain. Until that's explicitly verified (check Settings → Access on the gaisro-technika-docs Pages project in the Cloudflare dashboard), treat gaisro-technika-docs.pages.dev as potentially reachable without Cloudflare Access. Mitigations in place regardless: the site is marked noindex, and every device link the wiki publishes (*-nodered.tagai.uk, *-ssh.tagai.uk) is itself independently gated by its own Access application, so even an unauthenticated hit on the fallback domain only exposes the wiki's own low-sensitivity content, not device access.