Manage Kubernetes ingress traffic with Cloudflare Tunnels via the Gateway API.
- Gateway API v1.x
-
Install cloudflare-kubernetes-gateway with Kustomize:
kubectl apply -k github.com/pl4nty/cloudflare-kubernetes-gateway//config/default?ref=v0.10.1 -
Create a Cloudflare API token with these permissions:
- For User Tokens, Account > Cloudflare Tunnel > Edit and Zone > DNS > Edit
- For Account Tokens, Entire Account > Cloudflare One / Zero Trust > Argo Tunnel (Legacy) > Edit and All Domains > DNS & Zones > DNS > Edit
-
Create a Secret with your Cloudflare Account ID and API token:
Secret manifest
# kubectl create secret generic -n cloudflare-gateway cloudflare-gateway-token --from-literal=ACCOUNT_ID=<account-id> --from-literal=TOKEN=<api-token> apiVersion: v1 kind: Secret metadata: name: cloudflare-gateway-token namespace: cloudflare-gateway type: Opaque stringData: ACCOUNT_ID: <account-id> TOKEN: <api-token>
-
Create a GatewayClass for this controller, referencing the Secret:
GatewayClass manifest
apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: cloudflare spec: controllerName: github.com/pl4nty/cloudflare-kubernetes-gateway parametersRef: group: "" kind: Secret namespace: cloudflare-gateway name: cloudflare-gateway-token
-
Create a Gateway from the GatewayClass; each Gateway corresponds to a Cloudflare Tunnel. In most cases you should only need one per cluster.
Gateway manifest
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: gateway namespace: cloudflare-gateway spec: gatewayClassName: cloudflare # listeners are not used but need to be present listeners: - name: http protocol: HTTP port: 80
-
Manage traffic with HTTPRoutes.
HTTPRoute example manifest
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: example-route namespace: default spec: parentRefs: - name: gateway namespace: cloudflare-gateway hostnames: - example.com rules: - backendRefs: - name: example-service port: 80
-
(optional) Install Prometheus ServiceMonitors to collect controller and cloudflared metrics:
kubectl apply -k github.com/pl4nty/cloudflare-kubernetes-gateway//config/prometheus?ref=v0.10.1
The v1 Core spec is not yet supported, as some features (eg header-based routing) aren't available with Tunnels. The following features are supported:
- HTTPRoute hostname and path matching
- HTTPRoute Service backendRefs without filtering or weighting
- Gateway gatewayClassName and listeners only
- GatewayClass Core fields
Warning
Currently, DNS records are not deleted when route hostnames are modified or when routes are deleted. Requests to orphaned hostnames respond with an HTTP 404 Not Found, rather than a DNS lookup failure. For more details, see #206.
By default, a Cloudflare Tunnel client (cloudflared) runs for each Gateway, as a Deployment in the Gateway's namespace.
It can be configured with a ConfigMap referenced from the Gateway:
Gateway manifest
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
namespace: cloudflare-gateway
spec:
gatewayClassName: cloudflare
listeners:
- name: http
protocol: HTTP
port: 80
infrastructure:
parametersRef:
group: ""
kind: ConfigMap
name: gatewayConfigMap manifest
apiVersion: v1
kind: ConfigMap
metadata:
name: gateway
namespace: cloudflare-gateway
data:
# Disables the internal cloudflared deployment entirely. Separate clients must be deployed
disableDeployment: "true" # string
# The following are literal strings in yaml format that are passed directly through to the deployment spec
# Values are examples, not the defaults
# DeploymentSpec.replicas
replicas: "1" # string
# PodSpec.nodeSelector
nodeSelector: |
disktype: ssd
# PodSpec.affinity
affinity: |
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
# PodSpec.tolerations
tolerations: |
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
# PodSpec.containers[gateway].resources
resources: |
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
# Set as the TUNNEL_LOGLEVEL environment variable
loglevel: "info"Additional cloudflared clients can be deployed (guide)
to customise parameters that aren't exposed in the Gateway config,
and traffic will be load-balanced between them and the built-in client.
The Gateway controller creates a Secret with the same name as the Gateway containing the token for the Cloudflare Tunnel,
which can be passed directly to envFrom in custom deployments.
See also:
Copyright (c) 2023-2026 Tom Plant, Elias Elwyn, and contributors, MIT License.
This project is compliant with REUSE v3.3.