06-reference/research

cloudflare tunnel security mac mini

2026-05-11·research-brief·source: deep-research·! medium
cloudflaretunnelzero-trustaccessmac-minisecurityhq-raydata-cohardening

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)

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:

  1. Refresh the token via dashboard or API.
  2. The old token cannot establish new connections. Existing connections stay alive until cloudflared is restarted.
  3. To force-disconnect existing connections, hit DELETE /accounts/$ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/connections.
  4. 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:

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":

  1. 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.
  2. 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/config from a gh auth session.
  3. 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.
  4. Google account → Security → "Sign out of all devices" + force MFA re-enrollment. Apple ID equivalent.
  5. 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.
  6. 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.
  7. 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.
  8. Anthropic / OpenAI / xAI / ElevenLabs API keys stored in 1Password "Ray Agent" vault: rotate each in the respective dashboard.
  9. GitHub: revoke the SSH key registered from the Mac mini + any PATs. GitHub → Settings → SSH and GPG keys + Personal access tokens.
  10. Notion integration secret: rotate via Notion → Settings → Connections.
  11. 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):

  1. 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 cloudflared quarterly is enough, or wire it into the existing IP-drift cron.
  2. Tunnel-credential leakage to git. Self-hosted setups generate a ~/.cloudflared/<TUNNEL_UUID>.json file 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.
  3. 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.
  4. TryCloudflare / quick-tunnel sprawl. Free anonymous tunnels created with cloudflared tunnel --url have 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 quick cloudflared tunnel --url localhost:3000 debug 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.
  5. 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-router endpoint already uses a service token ([[08-tooling/2026-05-01-fat-cat-council-architecture-proposal.md]]); make sure that token is scoped to only the board-router app/path, not the entire hq.raydata.co zone, otherwise the token bypasses Google SSO across the whole HQ.
  6. 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:

  1. Verify Access policy is literal-email (ben@raydata.co), not domain-wide. One-time check, founder, 60 seconds in the Cloudflare dashboard.
  2. Verify FileVault is on. One-time check, founder, 30 seconds in System Settings → Privacy & Security → FileVault.
  3. 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.
  4. 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.
  5. Verify the Fat Cat Council board-router service token is scoped per-app, not zone-wide. One-time check, founder.
  6. 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)

Deferred (not yet, surface too small)

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

  1. Is FileVault actually on for the bedroom Mac mini? (Should be, but verify.) — assignable to founder.
  2. Is the live hq.raydata.co Access policy literal-email or domain? — quick check, then either close or fix.
  3. Is the Fat Cat board-router service token scoped per-app or zone-wide? — quick check; if zone-wide, that's a real find.
  4. Should we wire a tiny Logpush → R2 → iMessage-on-anomaly Worker now, or defer? — recommend defer; revisit when write paths land.
  5. 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.
  6. 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.
  7. 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

Sources

Changelog