Compare commits

..

15 commits

Author SHA1 Message Date
mwiegand
42fc425173 wip 2021-10-10 15:34:21 +02:00
mwiegand
f596f6b833 wip 2021-10-10 15:13:31 +02:00
mwiegand
7c72fbb044 wip 2021-10-10 15:02:15 +02:00
mwiegand
d87c77b441 wip 2021-10-10 14:55:57 +02:00
mwiegand
316d7db89d wip 2021-10-10 14:50:59 +02:00
mwiegand
c9eef4fc79 wip 2021-10-10 14:31:05 +02:00
mwiegand
1c9c4e0902 wip 2021-10-10 03:46:43 +02:00
mwiegand
cbaded9f8a wip 2021-10-10 01:35:12 +02:00
mwiegand
7c3c1cabf5 wip 2021-10-10 01:18:05 +02:00
mwiegand
ce7b3a0fc7 wip 2021-10-10 00:31:12 +02:00
mwiegand
cf54948abb wip 2021-10-10 00:06:28 +02:00
mwiegand
e35cdb98bb wip 2021-10-09 23:37:14 +02:00
mwiegand
d5a7a8c8cb wip 2021-10-09 22:34:08 +02:00
mwiegand
5f85594b32 wip 2021-10-09 22:15:03 +02:00
mwiegand
3eee733daf wip 2021-10-09 21:50:22 +02:00
11 changed files with 126 additions and 84 deletions

36
bin/wireguard_client_config Executable file
View file

@ -0,0 +1,36 @@
#!/usr/bin/env python3
from bundlewrap.repo import Repository
from os.path import realpath, dirname
from sys import argv
from ipaddress import ip_network, ip_interface
repo = Repository(dirname(dirname(realpath(__file__))))
server_node = repo.get_node('htz.mails')
data = server_node.metadata.get(f'wireguard/clients/{argv[1]}')
vpn_network = ip_interface(server_node.metadata.get('wireguard/my_ip')).network
allowed_ips = [
vpn_network,
ip_interface(server_node.metadata.get('network/internal/ipv4')).network,
]
for peer in server_node.metadata.get('wireguard/s2s').values():
for network in peer['allowed_ips']:
if not ip_network(network).subnet_of(vpn_network):
allowed_ips.append(ip_network(network))
print(
f'''[Interface]
PrivateKey = {repo.libs.wireguard.privkey(data['peer_id'])}
ListenPort = 51820
Address = {data['peer_ip']}
DNS = 8.8.8.8
[Peer]
PublicKey = {repo.libs.wireguard.pubkey(server_node.metadata.get('id'))}
PresharedKey = {repo.libs.wireguard.psk(data['peer_id'], server_node.metadata.get('id'))}
AllowedIPs = {', '.join(str(client_route) for client_route in sorted(allowed_ips))}
Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:51820
PersistentKeepalive = 10'''
)

View file

@ -0,0 +1,2 @@
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
dmesg -wT | grep wireguard

View file

@ -1,3 +1 @@
from ipaddress import ip_network
repo.libs.tools.require_bundle(node, 'systemd-networkd') repo.libs.tools.require_bundle(node, 'systemd-networkd')

View file

