Add dns node lookup support in partitions

This commit is contained in:
Kyle Havlovitz 2022-06-10 11:23:51 -07:00
parent dcf96d9563
commit cfc90ea2d5
2 changed files with 41 additions and 11 deletions

View File

@ -107,6 +107,14 @@ type serviceLookup struct {
acl.EnterpriseMeta acl.EnterpriseMeta
} }
type nodeLookup struct {
Datacenter string
Node string
Tag string
MaxRecursionLevel int
acl.EnterpriseMeta
}
// DNSServer is used to wrap an Agent and expose various // DNSServer is used to wrap an Agent and expose various
// service discovery endpoints using a DNS interface. // service discovery endpoints using a DNS interface.
type DNSServer struct { type DNSServer struct {
@ -846,13 +854,27 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi
return invalid() return invalid()
} }
if !d.parseDatacenter(querySuffixes, &datacenter) { if !d.parseDatacenterAndEnterpriseMeta(querySuffixes, cfg, &datacenter, &entMeta) {
return invalid()
}
// Namespace should not be set for node queries
ns := entMeta.NamespaceOrEmpty()
if ns != "" && ns != acl.DefaultNamespaceName {
return invalid() return invalid()
} }
// Allow a "." in the node name, just join all the parts // Allow a "." in the node name, just join all the parts
node := strings.Join(queryParts, ".") node := strings.Join(queryParts, ".")
return d.nodeLookup(cfg, datacenter, node, req, resp, maxRecursionLevel)
lookup := nodeLookup{
Datacenter: datacenter,
Node: node,
MaxRecursionLevel: maxRecursionLevel,
EnterpriseMeta: entMeta,
}
return d.nodeLookup(cfg, lookup, req, resp)
case "query": case "query":
// ensure we have a query name // ensure we have a query name
@ -959,7 +981,7 @@ func rCodeFromError(err error) int {
} }
// nodeLookup is used to handle a node query // nodeLookup is used to handle a node query
func (d *DNSServer) nodeLookup(cfg *dnsConfig, datacenter, node string, req, resp *dns.Msg, maxRecursionLevel int) error { func (d *DNSServer) nodeLookup(cfg *dnsConfig, lookup nodeLookup, req, resp *dns.Msg) error {
// Only handle ANY, A, AAAA, and TXT type requests // Only handle ANY, A, AAAA, and TXT type requests
qType := req.Question[0].Qtype qType := req.Question[0].Qtype
if qType != dns.TypeANY && qType != dns.TypeA && qType != dns.TypeAAAA && qType != dns.TypeTXT { if qType != dns.TypeANY && qType != dns.TypeA && qType != dns.TypeAAAA && qType != dns.TypeTXT {
@ -968,12 +990,13 @@ func (d *DNSServer) nodeLookup(cfg *dnsConfig, datacenter, node string, req, res
// Make an RPC request // Make an RPC request
args := &structs.NodeSpecificRequest{ args := &structs.NodeSpecificRequest{
Datacenter: datacenter, Datacenter: lookup.Datacenter,
Node: node, Node: lookup.Node,
QueryOptions: structs.QueryOptions{ QueryOptions: structs.QueryOptions{
Token: d.agent.tokens.UserToken(), Token: d.agent.tokens.UserToken(),
AllowStale: cfg.AllowStale, AllowStale: cfg.AllowStale,
}, },
EnterpriseMeta: lookup.EnterpriseMeta,
} }
out, err := d.lookupNode(cfg, args) out, err := d.lookupNode(cfg, args)
if err != nil { if err != nil {
@ -996,7 +1019,7 @@ func (d *DNSServer) nodeLookup(cfg *dnsConfig, datacenter, node string, req, res
q := req.Question[0] q := req.Question[0]
// Only compute A and CNAME record if query is not TXT type // Only compute A and CNAME record if query is not TXT type
if qType != dns.TypeTXT { if qType != dns.TypeTXT {
records := d.makeRecordFromNode(n, q.Qtype, q.Name, cfg.NodeTTL, maxRecursionLevel) records := d.makeRecordFromNode(n, q.Qtype, q.Name, cfg.NodeTTL, lookup.MaxRecursionLevel)
resp.Answer = append(resp.Answer, records...) resp.Answer = append(resp.Answer, records...)
} }

View File

@ -467,9 +467,9 @@ using the [`advertise-wan`](/docs/agent/config/cli-flags#_advertise-wan) and
[`translate_wan_addrs`](/docs/agent/config/config-files#translate_wan_addrs) configuration [`translate_wan_addrs`](/docs/agent/config/config-files#translate_wan_addrs) configuration
options. options.
## Namespaced/Partitioned Services <EnterpriseAlert inline /> ## Namespaced/Partitioned Services and Nodes <EnterpriseAlert inline />
Consul Enterprise supports resolving namespaced and partitioned services via DNS. Consul Enterprise supports resolving namespaced and partitioned services and nodes via DNS.
To maintain backwards compatibility existing queries can be used and these will To maintain backwards compatibility existing queries can be used and these will
resolve services within the `default` namespace and partition. However, for resolving resolve services within the `default` namespace and partition. However, for resolving
services from other namespaces or partitions the following form can be used: services from other namespaces or partitions the following form can be used:
@ -478,13 +478,20 @@ services from other namespaces or partitions the following form can be used:
[tag.]<service>.service.<namespace>.ns.<partition>.ap.<datacenter>.dc.<domain> [tag.]<service>.service.<namespace>.ns.<partition>.ap.<datacenter>.dc.<domain>
``` ```
This is the canonical name of a Consul Enterprise service. Currently all parts must be This is the canonical name of a Consul Enterprise service. Currently at least 2 of
present - in a future version (once the `[namespace, partition, datacenter]` must be present - in a future version (once the
[`prefer_namespace` configuration](/docs/agent/config/config-files#dns_prefer_namespace) has been [`prefer_namespace` configuration](/docs/agent/config/config-files#dns_prefer_namespace) has been
deprecated), the namespace, partition and datacenter components will become optional deprecated), the namespace, partition and datacenter components will all become optional
and may be individually omitted to default to the `default` namespace, local partition and may be individually omitted to default to the `default` namespace, local partition
or local datacenter respectively. or local datacenter respectively.
For node lookups, only the partition and datacenter need to be specified (nodes cannot be
namespaced):
```text
[tag.]<service>.service.<partition>.ap.<datacenter>.dc.<domain>
```
## DNS with ACLs ## DNS with ACLs
In order to use the DNS interface when In order to use the DNS interface when