Skip to content

prototype · access-control

Zero Trust Access Patterns

Experiments comparing practical access models for private web routes — Cloudflare Access, signed tokens, and application-layer JWT validation.

  • zero-trust
  • cloudflare-access
  • private-routes
  • security

This lab compares access control models for private web routes. The goal is operational: which approaches actually work, under what conditions, and where each one breaks.

What “private route” means in practice

A private route is one that should not be accessible to unauthenticated users. The gap between “should not be accessible” and “is not accessible” is where most access control failures live.

MechanismWhat it actually does
noindexAsks search crawlers not to index the URL
robots.txtAsks compliant crawlers not to visit the path
Security through obscurityHopes attackers don’t guess the URL
Cloudflare Access (without origin lockdown)Adds authentication but leaves origin reachable
Cloudflare Access + origin lockdownGates the route at the network edge
Application-layer JWT validationDefense in depth, catches origin bypasses
Cloudflare TunnelEliminates the public-facing origin entirely

Pattern 1: Cloudflare Access with Tunnel

Strongest practical option for a small deployment. cloudflared creates an outbound-only tunnel — the origin has no public IP. All ingress flows through Cloudflare’s network after authentication.

What it protects: Unauthenticated reads, direct-to-origin attacks, port scans What it doesn’t protect: Authenticated users with excessive permissions, Cloudflare infrastructure incidents, SSRF from inside the network

Setup cost: Moderate — requires running cloudflared as a system service and configuring DNS via the Cloudflare dashboard.

Pattern 2: Cloudflare Access + firewall + JWT validation

For cases where Tunnel is not available (existing infrastructure, VPS with public IP):

  1. Cloudflare Access policy in front of the route
  2. Firewall rule allowing only Cloudflare IPs to reach port 443
  3. Application validates Cf-Access-Jwt-Assertion header

This achieves the same security posture as Tunnel with more operational surface.

Weak point: Firewall rules drift. Cloudflare’s IP ranges change. If an IP is added to Cloudflare’s range and not to your allowlist, the gap is invisible until someone exploits it. Tunnel avoids this class of drift.

Pattern 3: Signed one-time tokens

For time-limited access without adding a user to a persistent policy:

  1. Server generates a token: HMAC-SHA256 over {user_id}:{resource_id}:{expiry} with a server-held secret
  2. Token is sent to the recipient out-of-band
  3. Application validates signature, checks expiry, marks token as used
  4. Used tokens stored in a fast store (Redis, Cloudflare KV) with TTL matching expiry

Suitable for: Temporary CV access, shared document links, contractor staging access Not suitable for: Long-lived access, high-frequency use cases (token store becomes a bottleneck), scenarios where the server cannot maintain state

Experiment log

Cloudflare Access + Spring Boot JWT validation — working prototype. Filter validates aud, iss, signature, and expiry. Key rotation picked up within cache TTL (60 minutes). No issues in testing.

One-time token via Cloudflare Worker — in progress. Worker generates tokens stored in KV, validates on request, marks used. Token invalidation is atomic with KV’s compare-and-swap pattern.

Tunnel on a low-spec VPS — working. cloudflared memory footprint is modest (~50MB). DNS propagation after tunnel route dns was fast (< 2 minutes). The main operational concern is the cloudflared process dying — solved with a systemd unit with restart policy.

Experiment

Prototype boundary

Labs are exploratory notes, not production guarantees. Status labels make maturity explicit.

Privacy

Safe publication rule

Labs should describe patterns and tradeoffs without exposing private infrastructure, tokens, identity provider details, or operational logs.

Related work