@ -3,16 +3,14 @@ from ipaddress import ip_network, ip_interface
from bundlewrap.exceptions import NoSuchNode from bundlewrap.exceptions import NoSuchNode
from bundlewrap.metadata import atomic from bundlewrap.metadata import atomic
repo.libs.wireguard.repo = repo
defaults = { defaults = {
'apt': { 'apt': {
'packages': { 'packages': {
# 'linux-headers-amd64': {},
'wireguard': { 'wireguard': {
'backports': node.os_version < (11,), 'backports': node.os_version < (11,),
# 'needs': [
# 'pkg_apt:linux-headers-amd64',
# ],
'triggers': [ 'triggers': [
'svc_systemd:systemd-networkd:restart', 'svc_systemd:systemd-networkd:restart',
], ],
@ -20,11 +18,43 @@ defaults = {
}, },
}, },
'wireguard': { 'wireguard': {
'privatekey': repo.vault.random_bytes_as_base64_for(f'{node.name} wireguard privatekey'), 's2s': {},
'clients': {},
}, },
} }
@metadata_reactor.provides(
'wireguard/s2s',
'wireguard/clients',
)
def s2s_peer_specific(metadata):
return {
'wireguard': {
's2s': {
s2s: {
'peer_id': repo.get_node(s2s).metadata.get(f'id'),
'peer_ip': repo.get_node(s2s).metadata.get(f'wireguard/my_ip'),
'endpoint': f'{repo.get_node(s2s).hostname}:51820',
'allowed_ips': [
str(ip_interface(repo.get_node(s2s).metadata.get(f'wireguard/my_ip')).network),
],
}
for s2s in metadata.get('wireguard/s2s')
},
'clients': {
client: {
'peer_id': client,
'allowed_ips': [
str(ip_interface(conf['peer_ip']).network),
],
}
for client, conf in metadata.get('wireguard/clients').items()
},
},
}
@metadata_reactor.provides( @metadata_reactor.provides(
'systemd/units', 'systemd/units',
) )
@ -36,11 +66,6 @@ def systemd_networkd_networks(metadata):
'Address': { 'Address': {
'Address': metadata.get('wireguard/my_ip'), 'Address': metadata.get('wireguard/my_ip'),
}, },
'Route': {
'Destination': str(ip_interface(metadata.get('wireguard/my_ip')).network),
'GatewayOnlink': 'yes',
'PreferredSource': str(ip_interface(metadata.get('network/internal/ipv4')).ip),
},
'Network': { 'Network': {
'DHCP': 'no', 'DHCP': 'no',
'IPForward': 'yes', 'IPForward': 'yes',
@ -48,14 +73,12 @@ def systemd_networkd_networks(metadata):
}, },
} }
for peer, config in metadata.get('wireguard/peers').items(): for peer, config in metadata.get('wireguard/s2s').items():
for route in config.get('route', []): for route in config.get('allowed_ips', []):
network.update({ network.update({
f'Route#{peer}_{route}': { f'Route#{peer}_{route}': {
'Destination': route, 'Destination': route,
'Gateway': str(ip_interface(repo.get_node(peer).metadata.get(f'wireguard/my_ip')).ip), 'Gateway': str(ip_interface(metadata.get('wireguard/my_ip')).ip),
'GatewayOnlink': 'yes',
'PreferredSource': str(ip_interface(metadata.get('network/internal/ipv4')).ip),
} }
}) })
@ -79,24 +102,25 @@ def systemd_networkd_netdevs(metadata):
'Description': 'WireGuard server', 'Description': 'WireGuard server',
}, },
'WireGuard': { 'WireGuard': {
'PrivateKey': metadata.get('wireguard/privatekey'), 'PrivateKey': repo.libs.wireguard.privkey(metadata.get('id')),
'ListenPort': 51820, 'ListenPort': 51820,
}, },
} }
for peer, config in metadata.get('wireguard/peers').items(): for peer, config in {
**metadata.get('wireguard/s2s'),
**metadata.get('wireguard/clients'),
}.items():
netdev.update({ netdev.update({
f'WireGuardPeer#{peer}': { f'WireGuardPeer#{peer}': {
'Endpoint': config['endpoint'], 'PublicKey': repo.libs.wireguard.pubkey(config['peer_id']),
'PublicKey': config['pubkey'], 'PresharedKey': repo.libs.wireguard.psk(config['peer_id'], metadata.get('id')),
'PresharedKey': config['psk'], 'AllowedIPs': ', '.join(config.get('allowed_ips', [])),
'AllowedIPs': ', '.join([
str(ip_interface(repo.get_node(peer).metadata.get(f'wireguard/my_ip')).ip),
*config.get('route', []),
]), # FIXME
'PersistentKeepalive': 30, 'PersistentKeepalive': 30,
} }
}) })
if config.get('endpoint'):
netdev[f'WireGuardPeer#{peer}']['Endpoint'] = config['endpoint']
return { return {
'systemd': { 'systemd': {
@ -105,33 +129,3 @@ def systemd_networkd_netdevs(metadata):
}, },
}, },
} }
@metadata_reactor.provides(
'wireguard/peers',
)
def peer_keys(metadata):
peers = {}
for peer_name in metadata.get('wireguard/peers', {}):
peer_node = repo.get_node(peer_name)
first, second = sorted([node.metadata.get('id'), peer_node.metadata.get('id')])
psk = repo.vault.random_bytes_as_base64_for(f'{first} wireguard {second}')
pubkey = repo.libs.keys.get_pubkey_from_privkey(
f'{peer_name} wireguard pubkey',
peer_node.metadata.get('wireguard/privatekey'),
)
peers[peer_name] = {
'psk': psk,
'pubkey': pubkey,
'endpoint': f'{peer_node.hostname}:51820',
}
return {
'wireguard': {
'peers': peers,
},
}

