Compare commits

..

No commits in common. "684c2b46e1bfa701823320420d0314caf77b84fc" and "fd15227637e241ba1d053b123b28d17848795118" have entirely different histories.

9 changed files with 97 additions and 82 deletions

View file

@ -2,19 +2,16 @@
'dns', 'dns',
) )
def acme_records(metadata): def acme_records(metadata):
domains = set() if metadata.get('bind/type') == 'slave':
return {}
for other_node in repo.nodes:
for domain, conf in other_node.metadata.get('letsencrypt/domains', {}).items():
domains.add(domain)
domains.update(conf.get('aliases', []))
return { return {
'dns': { 'dns': {
f'_acme-challenge.{domain}': { f'_acme-challenge.{domain}': {
'CNAME': {f"{domain}.{metadata.get('bind/acme_zone')}."}, 'CNAME': {f"{domain}.{metadata.get('bind/acme_zone')}."},
} }
for domain in domains for other_node in repo.nodes
for domain in other_node.metadata.get('letsencrypt/domains', {}).keys()
} }
} }
@ -23,13 +20,16 @@ def acme_records(metadata):
'bind/zones', 'bind/zones',
) )
def acme_zone(metadata): def acme_zone(metadata):
if metadata.get('bind/type') == 'slave':
return {}
return { return {
'bind': { 'bind': {
'zones': { 'zones': {
metadata.get('bind/acme_zone'): { metadata.get('bind/acme_zone'): {
'dynamic': True, 'dynamic': True,
'views': ['external'],
'records': set(), 'records': set(),
'views': ['external'],
}, },
}, },
}, },

View file

@ -1,3 +1,3 @@
% for domain, conf in sorted(domains.items()): % for domain, aliases in sorted(node.metadata.get('letsencrypt/domains', {}).items()):
${domain} ${' '.join(sorted(conf.get('aliases', [])))} ${domain} ${' '.join(sorted(aliases))}
% endfor % endfor

View file

@ -1,55 +1,79 @@
set -e
set -u
set -o pipefail
deploy_challenge() { deploy_challenge() {
echo " set -e
server ${server} set -u
zone ${zone}. set -o pipefail
update add $1.${zone}. 60 IN TXT \"$3\"
send
" | tee | nsupdate -y hmac-sha512:${zone}:${acme_key}
sleep 10 ACME_ZONE=${zone}
SERVER=${server}
DOMAIN=$1
CHALLENGE=$3
KEY=hmac-sha512:acme.sublimity.de:${acme_key}
cmd="
server $SERVER
zone $ACME_ZONE.
update add $DOMAIN.$ACME_ZONE. 60 IN TXT \"$CHALLENGE\"
send
"
echo "$cmd"
echo "$cmd" | nsupdate -y $KEY
sleep 15
} }
clean_challenge() { clean_challenge() {
echo " set -e
server ${server} set -u
zone ${zone}. set -o pipefail
update delete $1.${zone}. TXT
send
" | tee | nsupdate -y hmac-sha512:${zone}:${acme_key}
}
deploy_cert() {
DOMAIN="$1"
KEYFILE="$2"
CERTFILE="$3"
FULLCHAINFILE="$4"
CHAINFILE="$5"
% for domain, conf in sorted(domains.items()): ACME_ZONE=${zone}
% if conf.get('location', None): SERVER=${server}
if [[ $DOMAIN = ${domain} ]] DOMAIN=$1
then CHALLENGE=$3
cat "$KEYFILE" > "${conf['location']}/privkey.pem" KEY=hmac-sha512:acme.sublimity.de:${acme_key}
cat "$CERTFILE" > "${conf['location']}/cert.pem" cmd="
cat "$FULLCHAINFILE" > "${conf['location']}/fullchain.pem" server $SERVER
cat "$CHAINFILE" > "${conf['location']}/chain.pem" zone $ACME_ZONE.
fi update delete $DOMAIN.$ACME_ZONE. TXT
% endif send
% if conf.get('owner', None): "
chown ${conf['owner']} "${conf['location']}/privkey.pem" "${conf['location']}/cert.pem" "${conf['location']}/fullchain.pem" "${conf['location']}/chain.pem" echo "$cmd"
% endif echo "$cmd" | nsupdate -y $KEY
% for service in sorted(conf.get('reload', [])):
systemctl reload-or-restart ${service}
% endfor
% endfor
} }
deploy_cert() {<%text>
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}"</%text>
% for service, config in node.metadata.get('letsencrypt/concat_and_deploy', {}).items():
# concat_and_deploy ${service}
if [ "$DOMAIN" = "${config['match_domain']}" ]; then
cat $KEYFILE > ${config['target']}
cat $FULLCHAINFILE >> ${config['target']}
% if 'chown' in config:
chown ${config['chown']} ${config['target']}
% endif
% if 'chmod' in config:
chmod ${config['chmod']} ${config['target']}
% endif
% if 'commands' in config:
% for command in config['commands']:
${command}
% endfor
% endif
fi
% endfor
}
exit_hook() {<%text>
local ERROR="${1:-}"</%text>
% for service in sorted(node.metadata.get('letsencrypt/reload_after', set())):
systemctl reload-or-restart ${service}
% endfor
}
<%text>
HANDLER="$1"; shift HANDLER="$1"; shift
if [[ $HANDLER =~ ^(deploy_cert|deploy_challenge|clean_challenge)$ ]] if [[ "${HANDLER}" =~ ^(deploy_cert|exit_hook|deploy_challenge|clean_challenge)$ ]]; then
then
"$HANDLER" "$@" "$HANDLER" "$@"
fi fi</%text>

View file

@ -13,9 +13,6 @@ directories = {
files = { files = {
'/etc/dehydrated/domains.txt': { '/etc/dehydrated/domains.txt': {
'content_type': 'mako', 'content_type': 'mako',
'context': {
'domains': node.metadata.get('letsencrypt/domains'),
},
'triggers': { 'triggers': {
'action:letsencrypt_update_certificates', 'action:letsencrypt_update_certificates',
}, },
@ -31,7 +28,6 @@ files = {
'server': ip_interface(acme_node.metadata.get('network/external/ipv4')).ip, 'server': ip_interface(acme_node.metadata.get('network/external/ipv4')).ip,
'zone': acme_node.metadata.get('bind/acme_zone'), 'zone': acme_node.metadata.get('bind/acme_zone'),
'acme_key': acme_node.metadata.get('bind/keys/' + acme_node.metadata.get('bind/acme_zone')), 'acme_key': acme_node.metadata.get('bind/keys/' + acme_node.metadata.get('bind/acme_zone')),
'domains': node.metadata.get('letsencrypt/domains'),
}, },
'mode': '0755', 'mode': '0755',
}, },

View file

@ -53,19 +53,22 @@ def renew(metadata):
) )
def delegated_domains(metadata): def delegated_domains(metadata):
delegated_domains = { delegated_domains = {
domain: conf domain
for other_node in repo.nodes for other_node in repo.nodes
if other_node.has_bundle('letsencrypt') if other_node.has_bundle('letsencrypt')
and other_node.metadata.get('letsencrypt/delegate_to_node', None) == node.name and other_node.metadata.get('letsencrypt/delegate_to_node', None) == node.name
for domain, conf in other_node.metadata.get('letsencrypt/domains').items() for domain in other_node.metadata.get('letsencrypt/domains').keys()
} }
return { return {
'letsencrypt': { 'letsencrypt': {
'domains': delegated_domains, 'domains': {
domain: set()
for domain in delegated_domains
},
}, },
'dns': { 'dns': {
domain: repo.libs.dns.get_a_records(metadata, internal=False) domain: repo.libs.dns.get_a_records(metadata, internal=False)
for domain in delegated_domains.keys() for domain in delegated_domains
}, },
} }

View file

@ -60,9 +60,7 @@ def letsencrypt(metadata):
return { return {
'letsencrypt': { 'letsencrypt': {
'domains': { 'domains': {
metadata.get('mailserver/hostname'): { metadata.get('mailserver/hostname'): set(),
'reload': {'dovecot', 'postfix'},
},
}, },
}, },
} }

View file

@ -84,7 +84,7 @@ def letsencrypt(metadata):
return { return {
'letsencrypt': { 'letsencrypt': {
'domains': { 'domains': {
metadata.get('mosquitto/hostname'): {}, metadata.get('mosquitto/hostname'): set(),
}, },
}, },
} }

View file

@ -104,10 +104,10 @@ def letsencrypt(metadata):
return { return {
'letsencrypt': { 'letsencrypt': {
'domains': { 'domains': {
domain: { domain: set() for domain in metadata.get('nginx/vhosts').keys()
'reload': {'nginx'}, },
} 'reload_after': {
for domain in metadata.get('nginx/vhosts').keys() 'nginx',
}, },
}, },
} }

View file

@ -63,15 +63,9 @@
}, },
'letsencrypt': { 'letsencrypt': {
'domains': { 'domains': {
'ckn.li': {}, 'ckn.li': set(),
'test6.ckn.li': { 'sublimity.de': set(),
'aliases': {'www.test6.ckn.li'}, 'freibrief.net': set(),
'location': '/root/temp',
'owner': 'telegraf',
'reload': {'telegraf'},
},
'sublimity.de': {},
'freibrief.net': {},
}, },
}, },
'mailserver': { 'mailserver': {