Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions features.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
| ShortCertRotation| | | | | | | | |
| ClusterAPIComputeInstall| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
| ClusterAPIControlPlaneInstall| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
| DNSTemplatePlugin| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
| Example2| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
| ExternalSnapshotMetadata| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
| KMSEncryptionProvider| | | <span style="background-color: #519450">Enabled</span> | <span style="background-color: #519450">Enabled</span> | | | | |
Expand Down
8 changes: 8 additions & 0 deletions features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ var (
enable(inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()).
mustRegister()

FeatureGateDNSTemplatePlugin = newFeatureGate("DNSTemplatePlugin").
reportProblemsToJiraComponent("dns").
contactPerson("grzpiotrowski").
productScope(ocpSpecific).
enhancementPR("https://github.com/openshift/enhancements/pull/1936").
enable(inDevPreviewNoUpgrade()).
mustRegister()

FeatureGateMachineConfigNodes = newFeatureGate("MachineConfigNodes").
reportProblemsToJiraComponent("MachineConfigOperator").
contactPerson("ijanssen").
Expand Down
125 changes: 124 additions & 1 deletion openapi/generated_openapi/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

121 changes: 121 additions & 0 deletions operator/v1/types_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ type DNSSpec struct {
// 30 seconds or as noted in the respective Corefile for your version of OpenShift.
// +optional
Cache DNSCache `json:"cache,omitempty"`

// template is an optional configuration for custom DNS query handling via the CoreDNS template plugin.
// The template defines how to handle queries matching specific zones and query types.
//
// The template is injected into ALL Corefile server blocks (both custom servers from spec.servers
// and the default .:5353 block). This ensures consistent behavior across all DNS resolution paths.
//
// AAAA filtering is intended for IPv4-only clusters. In IPv6 or dual-stack clusters, use specific
// zones instead of "." to avoid filtering internal IPv6 service addresses (e.g., cluster.local).
//
// When this field is not set, no template plugin configuration is added to CoreDNS.
//
// +optional
// +openshift:enable:FeatureGate=DNSTemplatePlugin
Template *Template `json:"template,omitempty"`
}

// DNSCache defines the fields for configuring DNS caching.
Expand Down Expand Up @@ -467,6 +482,112 @@ const (
DNSAvailable = "Available"
)

// QueryType represents DNS query types supported by templates.
// +kubebuilder:validation:Enum=AAAA
type QueryType string

const (
// QueryTypeAAAA represents IPv6 address records (AAAA).
QueryTypeAAAA QueryType = "AAAA"
)

// QueryClass represents DNS query classes supported by templates.
// Valid value is "IN".
// +kubebuilder:validation:Enum=IN
type QueryClass string

const (
// QueryClassIN represents the Internet class.
QueryClassIN QueryClass = "IN"
)

// ResponseCode represents DNS response codes.
// +kubebuilder:validation:Enum=NOERROR
type ResponseCode string

const (
// ResponseCodeNOERROR indicates a successful DNS query with or without answer records.
// When used with returnEmpty action, this returns an empty response (no AAAA records)
// without indicating an error, which is the standard behavior for AAAA filtering.
ResponseCodeNOERROR ResponseCode = "NOERROR"
)

// Template defines a template for custom DNS query handling via the CoreDNS template plugin.
// Templates enable filtering or custom responses for DNS queries matching specific zones and query types.
// +openshift:enable:FeatureGate=DNSTemplatePlugin
type Template struct {
// zones specifies the DNS zones this template applies to.
// Each zone must be a valid DNS name as defined in RFC 1123.
// The special zone "." matches all domains (catch-all).
// Multiple zones can be specified to apply the same template actions to multiple domains.
//
// Examples:
// - ["."] matches all domains (catch-all for global AAAA filtering)
// - ["example.com"] matches only example.com and its subdomains
// - ["example.com", "test.com"] matches both domains and their subdomains
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
// +required
Zones []string `json:"zones"`

Comment on lines +519 to +533
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add schema validation for zones item format.

The comments require RFC1123-compatible zones (plus "."), but the schema currently only enforces presence/count. That allows malformed zones to be persisted and fail downstream.

Suggested CRD validation guard
 type Template struct {
 	// zones specifies the DNS zones this template applies to.
 	// Each zone must be a valid DNS name as defined in RFC 1123.
 	// The special zone "." matches all domains (catch-all).
 	// At least one zone must be specified.
+	// +kubebuilder:validation:items:Pattern=`^(\.|([a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.([a-z0-9]([-a-z0-9]*[a-z0-9])?))*)$`
 	// +kubebuilder:validation:Required
 	// +kubebuilder:validation:MinItems=1
 	Zones []string `json:"zones"`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// zones specifies the DNS zones this template applies to.
// Each zone must be a valid DNS name as defined in RFC 1123.
// The special zone "." matches all domains (catch-all).
// At least one zone must be specified.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
Zones []string `json:"zones"`
// zones specifies the DNS zones this template applies to.
// Each zone must be a valid DNS name as defined in RFC 1123.
// The special zone "." matches all domains (catch-all).
// At least one zone must be specified.
// +kubebuilder:validation:items:Pattern=`^(\.|([a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.([a-z0-9]([-a-z0-9]*[a-z0-9])?))*)$`
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
Zones []string `json:"zones"`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@operator/v1/types_dns.go` around lines 528 - 535, The Zones slice lacks
per-item format validation; update the Zones field in operator/v1/types_dns.go
to add a kubebuilder validation Pattern that enforces RFC1123 DNS names or the
literal ".". Specifically, add a comment like //
+kubebuilder:validation:Pattern="^(\\.|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)$"
immediately above the Zones []string `json:"zones"` declaration so each entry is
validated as either "." or an RFC1123-compliant name. Ensure the annotation is
placed alongside the existing Required/MinItems tags.

// queryType specifies the DNS query type to match.
//
// +kubebuilder:validation:Required
// +kubebuilder:default=AAAA
// +required
QueryType QueryType `json:"queryType"`

// queryClass specifies the DNS query class to match.
//
// +kubebuilder:validation:Required
// +kubebuilder:default=IN
// +required
QueryClass QueryClass `json:"queryClass"`

// actions defines a list of actions to apply to matching queries.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
// +required
Actions []TemplateAction `json:"actions"`
}

// TemplateAction defines the action taken by the template for matching queries.
// This is a discriminated union - exactly one action type must be specified.
//
// +union
// +kubebuilder:validation:XValidation:rule="has(self.returnEmpty)",message="only returnEmpty action is supported"
type TemplateAction struct {
// returnEmpty returns an empty DNS response with the specified response code.
// This is useful for filtering queries (e.g., AAAA filtering in IPv4-only clusters).
//
// When set, the template returns a response with no answer records. For AAAA filtering,
// this means IPv6 address queries return successfully but with no IPv6 addresses,
// causing clients to fall back to IPv4 (A record) queries.
//
// +optional
// +unionDiscriminator
ReturnEmpty *ReturnEmptyAction `json:"returnEmpty,omitempty"`
}

// ReturnEmptyAction configures the template to return empty DNS responses.
// This is used for query filtering, such as AAAA filtering in IPv4-only clusters.
type ReturnEmptyAction struct {
// rcode is the DNS response code to return in the empty response.
// Valid values are "NOERROR".
//
// NOERROR indicates a successful query with no answer records. This is the standard
// response for AAAA filtering - the query succeeds but returns no IPv6 addresses,
// causing clients to fall back to A record (IPv4) queries.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:Enum=NOERROR
// +kubebuilder:default=NOERROR
// +required
Rcode ResponseCode `json:"rcode"`
}

// DNSStatus defines the observed status of the DNS.
type DNSStatus struct {
// clusterIP is the service IP through which this DNS is made available.
Expand Down
Loading