From 3246f67a8129b7e1bff4e1c3c85cca2c973817de Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sun, 7 Nov 2021 16:19:01 +0100 Subject: [PATCH] wip --- bundles/bind-acme/metadata.py | 24 ++++++++++++- bundles/bind/files/named.conf.local | 20 +++++------ bundles/bind/items.py | 3 +- bundles/bind/metadata.py | 29 +++++++--------- bundles/letsencrypt/items.py | 4 +-- bundles/letsencrypt/metadata.py | 52 ----------------------------- 6 files changed, 49 insertions(+), 83 deletions(-) diff --git a/bundles/bind-acme/metadata.py b/bundles/bind-acme/metadata.py index 25b4401..da5bc91 100644 --- a/bundles/bind-acme/metadata.py +++ b/bundles/bind-acme/metadata.py @@ -1,3 +1,6 @@ +from ipaddress import ip_interface + + @metadata_reactor.provides( 'dns', ) @@ -20,16 +23,35 @@ def acme_records(metadata): @metadata_reactor.provides( + 'bind/acls/acme', + 'bind/keys/acme', 'bind/views/external/zones', ) def acme_zone(metadata): + allowed_ips = { + str(ip_interface(other_node.metadata.get('network/internal/ipv4')).ip) + for other_node in repo.nodes + if other_node.metadata.get('letsencrypt/domains', {}) + } + return { 'bind': { + 'acls': { + 'acme': { + 'key acme', + '!{ !{' + ' '.join(f'{ip};' for ip in sorted(allowed_ips)) + '}; any;}', + }, + }, + 'keys': { + 'acme': {}, + }, 'views': { 'external': { 'zones': { metadata.get('bind/acme_zone'): { - 'dynamic': True, + 'allow_update': { + 'acme', + }, }, }, }, diff --git a/bundles/bind/files/named.conf.local b/bundles/bind/files/named.conf.local index 6447296..1c47488 100644 --- a/bundles/bind/files/named.conf.local +++ b/bundles/bind/files/named.conf.local @@ -1,20 +1,16 @@ % for acl_name, acl_content in acls.items(): acl "${acl_name}" { - % for ac in sorted(acl_content, key=lambda e: (not e.startswith('!'), not e.startswith('key'))): + % for ac in sorted(acl_content, key=lambda e: (not e.startswith('!'), not e.startswith('key'), e)): ${ac}; % endfor }; % endfor -% for view_name, view_conf in views.items(): -% for zone_name, zone_conf in view_conf['zones'].items(): -% if zone_conf.get('key', False): -key "${view_name}.${zone_name}" { +% for key_name, key_conf in sorted(keys.items()): +key "${key_name}" { algorithm hmac-sha512; - secret "${zone_conf['key']}"; + secret "${key_conf['token']}"; }; -% endif -% endfor % endfor % for view_name, view_conf in views.items(): @@ -46,8 +42,12 @@ view "${view_name}" { % if type == 'slave': masters { ${master_ip}; }; % endif - % if type == 'master' and zone_conf.get('key', False): - allow-update { !{ !our-nets; any; }; key "${view_name}.${zone_name}"; }; + % if zone_conf.get('allow_update', False): + allow-update { + % for allow_update in zone_conf['allow_update']: + ${allow_update}; + % endfor + }; % endif file "/var/lib/bind/${view_name}/db.${zone_name}"; }; diff --git a/bundles/bind/items.py b/bundles/bind/items.py index d1ed8af..fc274fd 100644 --- a/bundles/bind/items.py +++ b/bundles/bind/items.py @@ -81,6 +81,7 @@ files['/etc/bind/named.conf.local'] = { for view_name, view_conf in master_node.metadata.get('bind/views').items() }, }, + 'keys': master_node.metadata.get('bind/keys'), 'views': dict(sorted( master_node.metadata.get('bind/views').items(), key=lambda e: (e[1].get('default', False), e[0]), @@ -130,7 +131,7 @@ for view_name, view_conf in node.metadata.get('bind/views').items(): files[f"/var/lib/bind/{view_name}/db.{zone_name}"].update({ 'source': 'db', 'content_type': 'mako', - 'unless': f"test -f /var/lib/bind/{view_name}/db.{zone_name}" if zone_conf.get('dynamic', False) else 'false', + 'unless': f"test -f /var/lib/bind/{view_name}/db.{zone_name}" if zone_conf.get('allow_update', False) else 'false', 'context': { 'serial': datetime.now().strftime('%Y%m%d%H'), 'records': zone_conf['records'], diff --git a/bundles/bind/metadata.py b/bundles/bind/metadata.py index 8d496fe..f6826b9 100644 --- a/bundles/bind/metadata.py +++ b/bundles/bind/metadata.py @@ -38,6 +38,7 @@ defaults = { }, }, 'zones': {}, + 'keys': {}, }, 'telegraf': { 'config': { @@ -174,29 +175,23 @@ def slaves(metadata): @metadata_reactor.provides( - 'bind/views', + 'bind/keys', ) def generate_keys(metadata): return { 'bind': { - 'views': { - view_name: { - 'zones': { - zone_name: { - 'key': repo.libs.hmac.hmac_sha512( - f'{view_name}.{zone_name}', - str(repo.vault.random_bytes_as_base64_for( - f"{metadata.get('id')} bind {view_name} key {zone_name}", - length=32, - )), - ) - } - for zone_name, zone_conf in view_conf['zones'].items() - if zone_conf.get('dynamic', False) - } + 'keys': { + key: { + 'token':repo.libs.hmac.hmac_sha512( + key, + str(repo.vault.random_bytes_as_base64_for( + f"{metadata.get('id')} bind key {key}", + length=32, + )), + ) } - for view_name, view_conf in metadata.get('bind/views').items() } + for key in metadata.get('bind/keys') }, } diff --git a/bundles/letsencrypt/items.py b/bundles/letsencrypt/items.py index b4dc82d..5b41e33 100644 --- a/bundles/letsencrypt/items.py +++ b/bundles/letsencrypt/items.py @@ -30,8 +30,8 @@ files = { 'context': { 'server': ip_interface(acme_node.metadata.get('network/external/ipv4')).ip, 'zone': acme_node.metadata.get('bind/acme_zone'), - 'acme_key_name': 'external' + acme_node.metadata.get('bind/acme_zone'), - 'acme_key': acme_node.metadata.get('bind/views/external/zones/'+acme_node.metadata.get('bind/acme_zone')+'/key'), + 'acme_key_name': 'acme', + 'acme_key': acme_node.metadata.get('bind/keys/acme/token'), 'domains': node.metadata.get('letsencrypt/domains'), }, 'mode': '0755', diff --git a/bundles/letsencrypt/metadata.py b/bundles/letsencrypt/metadata.py index 55a468b..c7caa85 100644 --- a/bundles/letsencrypt/metadata.py +++ b/bundles/letsencrypt/metadata.py @@ -18,55 +18,3 @@ defaults = { }, }, } - - -@metadata_reactor.provides( - 'systemd-timers/letsencrypt', - 'mirror/certs', -) -def renew(metadata): - delegated_node = metadata.get('letsencrypt/delegate_to_node', False) - - if delegated_node: - delegated_ip = ip_interface(repo.get_node(delegated_node).metadata.get('network/internal/ipv4')).ip - return { - 'mirror': { - 'certs': { - 'from': f"{delegated_ip}:/var/lib/dehydrated/certs", - 'to': '/var/lib/dehydrated', - }, - }, - } - else: - return { - 'systemd-timers': { - 'letsencrypt': { - 'command': '/bin/bash -c "/usr/bin/dehydrated --cron --accept-terms --challenge dns-01 && /usr/bin/dehydrated --cleanup"', - 'when': 'daily', - }, - }, - } - - -@metadata_reactor.provides( - 'letsencrypt/domains', - 'dns', -) -def delegated_domains(metadata): - delegated_domains = { - domain: conf - for other_node in repo.nodes - if other_node.has_bundle('letsencrypt') - and other_node.metadata.get('letsencrypt/delegate_to_node', None) == node.name - for domain, conf in other_node.metadata.get('letsencrypt/domains').items() - } - - return { - 'letsencrypt': { - 'domains': delegated_domains, - }, - 'dns': { - domain: repo.libs.dns.get_a_records(metadata, internal=False) - for domain in delegated_domains.keys() - }, - }