-
Notifications
You must be signed in to change notification settings - Fork 917
Lua Examples (Authoritative)
For LUA record examples, please see Lua Examples (Authoritative LUA records)
Please consult the authoritative documentation at
- https://doc.powerdns.com/authoritative/lua-records/index.html
- https://doc.powerdns.com/authoritative/dnsupdate.html#update-policy
- https://doc.powerdns.com/authoritative/lua-records/reference/index.html
before deploying any of those Lua Scripts and be warned that you can break your nameserver service if not properly implemented.
Always test your Lua script before deploying it to your live authoritative servers.
Feel free to add your own Snipplets - this is a wiki! ;)
What is achieved with this script? It strictly limits RFC2136 dynamic updates to a single record based on TSIG key authentication. The idea is to use a unique TSIG key name as identifier to allow updating only the record with the same name as the key, and in a specific zone. Specific use case is to secure the Let's Encrypt DNS-01 challenge if you do not trust your individual hosts so much to hand them over full control over a zone but only want to allow them updating a specific TXT record.
Inspired by https://github.com/joohoi/acme-dns, this approach uses pdns' RFC2136 capabilities and its Lua Update Policy functionality via lua-dnsupdate-policy-script
configuration parameter. Network source ranges for dynamic updates can be defined to further tighten security.
Similar to acme-dns, this approach relies on _acme-challenge
records (in multiple zones, even on different authoritative name servers) that are CNAME'd to unique TXT records in a single "auth zone", and those TXT records are access controlled. The code below could be adapted to work directly on _acme-challenge
records instead (and skipping the CNAME indirection), but would then require modification by either implementing a mapping key name <> record, or by using the whole _acme-challenge.foo.tld FQDN as key name.
- www.website.tld shall get a Let's Encrypt certificate, using DNS-01 challenge
-
_acme-challenge.www.website.tld IN CNAME 9810a46e5cef.my-auth.tld
DNS record -
9810a46e5cef.my-auth.tld IN TXT
will hold the ACME challenge - ACME clients supporting CNAME detection (e.g. Lego) can then update the TXT record
9810a46e5cef.my-auth.tld
with an RFC2136 update using a registered TSIG key named9810a46e5cef
- Add configuration to your
pdns.conf
dnsupdate = yes
lua-dnsupdate-policy-script = /path/to/check-dynupdates.lua
-
Register TSIG key in pdns with a unique key name equal to CNAME destination hostname-part, e.g. via
pdnsutil generate-tsig-key [unique-key-name] hmac-sha256
. On Linux, [unique-key-name] could be generated e.g. viacat /proc/sys/kernel/random/uuid
-
Create DNS record
_acme-challenge.www.website.tld IN CNAME [unique-key-name].my-auth.tld
-
Deploy TSIG key to the updating host and prepare ACME client for RFC2136
-
Put the following
check-dynupdates.lua
into the appropriate path that was set inpdns.conf
, and modify necessary network ranges
function updatepolicy(input)
-- target zone where the CNAMEs point to
myzone = "my-auth.tld."
-- allowed networks to accept updates from
mynetworks = newNMG()
mynetworks:addMasks({"1.2.3.0/24", "2.3.4.0/16", "127.0.0.0/8"})
pdnslog("updatepolicy: incoming request", pdns.loglevels.Info)
-- ignore non-authorized networks
if not mynetworks:match(input:getRemote())
then
pdnslog("updatepolicy: network check failed from " .. input:getRemote():toString(), pdns.loglevels.Info)
return false
end
-- ignore non-TSIG requests
if input:getTsigName():countLabels() == 0
then
pdnslog("updatepolicy: missing TSIG", pdns.loglevels.Info)
return false
end
-- only accept TXT record updates in myzone and for the TSIG-matching hostname
if input:getQType() == pdns.TXT and input:getZoneName():toString() == myzone and input:getQName():toString() == input:getTsigName():toString() .. myzone
then
pdnslog("updatepolicy: query checks successful", pdns.loglevels.Info)
return true
end
pdnslog("updatepolicy: query checks failed", pdns.loglevels.Info)
return false
end
Restart pdns and run ACME client. Depending on your pdns loglevel, you will see only the dynamic updates or the logs from the Lua script too.
Please also read the PowerDNS Documentation that is available from https://doc.powerdns.com/