diff --git a/docs/geomirrors.md b/docs/geomirrors.md index 465f97f85a6bb08a21b6768ed0ee79b1baf58238..9b2968e5cf17b7ed535a94fa2c661c018be24297 100644 --- a/docs/geomirrors.md +++ b/docs/geomirrors.md @@ -20,7 +20,7 @@ The continent mirrors america, asia and europe contain the archive mirrors as we - Host with Arch Linux installed - root access provided - Enough storage to host repos / debugrepos (at least) -- Bandwidth (depends on location) +- Bandwidth (depends on location) ## Adding a new mirror box - Add new entries in `hosts` file under `mirrors` and `geo_mirrors` sections @@ -38,7 +38,7 @@ The continent mirrors america, asia and europe contain the archive mirrors as we | ----------- | ----------- | ----------- | ----------- | ----------- | | install_arch | All | Install Arch | | Optional if you can | | mirrors.yml | All | Setup mirror | `<fqdn>` | | -| redirect.archlinux.org.yml | acme_dns_challenge | Make TXT records | | | +| redirect.archlinux.org.yml | dyn_dns | Make TXT records | | | | gemini.archlinux.org.yml | dbscripts | Allow debug repo syncing | | | | mirrors.yml | geo_dns | Add new domain to DNS | All other mirrors from geo.mirror | | | monitoring.archlinux.org.yml | wireguard,prometheus | Allow loki and prometheus to fetch data | | | diff --git a/group_vars/all/dyn_dns.yml b/group_vars/all/dyn_dns.yml new file mode 100644 index 0000000000000000000000000000000000000000..6d6bce7bc079635539f76010c24612c9e27e6277 --- /dev/null +++ b/group_vars/all/dyn_dns.yml @@ -0,0 +1,8 @@ +dyn_dns_server: "{{ hostvars['redirect.archlinux.org']['ipv4_address'] }}" +dyn_dns_zones: + _acme-challenge.geo.mirror.pkgbuild.com: &acme_challenge + key: certbot + allowed_ipv4: "{{ groups['geo_mirrors'] | map('extract', hostvars, ['ipv4_address']) }}" + allowed_ipv6: "{{ groups['geo_mirrors'] | map('extract', hostvars, ['ipv6_address']) }}" + valid_qtypes: [TXT] + _acme-challenge.riscv.mirror.pkgbuild.com: *acme_challenge diff --git a/group_vars/all/vault_dyn_dns_keys.yml b/group_vars/all/vault_dyn_dns_keys.yml new file mode 100644 index 0000000000000000000000000000000000000000..272d3993442dbdbebea51b0f8ff670e5eb8325ad --- /dev/null +++ b/group_vars/all/vault_dyn_dns_keys.yml @@ -0,0 +1,13 @@ +$ANSIBLE_VAULT;1.1;AES256 +61373835393530366133386434373162656332363939656235646235663333633532336435353266 +3364616435323230656233666633353535303436363433610a376133633938663634323932643764 +36656433366566623864636462383861636538363737343861316330306561373965626366363032 +6366373462303839660a653335623261306630623139643630323330633665393030333830653930 +37653166613264643537383734336163313537313334363635653062653832333638356361313461 +62353166393332326534356661653464333266383234396536383633323834333566633861643363 +66316162356566343964623237356264633564646634653834326363386235333361656332386265 +39333463343365393962663637666333376236366638306361316435306537643031346162346464 +33313466353666353136386463353831353365643333613066326136343234343636343833346465 +64343962303766303436613538616165623837383837303230623135623562303664333764323834 +62313864653234653138336134303638666234376631663361396662653863643433313864303330 +63663034353461346562 diff --git a/group_vars/geo_mirrors/vault_certbot.yml b/group_vars/geo_mirrors/vault_certbot.yml deleted file mode 120000 index 760d5f94f435cbe9cc884917061dc28dbcb1445b..0000000000000000000000000000000000000000 --- a/group_vars/geo_mirrors/vault_certbot.yml +++ /dev/null @@ -1 +0,0 @@ -../../host_vars/redirect.archlinux.org/vault_certbot.yml \ No newline at end of file diff --git a/host_vars/redirect.archlinux.org/vault_certbot.yml b/host_vars/redirect.archlinux.org/vault_certbot.yml deleted file mode 100644 index 679df61a0ee824fad00dcac1428cbc729f24813d..0000000000000000000000000000000000000000 --- a/host_vars/redirect.archlinux.org/vault_certbot.yml +++ /dev/null @@ -1,18 +0,0 @@ -$ANSIBLE_VAULT;1.1;AES256 -36396331303031376233613930366238363633633464636336663163363234623939623731616536 -6262353930613038346636343364663532343539343661620a313262666231333164653639653531 -64626638366531653865616130653235323933376235306130663034636633343764383264373632 -6335643131366364620a353835353663643533396161626462343566376264633331336365373936 -31393234333539656230633531626438643466656438643530363466303337356263333031396362 -65656461313261303461643062353634303266316163346132656135323639363833306335343831 -62353437643537333430343263626630323761356530386466633964336430373636623937326138 -62336564326462366661323665663032363939353138366132636564613364386266643762326565 -33386235393830336563363836333732656637363661666661656434326231323662383962643761 -66303761323336383838303166313766336338656433383834663932356431613638643563353865 -39346432366437303334343339383835646135326435656637646463303332343734643138653236 -33643739373839656138376339626134663332613438643036656430306338393436396465616337 -35336463383032346632626536383433633436653037613336313837386336306362323766356465 -30336233356631643362316539326135363961393435303535376136633762373061633965353564 -31393161646132323833653936346464646532353830643362366433653934326563646166303862 -62666364326563353439663636383437613134333836643134646135326435646234653762333438 -61306361393763356633303736333535656331636461333237633134626231633635 diff --git a/playbooks/redirect.archlinux.org.yml b/playbooks/redirect.archlinux.org.yml index 5bbcd4da8e9d81fdec96144f1b3c8296649e2297..3bae351d4f54f8e574eca92ac7e22a6698158d7c 100644 --- a/playbooks/redirect.archlinux.org.yml +++ b/playbooks/redirect.archlinux.org.yml @@ -14,4 +14,4 @@ - { role: promtail } - { role: hardening } - { role: ping } - - { role: acme_dns_challenge } + - { role: dyn_dns } diff --git a/roles/acme_dns_challenge/templates/dnsupdate-policy.lua.j2 b/roles/acme_dns_challenge/templates/dnsupdate-policy.lua.j2 deleted file mode 100644 index 50fc8a2223780aedcdd8a6618e25d9afd50358f2..0000000000000000000000000000000000000000 --- a/roles/acme_dns_challenge/templates/dnsupdate-policy.lua.j2 +++ /dev/null @@ -1,42 +0,0 @@ -#jinja2: lstrip_blocks: True --- Based on https://github.com/PowerDNS/pdns/wiki/Lua-Examples-(Authoritative)#updatepolicy-access-control-for-rfc2136-dynamic-updates -function updatepolicy(input) - valid_rrnames = { - {% for domain in geo_domains %} - ["_acme-challenge.{{ domain }}."]=true, - {% endfor %} - } - - -- only allow updates from our servers - mynetworks = newNMG() - mynetworks:addMasks({ -{% for host in groups['geo_mirrors'] | sort %} - '{{ hostvars[host]['ipv4_address'] }}/32', - '{{ hostvars[host]['ipv6_address'] }}/128', -{% endfor %} - }) - - -- 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 for _acme_challenge - if input:getQType() == pdns.TXT and valid_rrnames[input:getQName():toString()] - then - pdnslog("updatepolicy: query checks successful", pdns.loglevels.Info) - return true - end - - pdnslog("updatepolicy: query checks failed", pdns.loglevels.Info) - return false -end diff --git a/roles/certbot/templates/rfc2136.ini.j2 b/roles/certbot/templates/rfc2136.ini.j2 index 32bf6978e8870790343a5e05028a387241eec90e..3207643de31f069d2059a4ae62a83c26a6861bee 100644 --- a/roles/certbot/templates/rfc2136.ini.j2 +++ b/roles/certbot/templates/rfc2136.ini.j2 @@ -1,4 +1,4 @@ -dns_rfc2136_server = {{ certbot_rfc2136_server }} -dns_rfc2136_name = {{ certbot_rfc2136_key }} -dns_rfc2136_secret = {{ certbot_rfc2136_secret }} -dns_rfc2136_algorithm = {{ certbot_rfc2136_algorithm }} +dns_rfc2136_server = {{ dyn_dns_server }} +dns_rfc2136_name = certbot +dns_rfc2136_secret = {{ dyn_dns_keys['certbot'].secret }} +dns_rfc2136_algorithm = {{ dyn_dns_keys['certbot'].algorithm | upper }} diff --git a/roles/acme_dns_challenge/handlers/main.yml b/roles/dyn_dns/handlers/main.yml similarity index 100% rename from roles/acme_dns_challenge/handlers/main.yml rename to roles/dyn_dns/handlers/main.yml diff --git a/roles/acme_dns_challenge/tasks/main.yml b/roles/dyn_dns/tasks/main.yml similarity index 66% rename from roles/acme_dns_challenge/tasks/main.yml rename to roles/dyn_dns/tasks/main.yml index 2a7873f62c3b9975b9ef50a1fa4f4e3f5e97f1a7..f2d24c3b113d40cc8743b361532ed60c55cd579e 100644 --- a/roles/acme_dns_challenge/tasks/main.yml +++ b/roles/dyn_dns/tasks/main.yml @@ -8,27 +8,30 @@ - {src: dnsupdate-policy.lua.j2, dest: dnsupdate-policy.lua} notify: Restart powerdns -- name: Create directory for sqlite3 dbs +- name: Create directory for sqlite3 database file: path=/var/lib/powerdns state=directory owner=powerdns group=powerdns mode=0755 -- name: Initialize sqlite3 database for _acme-challenge zones +- name: Initialize sqlite3 database command: sqlite3 -init /usr/share/doc/powerdns/schema.sqlite3.sql /var/lib/powerdns/pdns.sqlite3 "" become: true become_user: powerdns args: creates: /var/lib/powerdns/pdns.sqlite3 -- name: Create _acme-challenge zones +- name: Create zones shell: | - pdnsutil create-zone _acme-challenge.{{ item }} {{ inventory_hostname }} - pdnsutil replace-rrset _acme-challenge.{{ item }} @ SOA "{{ inventory_hostname }}. root.archlinux.org. 0 10800 3600 604800 3600" - loop: "{{ geo_domains }}" - become: true - become_user: powerdns + pdnsutil create-zone {{ item.zone }} {{ inventory_hostname }} + pdnsutil replace-rrset {{ item.zone }} @ SOA "{{ inventory_hostname }}. root.archlinux.org. 0 10800 3600 604800 3600" + loop: "{{ dyn_dns_zones | dict2items(key_name='zone') }}" + loop_control: + label: "{{ item.zone }}" changed_when: false -- name: Import TSIG key (for certbot) - command: pdnsutil import-tsig-key {{ certbot_rfc2136_key }} {{ certbot_rfc2136_algorithm }} {{ certbot_rfc2136_secret }} +- name: Import TSIG keys + command: pdnsutil import-tsig-key {{ item.key }} {{ item.value.algorithm }} {{ item.value.secret }} + loop: "{{ dyn_dns_keys | dict2items }}" + loop_control: + label: "{{ item.key }}" changed_when: false - name: Open powerdns ipv4 port for monitoring.archlinux.org diff --git a/roles/dyn_dns/templates/dnsupdate-policy.lua.j2 b/roles/dyn_dns/templates/dnsupdate-policy.lua.j2 new file mode 100644 index 0000000000000000000000000000000000000000..833a9886d72903c064fbfd76ff196cf4efd25bec --- /dev/null +++ b/roles/dyn_dns/templates/dnsupdate-policy.lua.j2 @@ -0,0 +1,86 @@ +#jinja2: lstrip_blocks: True +-- Based on https://github.com/PowerDNS/pdns/wiki/Lua-Examples-(Authoritative)#updatepolicy-access-control-for-rfc2136-dynamic-updates +function updatepolicy(input) + local zones = { +{% for zone, prop in dyn_dns_zones.items() %} + ["{{ zone }}."] = { + ["key"] = "{{ prop.key }}.", + ["allowed_networks"] = { + {% for ipv4 in prop.allowed_ipv4 %} + '{{ ipv4 }}{{ '' if '/' in ipv4 else '/32' }}', + {% endfor %} + {% for ipv6 in prop.allowed_ipv6 %} + '{{ ipv6 }}{{ '' if '/' in ipv6 else '/128' }}', + {% endfor %} + }, + ["valid_qtypes"] = { + {% for qtype in prop.valid_qtypes %} + [pdns.{{ qtype }}] = true, + {% endfor %} + }, + ["subdomains"] = "{{ prop.subdomains | default('no') }}", + }, +{% endfor %} + } + + local zone_name = input:getZoneName():toString() + local zone = zones[zone_name] + + -- reject unknown zones + if not zone + then + pdnslog("updatepolicy: unknown zone " .. zone_name, pdns.loglevels.Info) + return false + end + + local allowed_networks = newNMG(zone["allowed_networks"]) + + -- reject unauthorized networks + if not allowed_networks:match(input:getRemote()) + then + pdnslog("updatepolicy: network check failed from " .. input:getRemote():toString(), pdns.loglevels.Info) + return false + end + + input_qname = input:getQName():toString() + + -- reject subdomain records when subdomains == "no" + if zone["subdomains"] == "no" and input_qname ~= zone_name + then + pdnslog("updatepolicy: subdomain records not allowed in zone " .. zone_name, pdns.loglevels.Info) + return false + end + + -- reject apex records when subdomains == "only" + if zone["subdomains"] == "only" and input_qname == zone_name + then + pdnslog("updatepolicy: apex records not allowed in zone " .. zone_name, pdns.loglevels.Info) + return false + end + + -- reject non-TSIG requests + if input:getTsigName():countLabels() == 0 + then + pdnslog("updatepolicy: missing TSIG", pdns.loglevels.Info) + return false + end + + input_tsig_name = input:getTsigName():toString() + + -- reject unauthorized TSIG key names + if zone["key"] ~= input_tsig_name + then + pdnslog("updatepolicy: wrong TSIG " .. input_tsig_name .. " for zone " .. zone_name, pdns.loglevels.Info) + return false + end + + -- reject disallowed record types + if not zone["valid_qtypes"][input:getQType()] + then + pdnslog("updatepolicy: disallowed record type " .. input:getQType(), pdns.loglevels.Info) + return false + end + + pdnslog("updatepolicy: query checks successful", pdns.loglevels.Info) + return true +end diff --git a/roles/acme_dns_challenge/templates/pdns.conf.j2 b/roles/dyn_dns/templates/pdns.conf.j2 similarity index 100% rename from roles/acme_dns_challenge/templates/pdns.conf.j2 rename to roles/dyn_dns/templates/pdns.conf.j2