-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Documentation gap: Provider-specific annotations placement for Gateway API sources
Issue Summary
The annotations documentation states that the "Gateway" source supports provider-specific annotations, but it doesn't clarify which resource (Gateway vs HTTPRoute/other Routes) these annotations should be placed on.
Current Behavior
According to the source code (source/gateway.go), annotations are handled as follows:
Gateway resource annotations:
- ✅
external-dns.alpha.kubernetes.io/target- read from Gateway (line ~380)
HTTPRoute (and other Route) resource annotations:
- ✅
external-dns.alpha.kubernetes.io/hostname- read from Route - ✅
external-dns.alpha.kubernetes.io/ttl- read from Route - ✅ Provider-specific annotations (e.g.,
cloudflare-proxied,aws/*, etc.) - read from Route (line ~244)
This means:
// In Endpoints() function:
annots := meta.Annotations // <- HTTPRoute annotations
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(annots)While targets come from Gateway:
// In resolve() function:
override := annotations.TargetsFromTargetAnnotation(gw.gateway.Annotations)Example That Doesn't Work
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
namespace: kube-system
annotations:
external-dns.alpha.kubernetes.io/target: "198.51.100.1" # ✅ Works
external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" # ❌ Ignored
spec:
gatewayClassName: cilium
listeners:
- name: https-example
hostname: "example.com"
protocol: HTTPS
port: 443
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example
annotations: {} # Provider-specific annotations needed here!
spec:
parentRefs:
- name: cilium-gateway
namespace: kube-system
hostnames:
- example.com
rules:
- backendRefs:
- name: example-service
port: 80Correct Configuration
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
namespace: kube-system
annotations:
external-dns.alpha.kubernetes.io/target: "198.51.100.1" # ✅ On Gateway
spec:
gatewayClassName: cilium
listeners:
- name: https-example
hostname: "example.com"
protocol: HTTPS
port: 443
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example
annotations:
external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" # ✅ On HTTPRoute
spec:
parentRefs:
- name: cilium-gateway
namespace: kube-system
hostnames:
- example.com
rules:
- backendRefs:
- name: example-service
port: 80Related Issues
- Question: Gatway-api target on HTTPRoute #4056 - mentions that
targetannotation "must be on the Gateway, so it won't work on HTTPRoute" but doesn't clarify other annotations - Annotations table uses "Gateway" as source name, which is ambiguous (refers to gateway-api sources, not the Gateway resource itself)
Proposed Solutions
Option 1: Improve Documentation (Quick Fix)
Update the documentation to explicitly state annotation placement:
In docs/annotations/annotations.md:
Add a new section or table explaining:
| Annotation Type | Gateway Resource | HTTPRoute Resource | GRPCRoute/TLSRoute/etc |
|---|---|---|---|
target |
✅ Read from Gateway | ❌ Ignored | ❌ Ignored |
hostname |
❌ Not used | ✅ Read from Route | ✅ Read from Route |
ttl |
❌ Not used | ✅ Read from Route | ✅ Read from Route |
Provider-specific (cloudflare-proxied, aws/*, etc.) |
❌ Not used | ✅ Read from Route | ✅ Read from Route |
In docs/sources/gateway-api.md:
Add examples showing correct annotation placement for different scenarios.
Option 2: Support Annotations on Both Resources (Feature Enhancement)
Implement annotation merging logic where:
- Gateway annotations apply to all Routes using that Gateway (defaults)
- Route annotations override Gateway annotations for specific Routes
- This would match user expectations and provide better DX
Example code change in source/gateway.go:
// Merge Gateway and Route annotations
gwAnnots := gw.gateway.Annotations
rtAnnots := meta.Annotations
mergedAnnots := mergeAnnotations(gwAnnots, rtAnnots) // Route overrides Gateway
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(mergedAnnots)This would enable use cases like:
- Setting
cloudflare-proxied: trueon Gateway (applies to all routes) - Overriding with
cloudflare-proxied: falseon specific HTTPRoute
Questions for Maintainers
- Is the current behavior (provider-specific annotations only on Routes) intentional design or unintended limitation?
- If intentional: Can we improve documentation to make this clear?
- If limitation: Would you accept a PR implementing Option 2 (annotation merging)?
Environment
- External-DNS version: v0.19.0
- DNS provider: Cloudflare
- Source:
gateway-httproute - Kubernetes Gateway API: v1
Additional Context
This behavior is architecturally logical from Gateway API perspective:
- Gateway = infrastructure layer (IP addresses, listeners)
- Routes = application layer (DNS records, routing rules)
However, it's not intuitive for users and causes confusion when annotations work on Gateway for some fields (target) but not others (provider-specific).