View file

@ -1,15 +0,0 @@
import base64
from nacl.public import PrivateKey
from nacl.encoding import Base64Encoder
from bundlewrap.utils import Fault
def gen_privkey(repo, identifier):
return repo.vault.random_bytes_as_base64_for(identifier)
def get_pubkey_from_privkey(identifier, privkey):
# FIXME this assumes the privkey is always a base64 encoded string
def derive_pubkey():
pub_key = PrivateKey(base64.b64decode(str(privkey))).public_key
return pub_key.encode(encoder=Base64Encoder).decode('ascii')
return Fault(f'pubkey from privkey {identifier}', derive_pubkey)

16
libs/wireguard.py Normal file
View file

@ -0,0 +1,16 @@
import base64
from nacl.public import PrivateKey
from nacl.encoding import Base64Encoder
from functools import cache
@cache
def privkey(id):
return str(repo.vault.random_bytes_as_base64_for(f"wireguard privkey {id}"))
@cache
def pubkey(id):
return PrivateKey(base64.b64decode(privkey(id))).public_key.encode(encoder=Base64Encoder).decode('ascii')
@cache
def psk(id1, id2):
return repo.vault.random_bytes_as_base64_for(f"wireguard psk {' '.join(sorted([id1, id2]))}")

View file

@ -58,10 +58,10 @@
'ram': 16192, 'ram': 16192,
}, },
'wireguard': { 'wireguard': {
'my_ip': '172.30.0.2/24', 'my_ip': '172.30.0.2/32',
'peers': { 's2s': {
'htz.mails': { 'htz.mails': {
'route': [ 'allowed_ips': [
'10.0.10.0/24', '10.0.10.0/24',
'10.0.11.0/24', '10.0.11.0/24',
'10.0.20.0/24', '10.0.20.0/24',

View file

@ -141,25 +141,36 @@
}, },
'wireguard': { 'wireguard': {
'my_ip': '172.30.0.1/24', 'my_ip': '172.30.0.1/24',
'peers': { 's2s': {
'home.server': { 'home.server': {
'route': [ 'allowed_ips': [
'10.0.0.0/24', '10.0.0.0/24',
'10.0.2.0/24', '10.0.2.0/24',
'10.0.9.0/24', '10.0.9.0/24',
], ],
}, },
'netcup.secondary': { 'netcup.secondary': {
'route': [ 'allowed_ips': [
'10.0.11.0/24', '10.0.11.0/24',
], ],
}, },
'wb.offsite-backups': { 'wb.offsite-backups': {
'route': [ 'allowed_ips': [
'192.168.178.0/24', '192.168.178.0/24',
], ],
}, },
}, },
'clients': {
'macbook': {
'peer_ip': '172.30.0.100/32',
},
'phone': {
'peer_ip': '172.30.0.101/32',
},
'ipad': {
'peer_ip': '172.30.0.102/32',
},
},
}, },
'zfs': { 'zfs': {
'pools': { 'pools': {

View file

@ -31,10 +31,10 @@
# 'hostname': 'mail2.sublimity.de', # 'hostname': 'mail2.sublimity.de',
# }, # },
'wireguard': { 'wireguard': {
'my_ip': '172.30.0.3/24', 'my_ip': '172.30.0.3/32',
'peers': { 's2s': {
'htz.mails': { 'htz.mails': {
'route': [ 'allowed_ips': [
'10.0.0.0/24', '10.0.0.0/24',
'10.0.2.0/24', '10.0.2.0/24',
'10.0.9.0/24', '10.0.9.0/24',

View file

@ -22,10 +22,10 @@
}, },
}, },
'wireguard': { 'wireguard': {
'my_ip': '172.30.0.4/24', 'my_ip': '172.30.0.4/32',
'peers': { 's2s': {
'htz.mails': { 'htz.mails': {
'route': [ 'allowed_ips': [
'10.0.0.0/24', '10.0.0.0/24',
'10.0.2.0/24', '10.0.2.0/24',
'10.0.9.0/24', '10.0.9.0/24',