Cloudflare
A cloudflared Deployment runs in-cluster, creating an encrypted tunnel
to the Cloudflare edge using a remotely-managed (token-based) tunnel,
as recommended by the official Cloudflare guide.
Remotely-Managed Tunnel (Recommended)
Prerequisites
- Cloudflare account with Zero Trust enabled
- A domain zone added to Cloudflare
cloudflaredCLI installed locally- Cluster can reach Cloudflare on port
7844
Step 1: Create a Tunnel in the Dashboard
- Go to Zero Trust → Networks → Cloudflare Tunnels
- Select Create a tunnel
- Choose Cloudflared and name it (e.g.
k8s-tunnel) - Copy the tunnel token (e.g.
eyJhIjoi...)
Step 2: Store the Token
kubectl create ns cloudflare-tunnel
kubectl -n cloudflare-tunnel create secret generic tunnel-token \
--from-literal=token=<YOUR_TUNNEL_TOKEN>
Step 3: Deploy cloudflared
The Deployment runs 2 replicas (for HA — guide: replicas are for HA, not LB). Each replica connects to Cloudflare with the same tunnel token — no need for separate tunnels per pod.
Configuration: cloudflare-k8s/deployment.yaml
- Routes traffic based on Public hostnames configured in the Cloudflare dashboard
- Each replica exposes a
/readyendpoint on port2000for liveness checks - ICMP support is enabled via
net.ipv4.ping_group_rangesysctl
Step 4: Deploy httpbin (Test App)
Deploy a sample httpbin application to verify tunnel connectivity:
This creates a Deployment (2 replicas) and ClusterIP service named
httpbin-service in the cloudflare-tunnel namespace.
Step 5: Configure Public Hostnames
In the Cloudflare dashboard under the tunnel, add Public hostnames:
| Hostname | Service |
|---|---|
lab.example.com |
http://traefik.kube-system.svc:80 |
*.lab.example.com |
http://traefik.kube-system.svc:80 |
For direct testing without Traefik, point a hostname straight at httpbin:
| Hostname | Service |
|---|---|
httpbin.lab.example.com |
http://httpbin-service.cloudflare-tunnel.svc:80 |
Traffic flows: User → Cloudflare Edge → cloudflared pod → Service → Pod
Step 6: Verify
Expected output:Test the httpbin endpoint:
Terraform — Tunnel Routes & Zero Trust
The cloudflare-k8s/ Terraform workspace manages private network routes
and Gateway rules for the tunnel:
Resources created:
| Resource | Purpose |
|---|---|
cloudflare_argo_tunnel |
Zero Trust tunnel definition |
cloudflare_tunnel_route |
Routes Kubernetes API IPs through the tunnel |
cloudflare_teams_list |
IP list for the API server |
cloudflare_teams_rule |
Bypass HTTP inspection for kubectl traffic |
Note
The Terraform-managed tunnel (cloudflare_argo_tunnel) is separate from
the dashboard-created tunnel used by the Deployment. Update main.tf to
reference the correct tunnel ID if you want Terraform to manage tunnel routes
for the dashboard-created tunnel.
Cloudflare Operator (Alternative)
A separate operator that manages DNS records and tunnels declaratively via Custom Resources:
Source: adyanth/cloudflare-operator