bundles/wireguard: rework metadata.py
Some checks failed
bundlewrap/pipeline/head There was a failure building this commit

This commit is contained in:
Franzi 2021-04-01 16:27:31 +02:00
parent b679f568eb
commit 6e423c24fb
Signed by: kunsi
GPG key ID: 12E3D2136B818350
7 changed files with 155 additions and 64 deletions

View file

@ -1,8 +0,0 @@
[Match]
Name=wg0
[Network]
Address=${my_ip}
[Route]
Destination=${network}

View file

@ -1,21 +1,16 @@
from ipaddress import ip_network
assert node.has_bundle('systemd-networkd')
network = ip_network(node.metadata['wireguard']['my_ip'], strict=False)
files = {
'/etc/systemd/network/99-wg0.netdev': {
'source': 'wg0.netdev',
'/etc/systemd/network/wg0.netdev': {
'content_type': 'mako',
'context': node.metadata['wireguard'],
'needs': {
'pkg_apt:wireguard',
'context': {
'network': f'{network.network_address}/{network.prefixlen}',
**node.metadata['wireguard'],
},
'triggers': {
'svc_systemd:systemd-networkd:restart',
},
},
'/etc/systemd/network/99-wg0.network': {
'source': 'wg0.network',
'content_type': 'mako',
'context': node.metadata['wireguard'],
'needs': {
'pkg_apt:wireguard',
},

View file

@ -1,5 +1,9 @@
from ipaddress import ip_network
from bundlewrap.exceptions import NoSuchNode
from bundlewrap.metadata import atomic
defaults = {
'apt': {
'packages': {
@ -16,10 +20,10 @@ defaults = {
},
'iptables': {
'bundle_rules': {
'wireguard': [
'wireguard': {
'iptables_both -A FORWARD -i wg0 -j ACCEPT',
'iptables_both -A FORWARD -o wg0 -j ACCEPT',
],
},
},
},
'wireguard': {
@ -29,51 +33,77 @@ defaults = {
@metadata_reactor.provides(
'wireguard/network',
'wireguard/peers',
)
def get_wireguard_network_from_server(metadata):
# FIXME This will break if more than one node sets 'wireguard/network'
for rnode in repo.nodes:
if not rnode.has_bundle('wireguard'):
continue
def peer_psks(metadata):
peers = {}
if node.name in rnode.metadata.get('wireguard/peers', {}).keys():
network = rnode.metadata.get('wireguard/network', None)
for peer_name in metadata.get('wireguard/peers', {}):
peers[peer_name] = {}
if network:
return {
'wireguard': {
'network': network,
},
}
if node.name < peer_name:
peers[peer_name] = {
'psk': repo.vault.random_bytes_as_base64_for(f'{node.name} wireguard {peer_name}'),
}
else:
peers[peer_name] = {
'psk': repo.vault.random_bytes_as_base64_for(f'{peer_name} wireguard {node.name}'),
}
return {}
return {
'wireguard': {
'peers': peers,
},
}
@metadata_reactor.provides(
'wireguard/peers',
)
def get_my_wireguard_peers(metadata):
def peer_pubkeys(metadata):
peers = {}
for rnode in repo.nodes:
if not rnode.has_bundle('wireguard'):
for peer_name in metadata.get('wireguard/peers', {}):
try:
rnode = repo.get_node(peer_name)
except NoSuchNode:
continue
if node.name in rnode.metadata.get('wireguard/peers', {}).keys():
peers[rnode.name] = {
'pubkey': repo.libs.keys.get_pubkey_from_privkey(repo, f'{node.name} wireguard {rnode.name}', rnode.metadata.get('wireguard/privatekey')),
'psk': rnode.metadata.get('wireguard/psk', metadata.get('wireguard/psk', None)),
}
peers[peer_name] = {
'pubkey': repo.libs.keys.get_pubkey_from_privkey(
repo,
f'{rnode.name} wireguard pubkey',
rnode.metadata.get('wireguard/privatekey'),
),
}
if not rnode.metadata.get(f'wireguard/peers/{node.name}/do_not_initiate_a_connection_from_your_side', False):
peers[rnode.name]['endpoint'] = f'{rnode.hostname}:51820'
return {
'wireguard': {
'peers': peers,
},
}
peers[rnode.name]['ips'] = rnode.metadata.get('wireguard/subnets', set())
your_ip = rnode.metadata.get('wireguard/my_ip', None)
if your_ip:
peers[rnode.name]['ips'].add(your_ip)
@metadata_reactor.provides(
'wireguard/peers',
)
def peer_ips_and_endpoints(metadata):
peers = {}
for peer_name in metadata.get('wireguard/peers', {}):
try:
rnode = repo.get_node(peer_name)
except NoSuchNode:
continue
ips = rnode.metadata.get('wireguard/subnets', set())
ips.add(rnode.metadata.get('wireguard/my_ip').split('/')[0])
ips = repo.libs.tools.remove_more_specific_subnets(ips)
peers[rnode.name] = {
'endpoint': '{}:51820'.format(rnode.metadata.get('wireguard/external_hostname', rnode.hostname)),
'ips': ips,
}
return {
'wireguard': {
@ -109,10 +139,63 @@ def icinga2(metadata):
'iptables/port_rules',
)
def iptables(metadata):
sources = set(metadata.get('wireguard/restrict-to', set()))
for peer_name in metadata.get('wireguard/peers'):
try:
rnode = repo.get_node(peer_name)
except NoSuchNode: # roadwarrior
continue
else:
sources.add(peer_name)
return {
'iptables': {
'port_rules': {
'51820/udp': atomic(metadata.get('wireguard/restrict-to', set(metadata.get('wireguard/peers', {}).keys()))),
'51820/udp': atomic(sources),
},
},
}
@metadata_reactor.provides(
'interfaces/wg0/ips',
)
def interface_ips(metadata):
return {
'interfaces': {
'wg0': {
'ips': {
metadata.get('wireguard/my_ip'),
},
},
},
}
@metadata_reactor.provides(
'interfaces/wg0/routes',
)
def routes(metadata):
network = ip_network(metadata.get('wireguard/my_ip'), strict=False)
ips = {
f'{network.network_address}/{network.prefixlen}',
}
routes = {}
for _, peer_config in metadata.get('wireguard/peers', {}).items():
for ip in peer_config['ips']:
ips.add(ip)
if '0.0.0.0/0' in ips:
ips.remove('0.0.0.0/0')
for ip in repo.libs.tools.remove_more_specific_subnets(ips):
routes[ip] = {}
return {
'interfaces': {
'wg0': {
'routes': routes,
},
},
}

View file

@ -55,3 +55,26 @@ def resolve_identifier(repo, identifier):
ip_dict['ipv6'].add(ip)
return ip_dict
def remove_more_specific_subnets(input_subnets) -> list:
final_subnets = []
for subnet in sorted(input_subnets):
source = ip_network(subnet)
if not source in final_subnets:
subnet_found = False
for dest_subnet in final_subnets:
if source.subnet_of(dest_subnet):
subnet_found = True
if not subnet_found:
final_subnets.append(source)
out = []
for net in final_subnets:
out.append(str(net))
return out

View file

@ -172,17 +172,15 @@ nodes['home.router'] = {
},
},
'wireguard': {
# TODO autogenerate?
'my_ip': '172.19.136.2/32',
'external_hostname': 'franzi-home.kunbox.net', # Set via DynDNS
'my_ip': '172.19.136.2/22',
'peers': {
'ovh.wireguard': {},
},
'subnets': {
'172.19.138.0/24',
'172.19.139.0/24',
},
'peers': {
'ovh.wireguard': {
'do_not_initiate_a_connection_from_your_side': True,
},
},
},
},
}

View file

@ -113,7 +113,7 @@ nodes['ovh.icinga2'] = {
'service_filter': '"checks_with_sms" in service.groups'
},
'wireguard': {
'my_ip': '172.19.136.3/32',
'my_ip': '172.19.136.3/22',
'peers': {
'ovh.wireguard': {},
},

View file

@ -24,10 +24,10 @@ nodes['ovh.wireguard'] = {
'ram': 2,
},
'wireguard': {
'network': '172.19.136.0/22',
'my_ip': '172.19.136.1/32',
'psk': vault.random_bytes_as_base64_for('ovh.icinga2 wireguard psk'),
'my_ip': '172.19.136.1/22',
'peers': {
'ovh.icinga2': {},
'home.router': {},
'kunsi-oneplus3': {
'ips': {
'172.19.136.100/32',