Cloudflare Tunnel + Access security model for hq.raydata.co — what a solo founder actually has to do
The question
From the Notion research backlog, 2026-05-11:
What's the production-tested security model for exposing a personal Mac Mini behind Cloudflare Tunnel + Cloudflare Access for a single-user dashboard (hq.raydata.co) — specifically: token rotation cadence, what happens if the Mac Mini is stolen, audit logging requirements, and the 3-5 most common Tunnel-exposure CVEs/misconfigurations to design around?
Driving need: hq.raydata.co already runs on Cloudflare Pages with Access SSO ([[01-projects/hq-raydata-co/2026-04-22-hq-proposal-v1.md]]) and the next phase exposes a Hono read-only API on the Mac mini at api.hq.raydata.co via Tunnel. Surface will expand later (vault writes, quick-capture, possibly more services). Time to harden before the surface area grows.
Headline finding
For a single-user setup, the load-bearing security move is not Tunnel-token rotation — it is the Access policy (Google SSO restricted to ben@raydata.co, MFA enforced at the Google account, optional service-token bypass disabled). The Tunnel token is functionally a secret stored on a single device; if the Mac mini is stolen, you delete the tunnel from the dashboard, which kills every replica's authority instantly. Token "rotation cadence" is more about hygiene than threat model. The more dangerous failure modes are (1) leaking the tunnel JSON credentials file into git, (2) an Access policy that's too permissive (email-domain @raydata.co instead of literal ben@raydata.co), (3) running a TryCloudflare quick-tunnel and forgetting to delete it, (4) exposing services in the Tunnel config that you didn't mean to publish, and (5) running an old cloudflared binary that ships a CVE'd Go runtime. None of these are exotic. All are one-time-setup discipline plus a quarterly check.
What we already know (vault)
- [[01-projects/hq-raydata-co/2026-04-22-hq-proposal-v1.md]] — the canonical hq.raydata.co architecture. Stack: Cloudflare Pages + Access (Google SSO,
ben@raydata.coonly) + Tunnel from Mac mini exposing a Hono API. Optional TOTP step-up for sensitive endpoints. 24h session refresh. - [[08-tooling/2026-04-30-ip-restricted-policies-tracker.md]] — the existing operational discipline: residential dynamic IP on Frontier, daily IP-drift cron, single allowlist registry. Implication: outbound-from-Mac-mini IP-allowlists are already a managed discipline; Tunnel completely sidesteps the inbound version (Tunnel makes the public IP irrelevant for hq.raydata.co).
- [[02-sops/2026-04-26-rdco-web-app-deployment-standard.md]] — the Cloudflare API token is in GitHub Secrets and rotates yearly. Same token does Pages deploys for every RDCO repo. Implication: that token is a separate concern from the Tunnel token; both rotate, different cadences, different blast radius.
- [[08-tooling/2026-05-01-fat-cat-council-architecture-proposal.md]] — confirms Cloudflare Access is "already in production for hq.raydata.co. Gates the
board-routerendpoint with a service token." Tells us at least one service-token auth path already exists; that's a separate keypair to track. - [[08-tooling/2026-05-02-lazyweb-mcp-security-review-decision.md]] — the existing security-review SOP and the "blast radius if compromised" framing applied to MCP installs. Same framing applies here; the Mac mini's filesystem is the real prize, not the Tunnel itself.
What the production-side sources say
Token rotation: cadence and mechanism
Cloudflare's official guidance (Tunnel tokens docs) tells you to "rotate tokens regularly to reduce the risk of compromise" but does not mandate an interval. Mechanism:
- Refresh the token via dashboard or API.
- The old token cannot establish new connections. Existing connections stay alive until
cloudflaredis restarted. - To force-disconnect existing connections, hit
DELETE /accounts/$ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/connections. - On each replica, reinstall the service with the new token:
sudo cloudflared service install <NEW_TOKEN>.
What enterprise teams actually do (synthesized from Cloudflare changelog + practitioner write-ups): quarterly rotation as discipline, immediate rotation on suspected compromise. The HA replica pattern only matters if you have multiple replicas; the Mac mini is a single replica, so "rotate during a quiet window and accept ~30s of reconnect" is the practical answer. No production team rotates more aggressively than monthly without automation.
Tunnel-token privileges (what an attacker gets)
A remotely-managed Tunnel token has a flat trust model: "anyone with the token can run the tunnel." It does not let the holder modify the tunnel config in the dashboard, create new ingress rules, or read other Cloudflare account resources — that requires an API token with separate scopes. But it does mean an attacker holding the token can:
- Stand up a parallel
cloudflaredsomewhere else and serve traffic on the same tunnel hostname. - Intercept inbound requests intended for the legitimate replica (Cloudflare load-balances across all replicas using the same token).
Practical implication for the Mac mini setup: if the token is leaked, the attacker can proxy hq.raydata.co API requests through their own machine until you rotate. Access is still in front, so they can't read responses without first defeating Access (Google SSO + MFA), but they can collect traffic metadata and present a malicious response to anyone who makes it past Access.
Mac-mini-stolen flow
Step-by-step revocation in priority order. This should be a printed checklist taped to the inside of a 1Password note titled "Mac mini compromise runbook":
- Cloudflare Zero Trust dashboard → Networks → Tunnels →
<your-tunnel>→ Delete. This nukes the tunnel completely; every credential associated with it stops working. Re-create later from a different machine. Time: ~30 seconds. - Cloudflare dashboard → My Profile → API Tokens → revoke
CLOUDFLARE_API_TOKEN(the one in GitHub Secrets per [[02-sops/2026-04-26-rdco-web-app-deployment-standard.md]]). The thief has read access to every repo cloned on the Mac mini, including any with the token in.git/configfrom agh authsession. - Cloudflare Access → Authentication → revoke all Google SSO sessions for ben@raydata.co. Forces re-auth on every device. The Mac mini's session cookie for hq.raydata.co stops working.
- Google account → Security → "Sign out of all devices" + force MFA re-enrollment. Apple ID equivalent.
- 1Password → revoke the Mac mini's device-specific session (1Password has a per-device list under Settings → Devices). Without this, an unlocked 1Password app on the stolen Mac is the worst leak.
- Stripe RAK (per [[08-tooling/2026-04-30-ip-restricted-policies-tracker.md]]): the IP allowlist is
47.204.119.46/32. The thief has to be on Ben's home WiFi to use it; still rotate as belt-and-suspenders. Stripe Dashboard → Developers → API Keys → roll. - App Store Connect API key (same tracker): no IP allowlist, so this is more urgent. App Store Connect → Users and Access → Keys → Revoke "Ray COO Agent" → generate new.
- Anthropic / OpenAI / xAI / ElevenLabs API keys stored in 1Password "Ray Agent" vault: rotate each in the respective dashboard.
- GitHub: revoke the SSH key registered from the Mac mini + any PATs. GitHub → Settings → SSH and GPG keys + Personal access tokens.
- Notion integration secret: rotate via Notion → Settings → Connections.
- FileVault: macOS FileVault is on by default for Apple Silicon Macs (verify). If on, the disk is encrypted at rest — the thief cannot read
~/rdco-vault/without your login password. This is the single biggest defense for the data side of the breach.
Recoverable after the above flow: every account, every credential, every cloud service. The Mac mini hardware is gone but everything it touched can be re-issued.
Not recoverable: any plaintext secret on disk that was not in 1Password. Audit ~/ for .env, ~/.aws/credentials, ~/.ssh/known_hosts patterns, browser-saved passwords. Per the existing [[../../.claude/projects/-Users-ray/memory/feedback_no_secrets_on_disk.md]] discipline, this should be near-zero, but verify the assumption.
Mac mini disk forensics: even with FileVault, an attacker with the device for a long time and significant resources is a different threat than a smash-and-grab. Realistic threat model for a single founder is the latter.
Audit logging — what's available, what's required
Cloudflare Access authentication logs capture every login attempt (success + failure) against any Access app. Visible at Zero Trust → Insights → Logs. API at /accounts/$ACCOUNT_ID/access/logs/access_requests with Access: Audit Logs Read permission. Documented retention: per Cloudflare's 2025 guidance, block-policy decisions retain ~1 week, authentication logs retain 6 months.
For longer retention or SIEM ingest, Cloudflare Logpush forwards to S3, R2, GCS, Splunk, Datadog, Elastic, etc. There are eight Zero-Trust account-scoped datasets (Access Requests, Audit logs, CASB findings, Gateway DNS / Network / HTTP, Zero Trust Session Logs).
For a solo founder: the dashboard view is enough day-to-day. The right discipline is a weekly 60-second skim of the Access auth log filtered to allowed: false — flag any country / IP / connection-type that isn't expected. The over-engineered version is Logpush → R2 (free tier covers it) + a tiny Worker that pings iMessage when failed-auth count exceeds N/hour. Defer the Logpush wiring until there's a real signal that warrants it; eyeballing the dashboard is fine for v1.
The most common Tunnel-exposure misconfigurations
The CVE / incident landscape for cloudflared specifically is thinner than expected — the binary itself has had few public CVEs. The dominant risk surface is misconfiguration and supply-chain (Go runtime CVEs propagating through cloudflared releases):
- CVE-2024-24790 (Go net/netip, CVSS 9.8). cloudflared's Go-1.22.2-built releases inherited a critical IPv4-in-IPv6 misparse vulnerability that bypasses IP allowlists (GitHub issue #1311). Cloudflare patched by upgrading the Go runtime; the discipline is keep cloudflared current. On macOS:
brew upgrade cloudflaredquarterly is enough, or wire it into the existing IP-drift cron. - Tunnel-credential leakage to git. Self-hosted setups generate a
~/.cloudflared/<TUNNEL_UUID>.jsonfile containing the tunnel's account tag, tunnel secret, and tunnel ID. Multiple GitHub issues document people accidentally committing this. Mitigation:.gitignore ~/.cloudflared/globally + scan with GitGuardian Cloudflare detector on the RDCO org. One-time setup. - Windows-specific token storage flaw (cloudflared issue #666): on Windows, the service installer stores the token in the executable path readable by any local user. Not applicable to the Mac mini, but worth noting if anything ever gets exposed via a Windows Boot Camp / VM partition.
- TryCloudflare / quick-tunnel sprawl. Free anonymous tunnels created with
cloudflared tunnel --urlhave no authentication and have been heavily abused for malware delivery in 2024-2025, notably the SERPENTINE#CLOUD campaign (Securonix writeup). Threat to RDCO: low (we're not running TryCloudflare), but operational risk if a quickcloudflared tunnel --url localhost:3000debug session is left running and the trycloudflare.com URL gets indexed. Mitigation: never use unauthenticated quick-tunnels for anything you don't immediately tear down; for the Mac mini API, always use a named tunnel with Access in front. - Permissive Access policy. The two most common misconfigurations:
- Domain-wide email match (
@raydata.co) instead of literal email (ben@raydata.co). If a future RDCO hire signs up for a Google Workspace account, they suddenly have access to the founder's HQ. Use literal email for v1. - Allowing service tokens at the application level instead of a separate sub-path. The Fat Cat Council
board-routerendpoint already uses a service token ([[08-tooling/2026-05-01-fat-cat-council-architecture-proposal.md]]); make sure that token is scoped to only theboard-routerapp/path, not the entirehq.raydata.cozone, otherwise the token bypasses Google SSO across the whole HQ.
- Domain-wide email match (
- Bonus: Bypass policies / "Service Auth" without IP scoping. Cloudflare Access lets you create "bypass" rules. If anything in the policy chain says "bypass for these IPs" and the IP list is broader than intended (e.g. an entire office subnet that no longer exists), Access is silently disabled for that range. Audit the policy at creation and again any time an IP-restricted policy in [[08-tooling/2026-04-30-ip-restricted-policies-tracker.md]] is touched.
The deeper threat-actor abuse pattern (Cloudflare Tunnel as malware infrastructure) is mostly relevant defensively to enterprise blocklists, not to a single user running a tunnel from their own home — RDCO is on the "victim could be impersonated" side, not the "attacker" side. The mitigations above cover what's in our threat model.
Cross-check: vault vs web
| Topic | Vault state | Web/CF guidance | Gap to close |
|---|---|---|---|
| Tunnel-token rotation cadence | Not codified anywhere | "Rotate regularly", no interval | Add: quarterly tunnel-token rotation to the IP-drift cron checklist |
| Mac-mini-stolen runbook | Implicit; no consolidated doc | Cloudflare doc covers Tunnel side only | Add: a single "Mac mini compromise runbook" (the 11-step list above) — file in 02-sops/ and reference from 1Password note |
| Audit-log review cadence | None | Dashboard-viewable, 6-month retention | Add: weekly 60-second Access-auth-log skim, no automation needed v1 |
.cloudflared/ git-ignore |
Not in any RDCO bootstrap doc | GitGuardian + repeated github issues | Add: line to [[02-sops/2026-04-26-rdco-web-app-deployment-standard.md]] bootstrap checklist, and global .gitignore |
| cloudflared binary version drift | Not tracked | CVE-2024-24790 motivates currency | Add: brew upgrade cloudflared to a quarterly hygiene cron |
| Access policy literal-email vs domain | Proposal says ben@raydata.co only |
Best practice confirmed | Verify the live policy matches the proposal — one-time check |
| Service-token scope (Fat Cat board-router) | Mentioned, scope not pinned | Cloudflare best practice = scope per-app | Verify the service-token policy is scoped to the board-router app only, not the whole HQ zone |
| Logpush / SIEM | Not wired | Available; free into R2 | Defer until traffic warrants it; revisit at v2 or when surface expands |
Mapping for RDCO — what's live discipline today vs. what's deferred
Live discipline TODAY (founder-or-Ray actionable now)
These are non-negotiable for the Tunnel-API expansion of hq.raydata.co:
- Verify Access policy is literal-email (
ben@raydata.co), not domain-wide. One-time check, founder, 60 seconds in the Cloudflare dashboard. - Verify FileVault is on. One-time check, founder, 30 seconds in System Settings → Privacy & Security → FileVault.
- Add
~/.cloudflared/to global gitignore + scan RDCO org with GitGuardian. One-time, Ray can do the gitignore + pattern check; founder grants GitGuardian if not already wired. - File a "Mac mini compromise runbook" SOP (the 11-step list above). One-time write, then live in
02-sops/with a 1Password note pointing to it. Ray-actionable, file today. - Verify the Fat Cat Council
board-routerservice token is scoped per-app, not zone-wide. One-time check, founder. - Add
brew upgrade cloudflared+ tunnel-token rotation reminder to the quarterly hygiene set. Same cron that does the IP-drift check; add to~/.claude/scripts/scheduled-jobs.txt.
Ongoing vigilance (lightweight, not a full-time concern)
- Weekly 60-second Access-auth-log skim filtered to
allowed: false. Add to the morning-prep / Sunday review cycle. - Quarterly tunnel-token rotation (March / June / September / December). Calendar reminder. ~5 minutes including replica reinstall.
- Quarterly cloudflared upgrade. Same cadence.
- Annual Cloudflare API token rotation (already documented in the deploy SOP). Already discipline; keep.
Deferred (not yet, surface too small)
- Logpush → R2 + SIEM-style alerting Worker. Not justified for single-user dashboard with no commercial blast radius. Revisit at v2 or when team grows.
- Hardware MFA key (YubiKey) for Cloudflare Access step-up. Google SSO + Google's existing MFA is enough for v1. Worth doing when sensitive write paths land.
- Multi-replica HA tunnel. Only worth it if downtime starts costing more than the operational complexity. Single Mac mini replica is fine for v1.
- Cloudflare Tunnel egress IP (Cloudflare One Connector). Would eliminate the IP-drift discipline entirely but adds cost + complexity. Revisit if the IP-drift cron starts firing more than ~quarterly.
Practical opinion
The most underweighted discipline in the public discourse is the Mac-mini-stolen runbook. People obsess over token rotation cadence (which Cloudflare itself doesn't define) and ignore the ten-minute exercise of writing down what to do in the first 15 minutes after a smash-and-grab. For a founder running ops from a single bedroom Mac mini, that runbook is the highest-leverage security artifact, ahead of any rotation schedule.
The second underweighted move is literal-email Access policy vs. domain-wide. Most write-ups show @example.com as the canonical pattern. For a single-user dashboard, that pattern is wrong by default — it grants future-employee access without any explicit decision.
The third is keeping cloudflared current. CVE-2024-24790 wasn't in cloudflared code, it was a Go runtime CVE that propagated through every binary built on the unpatched runtime. The discipline is "upgrade binaries quarterly" not "audit binaries annually."
Token rotation cadence is real but not the load-bearing discipline for a single-user setup. Quarterly is fine. Monthly is fine. Annually is mediocre but recoverable. Never-rotated for two years is bad. The actual blast radius if a single tunnel token leaks (assuming the rest of the security model is in place) is "attacker can run a parallel cloudflared and hit Access prompts they can't pass" — which is meaningfully bounded.
Follow-up questions surfaced
- Is FileVault actually on for the bedroom Mac mini? (Should be, but verify.) — assignable to founder.
- Is the live
hq.raydata.coAccess policy literal-email or domain? — quick check, then either close or fix. - Is the Fat Cat
board-routerservice token scoped per-app or zone-wide? — quick check; if zone-wide, that's a real find. - Should we wire a tiny Logpush → R2 → iMessage-on-anomaly Worker now, or defer? — recommend defer; revisit when write paths land.
- Is there appetite for moving the Mac mini's egress to a Cloudflare Tunnel egress IP (would obsolete the IP-drift cron entirely)? — strategic decision, not urgent.
- Are there any other RDCO surfaces (Squarely? Sanity Check?) that would benefit from running behind the same Access policy, or is that scope creep? — design question for v2.
- Do we want the Mac mini compromise runbook to live in 1Password (encrypted, accessible from any device on first re-login) or in the vault (faster to write, requires another device to read)? — recommend both: vault as canonical, 1Password note as the printable runbook.
Related
- [[../../01-projects/hq-raydata-co/2026-04-22-hq-proposal-v1.md]] — the canonical hq.raydata.co architecture
- [[../../08-tooling/2026-04-30-ip-restricted-policies-tracker.md]] — the operational pattern this brief extends
- [[../../02-sops/2026-04-26-rdco-web-app-deployment-standard.md]] — web-app deploy standard (CF token rotation discipline)
- [[../../08-tooling/2026-05-01-fat-cat-council-architecture-proposal.md]] — service-token usage on the same Access policy
- [[../../08-tooling/2026-05-02-lazyweb-mcp-security-review-decision.md]] — the blast-radius framing pattern this brief reuses
~/.claude/projects/-Users-ray/memory/feedback_no_secrets_on_disk.md— the underlying secret-storage discipline
Sources
- Cloudflare Tunnel tokens — Cloudflare Docs
- Access authentication logs — Cloudflare One docs
- Logpush integration — Cloudflare One docs
- Cloudflare Tunnel — Cloudflare One docs
- cloudflared issue #1311 — CVE-2024-24790 Go net/netip
- cloudflared issue #666 — Windows tunnel-token storage
- GitGuardian — Remediating Cloudflare API credential leaks
- The Hacker News — Cybercriminals abusing Cloudflare Tunnels (Aug 2024)
- Securonix — SERPENTINE#CLOUD analysis
- Cloudflare blog — Cloudflare Zero Trust + Datadog SIEM integration
- I finally understand Cloudflare Zero Trust tunnels — David Mohl
Changelog
- 2026-05-11 — initial brief filed by /deep-research engine in response to Notion backlog item 34bf7d49-36d1-8138-a96f-f0053722e301