cfgate.iocfgate v0.2.0-alpha.11 · Release documentation
Annotations Reference
Complete reference for all cfgate annotations.
Route Annotations
Section titled “Route Annotations”Per-route configuration applied to Gateway API HTTPRoute resources.
| Annotation | Values | Default | Description |
|---|---|---|---|
cfgate.io/origin-protocol | http, https | http | Backend protocol |
cfgate.io/origin-ssl-verify | true, false | inherited | TLS certificate verification |
cfgate.io/origin-connect-timeout | Duration string (30s, 1m) | 30s | Origin connection timeout |
cfgate.io/origin-http-host-header | Hostname string | none | Host header override sent to origin |
cfgate.io/origin-server-name | Hostname string | none | TLS SNI server name |
cfgate.io/origin-ca-pool | Managed file path | none | CA certificate pool path |
cfgate.io/origin-http2 | true, false | inherited | HTTP/2 to origin |
cfgate.io/origin-h2c | true, false | inherited | HTTP/2 cleartext (h2c) to origin |
cfgate.io/ttl | 1-86400 | inherited | DNS record TTL in seconds |
cfgate.io/cloudflare-proxied | true, false | true | Cloudflare proxy (orange cloud) |
cfgate.io/access-policy | name or namespace/name | none | Deprecated: resolves a policy reference for status only |
cfgate.io/hostname | RFC 1123 hostname | none | Override the route hostname |
Default for cfgate.io/origin-protocol: http
Detailed Annotation Documentation
Section titled “Detailed Annotation Documentation”cfgate.io/origin-protocol
Section titled “cfgate.io/origin-protocol”Specifies the protocol used to connect from cloudflared to the backend service.
Valid values: http, https
Default: http
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
Protocol values are case-insensitive: HTTPS and https both select TLS to the origin. Invalid values are rejected. For a private CA, configure the tunnel’s CA Secret and keep certificate verification enabled. See origin parameters for the connector contract.
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: secure-backend namespace: default annotations: cfgate.io/origin-protocol: "https"spec: parentRefs: - name: cloudflare-tunnel namespace: cfgate-system hostnames: - secure.example.com rules: - backendRefs: - name: my-service port: 443cfgate.io/origin-ssl-verify
Section titled “cfgate.io/origin-ssl-verify”Controls whether cloudflared verifies the TLS certificate presented by the origin server.
Valid values: true, false, 1, 0, yes, no (case-insensitive)
Default: inherited from tunnel defaults
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
Omission inherits the tunnel’s originDefaults.noTLSVerify setting. Without an insecure tunnel default, certificates are verified. Explicit true enables verification even under an insecure tunnel default; explicit false disables it for this route. Prefer a trusted CA bundle for private certificates.
metadata: annotations: cfgate.io/origin-protocol: "https" cfgate.io/origin-ssl-verify: "false"cfgate.io/origin-connect-timeout
Section titled “cfgate.io/origin-connect-timeout”Maximum time cloudflared waits to establish a connection to the origin server.
Valid values: Go duration string (e.g., 30s, 1m, 1h30m)
Default: inherited from tunnel defaults (otherwise 30s)
Use a positive whole number of seconds, such as 10s or 1m. Values that would be rounded or replaced by an SDK fallback are rejected.
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
metadata: annotations: cfgate.io/origin-connect-timeout: "10s"cfgate.io/origin-http-host-header
Section titled “cfgate.io/origin-http-host-header”Overrides the HTTP Host header sent to the origin server. Useful when the origin expects a specific hostname that differs from the public-facing hostname.
Valid values: Hostname string
Default: Not set (uses the route hostname)
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
metadata: annotations: cfgate.io/origin-http-host-header: "internal-service.local"cfgate.io/origin-server-name
Section titled “cfgate.io/origin-server-name”Specifies the TLS SNI (Server Name Indication) server name for the connection to the origin. Used when the origin’s TLS certificate is issued for a different name than the connecting hostname.
Valid values: Hostname string
Default: Not set
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
metadata: annotations: cfgate.io/origin-server-name: "real-cert-name.internal"cfgate.io/origin-ca-pool
Section titled “cfgate.io/origin-ca-pool”Literal in-container path to a CA certificate pool file used to verify the origin server’s TLS certificate. For alpha.5, cfgate accepts only its managed mount path, /etc/cfgate/origin-ca-pool/ca.pem, and only when the referenced CloudflareTunnel has spec.originDefaults.caPoolSecretRef configured.
Use spec.originDefaults.caPoolSecretRef on CloudflareTunnel when cfgate should mount a Kubernetes Secret. That managed Secret mount is available at /etc/cfgate/origin-ca-pool/ca.pem.
Valid values: /etc/cfgate/origin-ca-pool/ca.pem
Default: Not set (system CA pool)
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
metadata: annotations: cfgate.io/origin-ca-pool: "/etc/cfgate/origin-ca-pool/ca.pem"cfgate.io/origin-http2
Section titled “cfgate.io/origin-http2”Enables HTTP/2 for the connection between cloudflared and the origin server.
Valid values: true, false, 1, 0, yes, no (case-insensitive)
Default: inherited from tunnel defaults (otherwise false)
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
metadata: annotations: cfgate.io/origin-http2: "true"cfgate.io/origin-h2c
Section titled “cfgate.io/origin-h2c”Enables HTTP/2 cleartext (h2c) for the connection between cloudflared and the origin server. Use this for backends that speak HTTP/2 without TLS, such as Envoy sidecars or other h2c-speaking services.
Valid values: true, false, 1, 0, yes, no (case-insensitive)
Default: inherited from tunnel defaults (otherwise false)
Read by: CloudflareTunnel controller (via route collection), cloudflared-builder
Explicit false disables inherited h2c. When switching from a tunnel-wide HTTP/2 default, also set cfgate.io/origin-http2: "false"; both transports cannot be enabled together. Requires the inherent-design/cloudflared fork image (the default). Upstream cloudflared silently ignores this field. See Image.
The effective combination is checked against the referenced tunnel for each parent.
HTTPS with h2c and simultaneous HTTP/2 plus h2c are invalid. Such routes report
Accepted=False and retain matching HTTP 503 responses, allowing valid sibling
routes and backend revocations to publish. Invalid forwarding fallbacks also
become HTTP 503 responses. A stored Cloudflare configuration and a ready connector
Pod do not alone prove that an origin request succeeds.
HTTPRoute backends require a TCP Service port. UDP-only and SCTP-only ports report
ResolvedRefs=False with reason UnsupportedProtocol and retain matching HTTP
500 responses. An omitted Service protocol uses Kubernetes’ TCP default.
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: http2-backend namespace: default annotations: cfgate.io/origin-h2c: "true"spec: parentRefs: - name: cloudflare-tunnel namespace: cfgate-system hostnames: - h2c.example.com rules: - backendRefs: - name: http2-service port: 50051cfgate.io/ttl
Section titled “cfgate.io/ttl”Sets the DNS record TTL (Time To Live) in seconds. Value 1 is special and means “auto” (Cloudflare-managed TTL). Only relevant when CloudflareDNS discovers this route via gatewayRoutes.
Valid values: Integer from 1 to 86400
Default: inherits CloudflareDNS.spec.defaults.ttl (otherwise Auto)
Read by: CloudflareDNS controller (via route hostname collection). See CloudflareDNS for default TTL configuration.
metadata: annotations: cfgate.io/ttl: "300"cfgate.io/cloudflare-proxied
Section titled “cfgate.io/cloudflare-proxied”Controls whether Cloudflare proxies traffic for the DNS record (the “orange cloud” toggle). When true, traffic passes through Cloudflare’s network (DDoS protection, WAF, caching). When false, DNS resolves directly to the tunnel domain.
Valid values: true, false, 1, 0, yes, no (case-insensitive)
Default: true
Read by: CloudflareDNS controller (via route hostname collection). See CloudflareDNS for default proxy configuration.
metadata: annotations: cfgate.io/cloudflare-proxied: "false"cfgate.io/access-policy
Section titled “cfgate.io/access-policy”Deprecated. Resolves a CloudflareAccessPolicy reference for HTTPRoute status and warnings only. It does not create Cloudflare Access Applications and does not link policies. Use CloudflareAccessApplication to protect Gateway API targets.
Valid values: name (same namespace) or namespace/name
Default: Not set
Read by: HTTPRoute controller for deprecated status resolution only
metadata: annotations: cfgate.io/access-policy: "my-access-policy"Or cross-namespace:
metadata: annotations: cfgate.io/access-policy: "cfgate-system/shared-policy"cfgate.io/hostname
Section titled “cfgate.io/hostname”Sets or overrides the hostname for an HTTPRoute. When set, it overrides spec.hostnames.
Valid values: RFC 1123 hostname (max 253 characters, labels max 63 characters, lowercase alphanumeric and hyphens)
Default: Not set
Read by: HTTPRoute-driven reconciliation paths
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: my-app annotations: cfgate.io/hostname: "app.example.com"spec: parentRefs: - name: cloudflare-tunnel namespace: cfgate-system hostnames: - ignored.example.com rules: - backendRefs: - name: my-service port: 80Infrastructure Annotations
Section titled “Infrastructure Annotations”Applied to Gateway resources to connect them to CloudflareTunnel resources.
| Annotation | Values | Description |
|---|---|---|
cfgate.io/tunnel-ref | namespace/name or name | References the CloudflareTunnel resource this Gateway should use |
cfgate.io/tunnel-target | Tunnel domain (e.g., uuid.cfargotunnel.com) | Set by controller (read-only) |
cfgate.io/tunnel-ref
Section titled “cfgate.io/tunnel-ref”Connects a Gateway to a CloudflareTunnel resource. This annotation is the link between the Gateway API layer and cfgate’s tunnel management.
Format: namespace/name (recommended) or name (same namespace)
Read by: CloudflareTunnel controller (finds Gateways referencing this tunnel), CloudflareDNS controller (finds Gateways for route discovery), CloudflareAccessApplication controller (credential inheritance)
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: cloudflare-tunnel namespace: cfgate-system annotations: cfgate.io/tunnel-ref: cfgate-system/my-tunnelspec: gatewayClassName: cfgate listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: Allcfgate.io/tunnel-target
Section titled “cfgate.io/tunnel-target”The tunnel endpoint domain, set automatically by the CloudflareTunnel controller after tunnel creation. Format is {tunnelID}.cfargotunnel.com. Do not set this manually.
Read by: Gateway controller, DNS controllers
Lifecycle Annotations
Section titled “Lifecycle Annotations”Applied to CloudflareTunnel, CloudflareDNS, CloudflareAccessPolicy, and CloudflareAccessApplication resources to control deletion behavior.
| Annotation | Values | Default | Description |
|---|---|---|---|
cfgate.io/deletion-policy | orphan | Not set (full cleanup) | When set to orphan, skips Cloudflare-side cleanup on resource deletion |
cfgate.io/deletion-policy
Section titled “cfgate.io/deletion-policy”Controls what happens to Cloudflare-side resources when the Kubernetes resource is deleted.
Valid values: orphan
Default: Not set (the controller deletes the corresponding Cloudflare resource during finalization)
Supported on:
- CloudflareTunnel: When set to
orphan, the tunnel remains in Cloudflare but the K8s resource is removed. The controller skips tunnel deletion and proceeds directly to finalizer removal. - CloudflareDNS: When set to
orphan, the DNS records remain in Cloudflare but the K8s resource is removed. The controller skips record cleanup and proceeds directly to finalizer removal. - CloudflareAccessPolicy: When set to
orphan, the reusable Access policy and service tokens remain in Cloudflare. The controller skips cleanup and proceeds directly to finalizer removal. - CloudflareAccessApplication: When set to
orphan, Access Applications and the per-resource owner tag remain in Cloudflare. The controller skips application and tag cleanup and proceeds directly to finalizer removal.
Use cases:
- Migrating resources between clusters (delete from old cluster without destroying the Cloudflare resource)
- Debugging tunnel or access issues (remove K8s resource without affecting live traffic)
- Emergency finalizer unblocking (annotate a stuck resource, then delete it)
# Annotate before deletion to orphan the tunnelkubectl annotate cloudflaretunnel my-tunnel cfgate.io/deletion-policy=orphan
# Now delete: tunnel stays in Cloudflare, K8s resource removedkubectl delete cloudflaretunnel my-tunnel# Same for DNS resourceskubectl annotate cloudflarednses my-dns cfgate.io/deletion-policy=orphankubectl delete cloudflaredns my-dns# Same for access policieskubectl annotate cloudflareaccesspolicy my-policy cfgate.io/deletion-policy=orphankubectl delete cloudflareaccesspolicy my-policy# Same for access applicationskubectl annotate cloudflareaccessapplication my-app cfgate.io/deletion-policy=orphankubectl delete cloudflareaccessapplication my-appOrphaned Cloudflare resources remain your responsibility. Recreating a Kubernetes object with the same name creates a new UID and does not restore ownership. Follow the adoption and ownership-transfer procedure before resuming management, or delete the remote resources manually after verifying that no active owner uses them.
DNS Management Annotations
Section titled “DNS Management Annotations”Applied to CloudflareDNS resources to control DNS-specific behavior.
| Annotation | Values | Default | Description |
|---|---|---|---|
cfgate.io/allow-deep-subdomains | true | Not set (warning emitted) | Suppresses the DeepSubdomain warning event for multi-level subdomains |
cfgate.io/allow-deep-subdomains
Section titled “cfgate.io/allow-deep-subdomains”Suppresses the DeepSubdomain warning event that the controller emits when a hostname has more than one subdomain level relative to its zone. For example, api.staging.example.com in zone example.com has two subdomain levels and triggers the warning because Cloudflare Universal SSL certificates cover only single-level wildcards (*.example.com). Deeper subdomains require Cloudflare Advanced Certificate Manager or a custom certificate.
Valid values: "true" to suppress the warning; any other value or absent means the warning is emitted.
Default: Not set (warning emitted on each reconciliation)
Applied to: CloudflareDNS resources
Read by: CloudflareDNS controller (checked in syncRecords before emitting the DeepSubdomain event)
Set this annotation on the CloudflareDNS resource when you have appropriate TLS coverage for deep subdomains and want to suppress the recurring warning:
kubectl annotate cloudflarednses my-dns -n cfgate-system \ cfgate.io/allow-deep-subdomains=trueSee the Multi-level Subdomains section in the CloudflareDNS reference for details on subdomain depth validation.
Internal Annotations
Section titled “Internal Annotations”These annotations are managed by cfgate controllers and should not be set manually.
| Annotation | Applied To | Description |
|---|---|---|
cfgate.io/config-hash | CloudflareTunnel | SHA-256 hash of the last-synced tunnel configuration. Used to skip redundant Cloudflare API updates when the configuration has not changed. |
Notes on annotationFilter
Section titled “Notes on annotationFilter”The annotationFilter field on CloudflareDNS.spec.source.gatewayRoutes is not itself a cfgate annotation. It is a CRD spec field that accepts any user-chosen annotation key (or key=value pair) as a filter for route discovery.
When set, only HTTPRoutes bearing the specified annotation will be included in DNS sync. The annotation name and value are entirely user-defined.
Supported formats:
key=value: Only syncs routes where the annotation key exists AND the value matches exactlykey: Only syncs routes where the annotation key exists (any value)
Example: Using cfgate.io/dns-sync=enabled as a convention (but any annotation works):
apiVersion: cfgate.io/v1alpha1kind: CloudflareDNSmetadata: name: my-dns namespace: cfgate-systemspec: tunnelRef: name: my-tunnel zones: - name: example.com source: gatewayRoutes: enabled: true annotationFilter: "cfgate.io/dns-sync=enabled"Then only HTTPRoutes with the matching annotation are synced:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: synced-app annotations: cfgate.io/dns-sync: "enabled" # Matches filter, DNS record createdspec: parentRefs: - name: cloudflare-tunnel namespace: cfgate-system hostnames: - app.example.com rules: - backendRefs: - name: my-service port: 80Routes without the annotation are ignored by this CloudflareDNS resource, even if they reference the same Gateway and tunnel.