From d2ea2ccd9c3076a0fc1284525dac124402a99dbd Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sat, 6 Nov 2021 11:44:46 +0100 Subject: [PATCH] wip --- bundles/bind-acme/metadata.py | 29 ++++--------- bundles/bind/files/named.conf.local | 2 + bundles/bind/files/named.conf.options | 2 +- bundles/bind/items.py | 2 + bundles/letsencrypt/files/config | 1 + bundles/letsencrypt/files/dns-challenge.sh | 28 ------------- .../letsencrypt/files/dns_challenge_hook.sh | 41 +++++++++++++++++++ bundles/letsencrypt/files/hook.sh | 35 +++++++++++++++- bundles/letsencrypt/items.py | 8 ++++ bundles/letsencrypt/metadata.py | 2 +- nodes/htz.mails.py | 2 + 11 files changed, 99 insertions(+), 53 deletions(-) delete mode 100644 bundles/letsencrypt/files/dns-challenge.sh create mode 100644 bundles/letsencrypt/files/dns_challenge_hook.sh diff --git a/bundles/bind-acme/metadata.py b/bundles/bind-acme/metadata.py index 61c19c4..c100c4a 100644 --- a/bundles/bind-acme/metadata.py +++ b/bundles/bind-acme/metadata.py @@ -13,34 +13,19 @@ def acme_hostname(metadata): @metadata_reactor.provides( - 'bind/zones', + 'dns', ) def acme_records(metadata): if metadata.get('bind/type') == 'slave': return {} return { - 'bind': { - 'zones': { - zone: { - 'records': { - # FIXME: bw currently cant handle lists of dicts :( - h({ - 'name': f"_acme-challenge{'.' if name else ''}{name}", - 'type': 'CNAME', - 'value': f"{name}.{zone}.{metadata.get('bind/acme_hostname')}.", - }) - for name in { - record['name'] if record['name'] != '@' else '' - for record in conf['records'] - if f"{record['name']}.{zone}" in metadata.get('letsencrypt/domains') - } - } - } - for zone, conf in metadata.get('bind/zones').items() - if zone != metadata.get('bind/acme_hostname') - }, - }, + 'dns': { + f'_acme-challenge.{domain}': { + 'CNAME': {f"{domain}.{metadata.get('bind/acme_hostname')}."}, + } + for domain in node.metadata.get('letsencrypt/domains') + } } diff --git a/bundles/bind/files/named.conf.local b/bundles/bind/files/named.conf.local index 8295ac1..cc020ec 100644 --- a/bundles/bind/files/named.conf.local +++ b/bundles/bind/files/named.conf.local @@ -38,9 +38,11 @@ view "${view['name']}" { % if type == 'slave': masters { ${master_ip}; }; % endif + % if type == 'master': % for key in conf.get('keys', []): allow-update { key "${key}"; }; % endfor + % endif file "/var/lib/bind/${view['name']}/db.${zone}"; }; % endfor diff --git a/bundles/bind/files/named.conf.options b/bundles/bind/files/named.conf.options index 7478143..a17f44b 100644 --- a/bundles/bind/files/named.conf.options +++ b/bundles/bind/files/named.conf.options @@ -3,7 +3,7 @@ options { dnssec-validation auto; listen-on-v6 { any; }; - allow-query { any; }; + allow-query { any; }; max-cache-size 30%; querylog yes; diff --git a/bundles/bind/items.py b/bundles/bind/items.py index 89ce5e5..025bee1 100644 --- a/bundles/bind/items.py +++ b/bundles/bind/items.py @@ -53,6 +53,7 @@ files['/etc/bind/named.conf.options'] = { 'context': { 'type': node.metadata.get('bind/type'), 'slave_ips': sorted(slave_ips), + 'master_ip': master_ip, }, 'owner': 'root', 'group': 'bind', @@ -165,6 +166,7 @@ for view in views: unique_records )), 'hostname': node.metadata.get('bind/hostname'), + 'type': node.metadata.get('bind/type'), }, 'needs': [ f"directory:/var/lib/bind/{view['name']}", diff --git a/bundles/letsencrypt/files/config b/bundles/letsencrypt/files/config index 2d4b2b6..4df6601 100644 --- a/bundles/letsencrypt/files/config +++ b/bundles/letsencrypt/files/config @@ -3,3 +3,4 @@ BASEDIR=/var/lib/dehydrated WELLKNOWN="${BASEDIR}/acme-challenges" DOMAINS_TXT="/etc/dehydrated/domains.txt" HOOK="/etc/dehydrated/hook.sh" +CA="https://acme-staging-v02.api.letsencrypt.org/directory" diff --git a/bundles/letsencrypt/files/dns-challenge.sh b/bundles/letsencrypt/files/dns-challenge.sh deleted file mode 100644 index 59756f2..0000000 --- a/bundles/letsencrypt/files/dns-challenge.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -OPERATION=$1 -DOMAIN=$2 -TOKEN=$4 -TTL=300 - -case "$1" in - "deploy_challenge") - - ;; - "clean_challenge") - ;; - "deploy_cert") - ;; - "unchanged_cert") - ;; - "startup_hook") - ;; - "exit_hook") - ;; -esac - -exit 0 diff --git a/bundles/letsencrypt/files/dns_challenge_hook.sh b/bundles/letsencrypt/files/dns_challenge_hook.sh new file mode 100644 index 0000000..c374afc --- /dev/null +++ b/bundles/letsencrypt/files/dns_challenge_hook.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +ACME_ZONE=${acme_hostname} +SERVER=${bind_hostname} +OPERATION=$1 +DOMAIN=$2 +TOKEN=$4 +TTL=300 + +case "$1" in + "deploy_challenge") + printf " + server 127.0.0.1 + zone $ACME_ZONE. + update add $DOMAIN.$ACME_ZONE. 600 IN TXT \"$TOKEN\" + send + " | nsupdate -y $TOKEN + ;; + "clean_challenge") + printf " + server 127.0.0.1 + zone $ACME_ZONE. + update delete $DOMAIN.$ACME_ZONE. TXT + send + " | nsupdate -y $TOKEN + ;; + "deploy_cert") + ;; + "unchanged_cert") + ;; + "startup_hook") + ;; + "exit_hook") + ;; +esac + +exit 0 diff --git a/bundles/letsencrypt/files/hook.sh b/bundles/letsencrypt/files/hook.sh index 4cdf79d..695b474 100644 --- a/bundles/letsencrypt/files/hook.sh +++ b/bundles/letsencrypt/files/hook.sh @@ -1,3 +1,36 @@ +deploy_challenge() { + set -e + set -u + set -o pipefail + + ACME_ZONE=${zone} + SERVER=${server} + DOMAIN=$1 + CHALLENGE=$3 + KEY=hmac-sha512:acme:${acme_key} + cmd=" + server 127.0.0.1 + zone $ACME_ZONE. + update delete $DOMAIN.$ACME_ZONE. TXT + update add $DOMAIN.$ACME_ZONE. 60 IN TXT \"$CHALLENGE\" + send + " + echo "$cmd" + echo "$cmd" | nsupdate -y $KEY + cmd=" + server $SERVER + local $SERVER + zone $ACME_ZONE. + update delete $DOMAIN.$ACME_ZONE. TXT + update add $DOMAIN.$ACME_ZONE. 60 IN TXT \"$CHALLENGE\" + send + " + echo "$cmd" + echo "$cmd" | nsupdate -y $KEY + + sleep 10 +} + deploy_cert() {<%text> local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}" % for service, config in node.metadata.get('letsencrypt/concat_and_deploy', {}).items(): @@ -32,6 +65,6 @@ exit_hook() {<%text> <%text> HANDLER="$1"; shift -if [[ "${HANDLER}" =~ ^(deploy_cert|exit_hook)$ ]]; then +if [[ "${HANDLER}" =~ ^(deploy_cert|exit_hook|deploy_challenge)$ ]]; then "$HANDLER" "$@" fi diff --git a/bundles/letsencrypt/items.py b/bundles/letsencrypt/items.py index 1835866..6e0b555 100644 --- a/bundles/letsencrypt/items.py +++ b/bundles/letsencrypt/items.py @@ -21,6 +21,14 @@ files = { }, '/etc/dehydrated/hook.sh': { 'content_type': 'mako', + 'context': { + 'server': node.metadata.get('network/external/ipv4').split('/')[0], + 'zone': node.metadata.get('bind/acme_hostname'), + 'acme_key': node.metadata.get('bind/keys/acme'), + }, + 'mode': '0755', + }, + '/etc/dehydrated/letsencrypt-ensure-some-certificate': { 'mode': '0755', }, '/etc/dehydrated/letsencrypt-ensure-some-certificate': { diff --git a/bundles/letsencrypt/metadata.py b/bundles/letsencrypt/metadata.py index 631721c..57aadd4 100644 --- a/bundles/letsencrypt/metadata.py +++ b/bundles/letsencrypt/metadata.py @@ -40,7 +40,7 @@ def renew(metadata): return { 'systemd-timers': { 'letsencrypt': { - 'command': '/bin/bash -c "/usr/bin/dehydrated --cron --accept-terms --challenge http-01 && /usr/bin/dehydrated --cleanup"', + 'command': '/bin/bash -c "/usr/bin/dehydrated --cron --accept-terms --challenge dns-01 && /usr/bin/dehydrated --cleanup"', 'when': 'daily', }, }, diff --git a/nodes/htz.mails.py b/nodes/htz.mails.py index 942b81f..10d98c1 100644 --- a/nodes/htz.mails.py +++ b/nodes/htz.mails.py @@ -32,6 +32,7 @@ }, 'bind': { 'hostname': 'resolver.name', + 'acme_hostname': 'acme.sublimity.de', 'zones': { 'sublimity.de': {}, 'freibrief.net': {}, @@ -63,6 +64,7 @@ 'letsencrypt': { 'domains': { 'ckn.li': set(), + 'test1.ckn.li': set(), 'sublimity.de': set(), 'freibrief.net': set(), },