wip
This commit is contained in:
parent
a59c981238
commit
3246f67a81
6 changed files with 49 additions and 83 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
from ipaddress import ip_interface
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'dns',
|
'dns',
|
||||||
)
|
)
|
||||||
|
@ -20,16 +23,35 @@ def acme_records(metadata):
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
|
'bind/acls/acme',
|
||||||
|
'bind/keys/acme',
|
||||||
'bind/views/external/zones',
|
'bind/views/external/zones',
|
||||||
)
|
)
|
||||||
def acme_zone(metadata):
|
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 {
|
return {
|
||||||
'bind': {
|
'bind': {
|
||||||
|
'acls': {
|
||||||
|
'acme': {
|
||||||
|
'key acme',
|
||||||
|
'!{ !{' + ' '.join(f'{ip};' for ip in sorted(allowed_ips)) + '}; any;}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'keys': {
|
||||||
|
'acme': {},
|
||||||
|
},
|
||||||
'views': {
|
'views': {
|
||||||
'external': {
|
'external': {
|
||||||
'zones': {
|
'zones': {
|
||||||
metadata.get('bind/acme_zone'): {
|
metadata.get('bind/acme_zone'): {
|
||||||
'dynamic': True,
|
'allow_update': {
|
||||||
|
'acme',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
% for acl_name, acl_content in acls.items():
|
% for acl_name, acl_content in acls.items():
|
||||||
acl "${acl_name}" {
|
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};
|
${ac};
|
||||||
% endfor
|
% endfor
|
||||||
};
|
};
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for view_name, view_conf in views.items():
|
% for key_name, key_conf in sorted(keys.items()):
|
||||||
% for zone_name, zone_conf in view_conf['zones'].items():
|
key "${key_name}" {
|
||||||
% if zone_conf.get('key', False):
|
|
||||||
key "${view_name}.${zone_name}" {
|
|
||||||
algorithm hmac-sha512;
|
algorithm hmac-sha512;
|
||||||
secret "${zone_conf['key']}";
|
secret "${key_conf['token']}";
|
||||||
};
|
};
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for view_name, view_conf in views.items():
|
% for view_name, view_conf in views.items():
|
||||||
|
@ -46,8 +42,12 @@ view "${view_name}" {
|
||||||
% if type == 'slave':
|
% if type == 'slave':
|
||||||
masters { ${master_ip}; };
|
masters { ${master_ip}; };
|
||||||
% endif
|
% endif
|
||||||
% if type == 'master' and zone_conf.get('key', False):
|
% if zone_conf.get('allow_update', False):
|
||||||
allow-update { !{ !our-nets; any; }; key "${view_name}.${zone_name}"; };
|
allow-update {
|
||||||
|
% for allow_update in zone_conf['allow_update']:
|
||||||
|
${allow_update};
|
||||||
|
% endfor
|
||||||
|
};
|
||||||
% endif
|
% endif
|
||||||
file "/var/lib/bind/${view_name}/db.${zone_name}";
|
file "/var/lib/bind/${view_name}/db.${zone_name}";
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,6 +81,7 @@ files['/etc/bind/named.conf.local'] = {
|
||||||
for view_name, view_conf in master_node.metadata.get('bind/views').items()
|
for view_name, view_conf in master_node.metadata.get('bind/views').items()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'keys': master_node.metadata.get('bind/keys'),
|
||||||
'views': dict(sorted(
|
'views': dict(sorted(
|
||||||
master_node.metadata.get('bind/views').items(),
|
master_node.metadata.get('bind/views').items(),
|
||||||
key=lambda e: (e[1].get('default', False), e[0]),
|
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({
|
files[f"/var/lib/bind/{view_name}/db.{zone_name}"].update({
|
||||||
'source': 'db',
|
'source': 'db',
|
||||||
'content_type': 'mako',
|
'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': {
|
'context': {
|
||||||
'serial': datetime.now().strftime('%Y%m%d%H'),
|
'serial': datetime.now().strftime('%Y%m%d%H'),
|
||||||
'records': zone_conf['records'],
|
'records': zone_conf['records'],
|
||||||
|
|
|
@ -38,6 +38,7 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'zones': {},
|
'zones': {},
|
||||||
|
'keys': {},
|
||||||
},
|
},
|
||||||
'telegraf': {
|
'telegraf': {
|
||||||
'config': {
|
'config': {
|
||||||
|
@ -174,29 +175,23 @@ def slaves(metadata):
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'bind/views',
|
'bind/keys',
|
||||||
)
|
)
|
||||||
def generate_keys(metadata):
|
def generate_keys(metadata):
|
||||||
return {
|
return {
|
||||||
'bind': {
|
'bind': {
|
||||||
'views': {
|
'keys': {
|
||||||
view_name: {
|
key: {
|
||||||
'zones': {
|
'token':repo.libs.hmac.hmac_sha512(
|
||||||
zone_name: {
|
key,
|
||||||
'key': repo.libs.hmac.hmac_sha512(
|
str(repo.vault.random_bytes_as_base64_for(
|
||||||
f'{view_name}.{zone_name}',
|
f"{metadata.get('id')} bind key {key}",
|
||||||
str(repo.vault.random_bytes_as_base64_for(
|
length=32,
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for view_name, view_conf in metadata.get('bind/views').items()
|
|
||||||
}
|
}
|
||||||
|
for key in metadata.get('bind/keys')
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ files = {
|
||||||
'context': {
|
'context': {
|
||||||
'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_name': 'external' + acme_node.metadata.get('bind/acme_zone'),
|
'acme_key_name': 'acme',
|
||||||
'acme_key': acme_node.metadata.get('bind/views/external/zones/'+acme_node.metadata.get('bind/acme_zone')+'/key'),
|
'acme_key': acme_node.metadata.get('bind/keys/acme/token'),
|
||||||
'domains': node.metadata.get('letsencrypt/domains'),
|
'domains': node.metadata.get('letsencrypt/domains'),
|
||||||
},
|
},
|
||||||
'mode': '0755',
|
'mode': '0755',
|
||||||
|
|
|
@ -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()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue