Cloudflare Zero Trust and Access for Internal Apps
Why Zero Trust for internal apps
Traditional: admin panel at admin.yourcompany.com → protect with basic auth + IP whitelist.
Problems:
- Basic auth passwords leak
- IP whitelist breaks when staff work from cafes
- No audit trail of who accessed what
- VPN for everyone is heavy and brittle
Zero Trust:
- Employees log in with SSO (Google, Microsoft, Okta)
- Cloudflare verifies identity at the edge
- Each app has its own policy (which users, from where, with MFA)
- Every request logged
- No passwords or shared secrets
Free plan: up to 50 users free. Paid: $3-7/user/month.
Architecture
Employee browser
│
▼
Cloudflare edge ◄── SSO provider (Google/Microsoft/Okta)
│
▼ (identity verified)
DomainIndia origin (admin app, staging, internal tool)Cloudflare inserts an Authorization header or JWT; your origin trusts it because the traffic arrives via Cloudflare Tunnel.
Step 1 — Enable Cloudflare Zero Trust
- Log in to Cloudflare dashboard
- Zero Trust (in left sidebar) → click "Launch"
- Choose team name (becomes
team-name.cloudflareaccess.com) - Select "Free" plan (sufficient for most small teams)
Step 2 — Add SSO provider
Zero Trust → Settings → Authentication → Login methods → Add new.
Google Workspace:
- Create OAuth 2.0 credentials in Google Cloud Console
- Add redirect URI shown by Cloudflare
- Copy Client ID + Secret into Cloudflare
One-time PIN (no SSO):
- Simplest — users get emailed a code
- Good for external contractors / partners
Step 3 — Create an Access application
Zero Trust → Access → Applications → Add application → Self-hosted.
- Application name:
Admin Panel - Subdomain:
admin - Domain:
yourcompany.com - Session duration: 24 hours
Policy:
- Action: Allow
- Include: Emails ending in
@yourcompany.com - Require: Authentication via Google
Optional extra:
- Require MFA (once Google provides it)
- Include specific IPs (office network)
- Require certain countries (block rest of world)
Step 4 — Cloudflare Tunnel (recommended)
Traditional: expose your origin to the internet + use Access to block.
Better: Cloudflare Tunnel — origin makes outbound connection, never exposes a public port.
- Zero Trust → Networks → Tunnels → Create tunnel
- Name the tunnel
- Copy the install command shown, run on your DomainIndia VPS:
```bash
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.rpm -o cloudflared.rpm
sudo rpm -i cloudflared.rpm
sudo cloudflared service install <TOKEN_FROM_DASHBOARD>
```
- Configure routes:
- Hostname: admin.yourcompany.com
- Service: http://localhost:3000 (your internal app)
- DNS auto-configures — no manual DNS record needed
Origin server (localhost:3000) never exposed to internet. Traffic exits only to Cloudflare.
Step 5 — Verify origin identity
Your app should only trust requests from Cloudflare Access. Two options:
Option A — `Cf-Access-Jwt-Assertion` header:
Cloudflare adds this JWT header to every authenticated request. Verify in your app:
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({
jwksUri: 'https://team-name.cloudflareaccess.com/cdn-cgi/access/certs',
});
app.use(async (req, res, next) => {
const token = req.headers['cf-access-jwt-assertion'];
if (!token) return res.status(401).send('No access token');
const decoded = jwt.decode(token, { complete: true });
const key = await client.getSigningKey(decoded.header.kid);
const payload = jwt.verify(token, key.getPublicKey(), {
audience: 'YOUR_AUD', // shown in Access app settings
issuer: 'https://team-name.cloudflareaccess.com',
});
req.user = { email: payload.email, groups: payload.groups };
next();
});Option B — `CF-Connecting-IP` whitelist:
Only accept requests from Cloudflare IP ranges. Simpler but less strong. See Cloudflare IP list.
Step 6 — Policies for fine-grained access
Different rules for different apps:
Application: Production database console
Policy: Allow
Include: user is DBA role
Require: MFA + India-only IP
Session: 1 hourApplication: Marketing CMS
Policy: Allow
Include: @yourcompany.com OR [email protected]
Session: 8 hoursApplication: Staging site
Policy: Allow
Include: @yourcompany.com
Bypass: from office IP 120.60.X.X
Session: 24 hoursStep 7 — Logs and audit
Zero Trust → Logs → Access shows:
- Who accessed what, when, from where
- Failed auth attempts (useful for threat detection)
- MFA challenges
Export to SIEM via Logpush (paid) or manually via API.
Cloudflare WARP for outbound
For fully zero-trust deploys, WARP agent on employee laptops forces all traffic through Cloudflare — including DNS queries. Adds malware filtering, DNS-based filtering of malicious sites, even from coffee-shop WiFi.
Common patterns
Pattern 1: Protect Grafana / internal dashboards
Grafana → Tunnel (localhost:3000) → Access policy (admins only) → grafana.yourcompany.com
No password on Grafana itself. Access is the gatekeeper. Grafana's auth_proxy module trusts the JWT identity.
Pattern 2: Partner extranet
External partners get invited via email. They sign in with one-time PIN. Policy restricts to specific URLs (/partner/*) only. Ticketing quick + no account provisioning burden.
Pattern 3: SSH via Access
Zero Trust can broker SSH connections too. Install cloudflared access ssh on laptops. No public SSH port needed on VPS. Every session auditable.
Migration — from password-protected admin to Zero Trust
- Set up Zero Trust + SSO (5 min)
- Create Access application for admin panel (2 min)
- Install cloudflared tunnel on VPS (5 min)
- Update DNS to proxy through Cloudflare
- Test with a test user
- Remove basic auth from origin (now redundant)
- Announce to team + share SSO login URL
Total migration: under 1 hour for a single app.
Common pitfalls
FAQ
Free up to 50 users. Beyond that: $3/user/mo (teams up to 250) or $7/user/mo (unlimited + ZTNA features).
Zero Trust is per-app authentication; VPN is network-level. Zero Trust is modern practice — narrower blast radius if a user is compromised.
You can use external DNS, but CF must proxy the traffic for policies to apply. Easier to move DNS to Cloudflare.
Slightly (edge hop). 20-50ms added latency typical. For sub-100ms internal apps, acceptable.
Access supports SSH, RDP, kubectl, databases via Cloudflare's Browser Isolation + WARP. Beyond scope of this article.
Front your DomainIndia internal apps with Cloudflare Zero Trust. See our hosting options