Skip to content
Merged
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 assets/components/openshift-dns/dns/configmap.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
apiVersion: v1
data:
Corefile: |
{{- .C2CCDNSBlocks }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it possible to mask out the next server block by setting up a special domain?
Say you configure cluster.local as domain. That would render

cluster.local:5353 {
...
}
.:5353 {
...
}

Which is more specific than the catch all, and would route all the cluster.local requests to remote cluster.
This is a bit of a stretch because no real use case configures a remote cluster with the same domain than the local one, but should we validate it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

True, good catch

.:5353 {
bufsize 1232
errors
Expand Down
21 changes: 21 additions & 0 deletions cmd/generate-config/config/config-openapi-spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,28 @@
},
"clusterToCluster": {
"type": "object",
"required": [
"dns"
],
"properties": {
"dns": {
"description": "DNS cache settings for CoreDNS server blocks generated for remote clusters.",
"type": "object",
"properties": {
"cacheNegativeTTL": {
"description": "Maximum TTL (seconds) for denial (NXDOMAIN/NODATA) DNS cache entries in CoreDNS\nserver blocks generated for remote clusters. Must be \u003e= 0. Setting to 0 disables denial caching.",
"type": "integer",
"default": 10,
"minimum": 0
},
"cacheTTL": {
"description": "Maximum TTL (seconds) for positive DNS cache entries in CoreDNS server blocks\ngenerated for remote clusters. Must be \u003e= 0. Setting to 0 disables positive caching.",
"type": "integer",
"default": 10,
"minimum": 0
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
},
"remoteClusters": {
"description": "List of remote clusters to establish connectivity with.\nC2CC is disabled when this list is empty.",
"type": "array",
Expand Down
6 changes: 6 additions & 0 deletions docs/user/howto_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ apiServer:
cipherSuites: []
minVersion: ""
clusterToCluster:
dns:
cacheNegativeTTL: 0
cacheTTL: 0
remoteClusters:
- clusterNetwork: []
domain: ""
Expand Down Expand Up @@ -190,6 +193,9 @@ apiServer:
cipherSuites: []
minVersion: VersionTLS12
clusterToCluster:
dns:
cacheNegativeTTL: 10
cacheTTL: 10
remoteClusters:
- clusterNetwork: []
domain: ""
Expand Down
8 changes: 8 additions & 0 deletions packaging/microshift/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ apiServer:
# Defaults to VersionTLS12.
minVersion: VersionTLS12
clusterToCluster:
# DNS cache settings for CoreDNS server blocks generated for remote clusters.
dns:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd add these 2 TTL values are set to 10 seconds by default (when not defined). Should it be also add it in cmd/generate-config/config/config-openapi-spec.json ?

# Maximum TTL (seconds) for denial (NXDOMAIN/NODATA) DNS cache entries in CoreDNS
# server blocks generated for remote clusters. Must be >= 0. Setting to 0 disables denial caching.
cacheNegativeTTL: 10
# Maximum TTL (seconds) for positive DNS cache entries in CoreDNS server blocks
# generated for remote clusters. Must be >= 0. Setting to 0 disables positive caching.
cacheTTL: 10
# List of remote clusters to establish connectivity with.
# C2CC is disabled when this list is empty.
remoteClusters:
Expand Down
8 changes: 6 additions & 2 deletions pkg/components/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,12 @@ func startDNSController(ctx context.Context, cfg *config.Config, kubeconfigPath

hostsEnabled := cfg.DNS.Hosts.Status == config.HostsStatusEnabled
extraParams := assets.RenderParams{
"ClusterIP": cfg.Network.DNS,
"HostsEnabled": hostsEnabled,
"ClusterIP": cfg.Network.DNS,
"HostsEnabled": hostsEnabled,
"C2CCDNSBlocks": "",
}
if cfg.C2CC.IsEnabled() {
extraParams["C2CCDNSBlocks"] = config.RenderC2CCDNSBlocks(cfg.C2CC.Resolved, *cfg.C2CC.DNS.CacheTTL, *cfg.C2CC.DNS.CacheNegativeTTL)
}

if err := assets.ApplyServices(ctx, svc, renderTemplate, renderParamsFromConfig(cfg, extraParams), kubeconfigPath); err != nil {
Expand Down
65 changes: 65 additions & 0 deletions pkg/config/c2cc.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,22 @@ import (
netutils "k8s.io/utils/net"
)

type C2CCDNS struct {
// Maximum TTL (seconds) for positive DNS cache entries in CoreDNS server blocks
// generated for remote clusters. Must be >= 0. Setting to 0 disables positive caching.
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=10
CacheTTL *int `json:"cacheTTL,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do you think it's necessary to add a check and an error log message if the user set a non integer as a TTL value. Or is it enough with the type enforced in this struct?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think that might be too defensive: I think the parser will throw an error

// Maximum TTL (seconds) for denial (NXDOMAIN/NODATA) DNS cache entries in CoreDNS
// server blocks generated for remote clusters. Must be >= 0. Setting to 0 disables denial caching.
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=10
CacheNegativeTTL *int `json:"cacheNegativeTTL,omitempty"`
}

type C2CC struct {
// DNS cache settings for CoreDNS server blocks generated for remote clusters.
DNS C2CCDNS `json:"dns"`
// List of remote clusters to establish connectivity with.
// C2CC is disabled when this list is empty.
RemoteClusters []RemoteCluster `json:"remoteClusters,omitempty"`
Expand Down Expand Up @@ -39,6 +54,7 @@ type ResolvedRemoteCluster struct {
ClusterNetwork []*net.IPNet
ServiceNetwork []*net.IPNet
Domain string
DNSIP string // 10th IP of ServiceNetwork[0], computed during validation when Domain is set
}

func (rc *ResolvedRemoteCluster) AllCIDRs() []*net.IPNet {
Expand Down Expand Up @@ -164,6 +180,13 @@ func (c *C2CC) validate(cfg *Config) error {
return fmt.Errorf("cluster to cluster requires OVN-Kubernetes CNI (network.cniPlugin must be \"\" or \"ovnk\", got %q)", cfg.Network.CNIPlugin)
}

if c.DNS.CacheTTL != nil && *c.DNS.CacheTTL < 0 {
return fmt.Errorf("dns.cacheTTL must be >= 0, got %d", *c.DNS.CacheTTL)
}
if c.DNS.CacheNegativeTTL != nil && *c.DNS.CacheNegativeTTL < 0 {
return fmt.Errorf("dns.cacheNegativeTTL must be >= 0, got %d", *c.DNS.CacheNegativeTTL)
}

resolved, parseErrs := c.parseRemoteClusters()
if len(parseErrs) > 0 {
return errors.Join(parseErrs...)
Expand Down Expand Up @@ -259,13 +282,25 @@ func validateRemoteCluster(
if domainErrs := validation.IsDNS1123Subdomain(rc.Domain); len(domainErrs) > 0 {
errs = append(errs, fmt.Errorf("%s.domain %q is not a valid DNS name: %s", label, rc.Domain, strings.Join(domainErrs, ", ")))
}
if rc.Domain == "cluster.local" {
errs = append(errs, fmt.Errorf("%s.domain cannot be cluster.local", label))
}
if prev, ok := seenRemoteDomains[rc.Domain]; ok {
errs = append(errs, fmt.Errorf("%s.domain %q duplicates remoteClusters[%d]", label, rc.Domain, prev))
} else {
seenRemoteDomains[rc.Domain] = i
}
}

if rc.Domain != "" && len(rc.ServiceNetwork) > 0 {
dnsIP, err := getClusterDNS(rc.ServiceNetwork[0])
if err != nil {
errs = append(errs, fmt.Errorf("%s: failed to compute DNS IP from serviceNetwork[0] %q: %w", label, rc.ServiceNetwork[0], err))
} else {
res.DNSIP = dnsIP
}
}

errs = append(errs, validateIPFamilyConsistencyNets(res.ClusterNetwork, label+".clusterNetwork")...)
errs = append(errs, validateIPFamilyConsistencyNets(res.ServiceNetwork, label+".serviceNetwork")...)
errs = append(errs, validateNetworkShapeNets(res.ClusterNetwork, res.ServiceNetwork, label)...)
Expand Down Expand Up @@ -345,3 +380,33 @@ func checkCIDRConflicts(cidr *net.IPNet, cidrStr, label string, seenCIDRs []labe
func cidrsOverlap(a, b *net.IPNet) bool {
return a.Contains(b.IP) || b.Contains(a.IP)
}

// RenderC2CCDNSBlocks generates CoreDNS server blocks for cross-cluster DNS.
func RenderC2CCDNSBlocks(resolved []ResolvedRemoteCluster, cacheTTL, cacheNegativeTTL int) string {
var blocks []string
for _, rc := range resolved {
if rc.Domain == "" {
continue
}
blocks = append(blocks, formatDNSBlock(rc.Domain, rc.DNSIP, cacheTTL, cacheNegativeTTL))
}
if len(blocks) == 0 {
return ""
}
return "\n" + strings.Join(blocks, "\n")
}

func formatDNSBlock(domain, dnsIP string, cacheTTL, cacheNegativeTTL int) string {
return fmt.Sprintf(` %s:5353 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we make this a constant at the top of the file?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's only used in single place so I'd rather not move it to a place almost 400 lines away.

bufsize 1232
errors
log . {
class error
}
rewrite stop name suffix .%s .cluster.local answer auto
forward . %s
cache %d {
denial 9984 %d
}
}`, domain, domain, dnsIP, cacheTTL, cacheNegativeTTL)
}
Loading