This plugin enables CoreDNS to use Consul's Key-Value store as a backend for DNS records.
It supports both forward and reverse DNS lookups, as well as wildcard entries.
Important
This plugin is still actively being worked on.
Expect possible changes or reworks of how this plugin functions and how the config is structured.
Additionally, this README isn't always up-to-date, so not everything mentioned here might work as described.
- Use Consul KV as a DNS record store
- Real-time configuration updates via Consul KV
- Support for forward and reverse DNS records
- Wildcard and root domain support
- Configurable TTL with default value
- Metrics for monitoring (compatible with Prometheus)
The CoreDNS ConsulKV Plugin follows a modular architecture to process DNS queries and load records from the key/value storage:
sequenceDiagram
participant User
participant CoreDNS
participant ConsulKV
participant Consul
participant NextPlugin
participant LockdownChecker
User->>CoreDNS: DNS Query
CoreDNS->>ConsulKV: Handle Query
alt Consul is reachable
ConsulKV->>Consul: Fetch DNS Record
Consul-->>ConsulKV: Return Record
alt Record found
ConsulKV-->>CoreDNS: DNS Response
CoreDNS-->>User: DNS Response
else Record not found
ConsulKV->>NextPlugin: Pass Query
NextPlugin-->>CoreDNS: DNS Response
CoreDNS-->>User: DNS Response
end
else Consul is unreachable (Lockdown mode)
ConsulKV->>NextPlugin: Bypass Query
NextPlugin-->>CoreDNS: DNS Response
CoreDNS-->>User: DNS Response
Note over ConsulKV,LockdownChecker: Start Lockdown Checker if not running
loop Every X seconds
LockdownChecker->>Consul: Check Connection
alt Consul is back online
Consul-->>LockdownChecker: Connection Successful
LockdownChecker->>ConsulKV: Exit Lockdown Mode
end
end
end
To use this plugin, you need to compile it into CoreDNS. Add the following line to the plugin.cfg
file in your CoreDNS source code:
consulkv:github.com/mwantia/coredns-consulkv-plugin
Then, rebuild CoreDNS with:
go get github.com/mwantia/coredns-consulkv-plugin
go generate
go build
Add the plugin to your CoreDNS configuration file (Corefile):
consulkv [ENV FILES...] {
address http://127.0.0.1:8500
token anonymous
kv_prefix dns
disable_watch
}
address
: Consul HTTP address (default:http://127.0.0.1:8500
)token
: Consul ACL token (optional)kv_prefix
: Consul KV key for plugin configuration (default:dns
)disable_watch
: If set, Consul KV will not watch for any updated fordns/config
Load with all default values.
consulkv
Load .env
in current directory to use for configuration.
consulkv .env
Use the available config to define the connection to Consul.
consulkv {
address http://127.0.0.1:8500
token anonymous
}
The plugin configuration is stored in Consul KV at the specified <kv_prefix>/config
.
The configuration must be a JSON object with the following structure:
{
"flattening": "local",
"zones": [
"example.com",
"0.168.192.in-addr.arpa"
],
"consul_cache": {
"use_cache": true,
"max_age": 60,
"consistent": false,
"allowstale": true
}
}
zones
: DNS zone to be handled by this plugin (can be specified multiple times)flattening
: CNAME flattening mode (optional, default:local
)none
: No CNAME flattening, returns CNAME record immediatelylocal
: Flatten CNAMEs only for records managed by this pluginfull
: Flatten all CNAMEs, including external ones (usesplugin.NextOrFailure
for external resolution)
consul_cache
: Defines the internal cache used by the Consul clientuse_cache
: Requests that the Consul agent cache results locallymax_age
: Limits how old a cached value will be returned ifuse_cache
is trueconsistent
: Forces the read to be fully consistent; More expensive but prevents ever performing a stale readallowstale
: Allows any Consul server (non-leader) to service a read; Allows for lower latency and higher throughput
The plugin watches for changes to the configuration in Consul KV and applies updates in real-time without requiring a CoreDNS restart. \
Just creating a zone prefix in Consul KV is not enough.
This plugin requires that all zones that should be handled to be defined under zones
.
DNS records are stored in Consul's KV store with the following structure:
<kv_prefix>/zones/<zone>/<record>
For example:
dns/example.com/www
dns/0.168.192.in-addr.arpa/1
The value for each key must be a JSON object with the following structure:
{
"ttl": 3600,
"records": [
{
"type": "<query-type>",
"value": "<see-below-for-examples>"
}
]
}
- Zone apex (root domain): Use
@
as the record name. - Wildcard: Use
*
as the record name.
-
SOA root record with NS for example.com
Key:
dns/zones/example.com/@
{ "ttl": 3600, "records": [ { "type": "SOA", "value": { "mname": "ns.example.com", "rname": "hostmaster.example.com", "serial": 2024081001, "refresh": 7200, "retry": 3600, "expire": 1209600, "minimum": 3600 }, { "type": "NS", "value": ["ns.example.com"] } } ] }
-
A record for ns.example.com:
Key:
dns/zones/example.com/ns
Value:{ "ttl": 3600, "records": [ { "type": "A", "value": ["192.168.0.5"] } ] }
-
PTR record for reverse DNS:
Key:
dns/zones/0.168.192.in-addr.arpa/5
Value:{ "ttl": 3600, "records": [ { "type": "PTR", "value": ["ns.example.com"] } ] }
-
Wildcard record for
*.example.com
with additional TXT:Key:
dns/zones/example.com/*
Value:{ "ttl": 3600, "records": [ { "type": "A", "value": ["192.168.0.100"] }, { "type": "TXT", "value": ["Additional information displayed as TXT"] } ] }
-
SRV record for a service:
Key:
dns/zones/example.com/_sip._tcp
Value:{ "ttl": 3600, "records": [ { "type": "SRV", "value": [ { "target": "sip.example.com", "port": 5060, "priority": 10, "weight": 100 } ] } ] }
-
CNAME record for test.example.com:
Key:
dns/zones/example.com/www
Value:{ "ttl": 3600, "records": [ { "type": "CNAME", "value": "example.com" } ] }
-
HTTPS for service.example.com with additional A records:
Key:
dns/zones/example.com/service
Value:{ "ttl": 3600, "records": [ { "type": "A", "value": ["192.168.0.10", "192.168.0.11"] }, { "type": "HTTPS", "value": [ { "priority": 1, "target": "docker1.example.com", "params": { "alpn": "h2,http/1.1", "port": "443", "ipv4hint": "192.168.0.10" } }, { "priority": 1, "target": "docker2.example.com", "params": { "alpn": "h2,http/1.1", "port": "443", "ipv4hint": "192.168.0.11" } } ] } ] }
This plugin exposes the following metrics for Prometheus:
coredns_consulkv_plugin_errors_total{error}
:- Count the amount of errors within the plugin
The list of possible errors are:CONSUL_GET
: Occures when ConsulKV was unable to connect to ConsulSOA_GET
: Occures when ConsulKV was unable to load any SOA entries from Consul or as defaultWRITE_MSG
: Occures when ConsulKV was unable to write the response to CoreDNS due to an internal panicJSON_UNMARSHAL
: Occures when ConsulKV was unable to unmarshal the received json value from Consul
- Count the amount of errors within the plugin
coredns_consulkv_consul_config_updated_total{error}
:- Count the amount of times the config was updated from the Consul key/value
The list of possible errors are:NOERROR
: Occures when ConsulKV was successfully able to receive data from ConsulERROR
: Occures when ConsulKV was unable to connect to Consul, or the data was invalid
- Count the amount of times the config was updated from the Consul key/value
coredns_consulkv_consul_request_duration_seconds{status, le}
- Histogram of the time (in seconds) each request to Consul took
The list of possible statuses are:NOERROR
: Occures when ConsulKV was successfully able to receive data from ConsulNODATA
: Occures when ConsulKV was able to receive a response from Consul but no record existsERROR
: Occures when ConsulKV was unable to connect to Consul
- Histogram of the time (in seconds) each request to Consul took
coredns_consulkv_query_requests_total{zone, type}
- Count the amount of queries received as request by the plugin
The labelzone
defines the zonename requested in this query (Example:example.com.
)
The labeltype
defines the query type that was requested (Example:A
,CNAME
)
- Count the amount of queries received as request by the plugin
coredns_consulkv_query_responses_successful_total{zone, type}
- Count the amount of successful queries handled and responded to by the plugin
The labelzone
defines the zonename requested in this query (Example:example.com.
)
The labeltype
defines the query type that was requested (Example:A
,CNAME
)
- Count the amount of successful queries handled and responded to by the plugin
coredns_consulkv_query_responses_failed_total{zone, type, error}
- Count the amount of failed queries handled by the plugin
The labelzone
defines the zonename requested in this query (Example:example.com.
)
The labeltype
defines the query type that was requested (Example:A
,CNAME
)
The list of possible errors are:ERROR
: Occures when ConsulKV wasn't able to complete the request due to internal errorsNODATA
: Occures when ConsulKV was unable to find a record matching the requestNXDOMAIn
: Occures when ConsulKV was unable to find a record and was unable to return any form of data, likeSOA
- Count the amount of failed queries handled by the plugin
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.