diff --git a/group_vars/all/vars.yml b/group_vars/all/vars.yml index 4f50fbc..17ed81b 100644 --- a/group_vars/all/vars.yml +++ b/group_vars/all/vars.yml @@ -2,6 +2,10 @@ certmgr_mode: webserver +dns_axfr_ips: +- 216.218.133.2 +- 2001:470:600::2 + dss_domain: dss.binary-kitchen.de gogs_domain: git.binary-kitchen.de diff --git a/roles/dns-extern/files/updatepolicy.aliases b/roles/dns-extern/files/updatepolicy.aliases new file mode 100644 index 0000000..871836d --- /dev/null +++ b/roles/dns-extern/files/updatepolicy.aliases @@ -0,0 +1,9 @@ +-- +-- Define additional domains to allow (acme) updates for with an exisiting TSIG key +-- +-- Line format: +-- alias[""] = { "", ... } +-- +-- WARNING: Trailing "." are important for correct validation on all used names +-- +-- diff --git a/roles/dns-extern/files/updatepolicy.lua b/roles/dns-extern/files/updatepolicy.lua new file mode 100644 index 0000000..cb852b5 --- /dev/null +++ b/roles/dns-extern/files/updatepolicy.lua @@ -0,0 +1,58 @@ +function loadaliasesfromfile() + local env = { alias = {} } + local f,err = loadfile("/etc/powerdns/updatepolicy.aliases", "t", env) + if f then + f() -- run the loaded code in the prepared env for safety reasons + pdnslog("Successfully loaded alias config", pdns.loglevels.Debug) + else + pdnslog("Failed to load alias config: "..err, pdns.loglevels.Warning) + end + return env.alias +end + +function getacmedomains(domain) + -- Add domain as the first entry to the list + local domains = {[0] = "_acme-challenge."..domain} + local counter = 1 + -- Load additional alias domains from config file + local aliases = loadaliasesfromfile() + if aliases[domain] ~= nil then + for _,alias in pairs(aliases[domain]) do + domains[counter] = "_acme-challenge."..alias + counter = counter + 1 + end + end + -- Return all challenge domains + return domains +end + +function updatepolicy(input) + -- Check for valid TSIG key or fail + local key = input:getTsigName() + local keyname = nil + if key == nil or not pcall(function() keyname = key:toString() end) or keyname == "" then + -- fail on no key (and work around the possible odd exception with pcall) + pdnslog("No TSIG key found. Update rejected.", pdns.loglevels.Error) + return false + end + + -- Process ACME keys + local pos,_,domain = string.find(keyname, "^acme%-(.+)") + if pos ~= nil then + for _,acmedomain in pairs(getacmedomains(domain)) do + pdnslog("Validating against "..acmedomain, pdns.loglevels.Debug) + if input:getQType() == pdns.TXT and input:getQName():toString():lower() == acmedomain:lower() then + -- valid acme key with matching domain matches name and TXT + pdnslog("ACME TSIG '"..keyname.."' key found and request matches domain or known aliases. Update permitted.") + return true + end + end + -- acme key and no valid match + pdnslog("ACME TSIG '"..keyname.."' key found but request does not match domain or known aliases. Update rejected.", pdns.loglevels.Error) + return false + end + + -- Process other keys with the normal default policy result + pdnslog("TSIG Key '"..keyname.."' found. Update permitted.") + return true +end diff --git a/roles/dns-extern/handlers/main.yml b/roles/dns-extern/handlers/main.yml new file mode 100644 index 0000000..ae00ee9 --- /dev/null +++ b/roles/dns-extern/handlers/main.yml @@ -0,0 +1,4 @@ +--- + +- name: Restart powerdns + service: name=pdns state=restarted diff --git a/roles/dns-extern/tasks/main.yml b/roles/dns-extern/tasks/main.yml new file mode 100644 index 0000000..54df9b3 --- /dev/null +++ b/roles/dns-extern/tasks/main.yml @@ -0,0 +1,21 @@ +--- + +- name: Install powerdns + apt: name={{ item }} + with_items: + - pdns-server + - pdns-backend-sqlite3 + +- name: Configure powerdns + template: src=pdns.conf.j2 dest=/etc/powerdns/pdns.conf + notify: Restart powerdns + +- name: Copy update policy script + copy: src=updatepolicy.lua dest=/etc/powerdns/updatepolicy.lua + notify: Restart powerdns + +- name: Initialize update policy alias list + copy: src=updatepolicy.aliases dest=/etc/powerdns/updatepolicy.aliases force=no + +- name: Start the powerdns services + service: name=pdns state=started enabled=yes diff --git a/roles/dns-extern/templates/pdns.conf.j2 b/roles/dns-extern/templates/pdns.conf.j2 new file mode 100644 index 0000000..76a9942 --- /dev/null +++ b/roles/dns-extern/templates/pdns.conf.j2 @@ -0,0 +1,13 @@ +local-address=0.0.0.0 +local-ipv6=:: +launch=gsqlite3 +gsqlite3-dnssec +gsqlite3-database=/var/lib/powerdns/powerdns.sqlite3 +master +slave-cycle-interval=30 +dnsupdate=yes +only-notify= +allow-axfr-ips=127.0.0.1,::1{% if dns_axfr_ips is defined %},{{ dns_axfr_ips | join(',') }} +{% endif %} +allow-dnsupdate-from=0.0.0.0/0,::/0 +lua-dnsupdate-policy-script=/etc/powerdns/updatepolicy.lua diff --git a/site.yml b/site.yml index a9301b0..97fa722 100644 --- a/site.yml +++ b/site.yml @@ -87,4 +87,4 @@ - name: Setup primary dns server hosts: neon.binary-kitchen.net roles: -# - dns-extern + - dns-extern