changeset 5:7e8c7de5b490

port wireguard setup
author drewp@bigasterisk.com
date Wed, 10 Nov 2021 09:51:54 -0800
parents 53ab69ba2d07
children aa633eb49c63
files inventory.py tasks.py templates/wireguard_bogasterisk.conf.j2 templates/wireguard_wg0.conf.j2 wireguard.py
diffstat 5 files changed, 135 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/inventory.py	Wed Nov 10 09:50:31 2021 -0800
+++ b/inventory.py	Wed Nov 10 09:51:54 2021 -0800
@@ -2,11 +2,37 @@
 ssh_key = '/root/.ssh/id_ecdsa'
 
 big = [
-    'bang',
-    'dash',
-    'slash',
+    ('bang', {
+        'wireguard_address': '10.5.0.1'
+    }),
+    ('dash', {
+        'interface': 'enp2s0',
+        'addr': '10.1.0.5',
+        'wireguard_address': '10.5.0.5'
+    }),
+    ('slash', {
+        'interface': 'enp3s0',
+        'addr': '10.1.0.6',
+        'wireguard_address': '10.5.0.6'
+    }),
 ]
 pi = [
-    'frontbed',
-    ('garage', {'ssh_hostname': '10.2.0.19'}),
+    ('frontbed', {
+        'interface': 'eth0',
+        'addr': '10.2.0.17',
+        'wireguard_address': '10.5.0.17'
+    }),
+    ('garage', {
+        'ssh_hostname': '10.2.0.19',
+        'interface': 'eth0',
+        'addr': '10.2.0.14',
+        'wireguard_address': '10.5.0.14'
+    }),
 ]
+
+remote = [
+    ('prime', {
+        'ssh_hostname': 'public.bigasterisk.com',
+        'wireguard_address': '10.5.0.2'
+    }),
+]
--- a/tasks.py	Wed Nov 10 09:50:31 2021 -0800
+++ b/tasks.py	Wed Nov 10 09:51:54 2021 -0800
@@ -7,14 +7,22 @@
 cd /my/proj/infra
 env/bin/pyinfra '''
 
+
 @task
 def users(ctx):
     ctx.run(cmd + 'inventory.py users.py', pty=True)
 
+
 @task
 def system(ctx):
     ctx.run(cmd + 'inventory.py system.py', pty=True)
 
+
+@task
+def wireguard(ctx):
+    ctx.run(cmd + 'inventory.py wireguard.py', pty=True)
+
+
 @task
 def get_fact(ctx, host='dash', fact='server.LinuxDistribution'):
     ctx.run(cmd + f'{host} fact {fact}', pty=True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/wireguard_bogasterisk.conf.j2	Wed Nov 10 09:51:54 2021 -0800
@@ -0,0 +1,12 @@
+# written by pyinfra
+
+[Interface]
+# {{ host.name }}
+Address = 10.7.0.2/16
+PrivateKey = {{priv_key}}
+ListenPort = 2113
+
+{{ peer_block('monk',             'aroc8MNdTnKg175HYxri+Yr1afuaC0awyr6TfGMpvxI=', '10.7.0.42/32') }}
+{{ peer_block('firebert (phone)', 'Rr9N6dGbMLzl6wuEJlaq67gNQ5QW2ZcwD4Brn/3XJyA=', '10.7.0.88/32') }}
+{{ peer_block('bird',             '9CkgqeAiX1GhNM+t9m2nJD5QJHx9iTCFRB5c1x7h704=', '10.7.0.46/32') }}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/wireguard_wg0.conf.j2	Wed Nov 10 09:51:54 2021 -0800
@@ -0,0 +1,25 @@
+# written by pyinfra
+
+[Interface]
+# {{ host.name }}
+Address = {{wireguard_ip}}/24
+PrivateKey = {{priv_key}}
+ListenPort = 1195
+
+{% if host.name == 'bang' %}
+    {{ peer_block('dash',        'X39ewB2uYLZTFaG+RFeLpyOrnCgjc4wRKrcV0Jz3sTM=', '10.5.0.5/32',  'dash:1195') }}
+    {{ peer_block('dot',         'sav1VQE1XzbOGfNjDRxcHAmEWtmVGYC1B7KXH+5IKxY=', '10.5.0.30/32', 'dot:1195') }}
+    {{ peer_block('frontbed',    'ENhRhEgGaFfwV74MqYBHJgkOFpNAF5kVHVK5/tRVTjU=', '10.5.0.17/32', 'frontbed:1195') }}
+    {{ peer_block('garage',      'x2i552K4ApoYYRUnx2HFgJRsdRWizcd4P5IqSZD5iwM=', '10.5.0.14/32', 'garage:1195') }}
+    {{ peer_block('prime',       'vR9lfsUSOIMxkY/k2gRJ6E8ZudccfPpVhrbE9zuxalU=', '10.5.0.0/24',  'public.bigasterisk.com:1195', 50) }}
+    {{ peer_block('slash',       'IRLLt2yFuXVJbpevAj9d84mGAvi6SbJr1AwLAK/pBTM=', '10.5.0.6/32',  'slash:1195') }}
+{% elif host.name == 'prime' %}
+    {{ peer_block('bang',        'pAxirNVF08R6zYyudhTKjZ9fqC9UKMxknfLi5A39QVY=', '10.5.0.0/24') }}
+    {{ peer_block('plus',        'tH2og4BbXaH6BrHSBd73Fx1XT0DxR8vjQxjqHFa913A=', '10.5.0.110/32') }}
+    {{ peer_block('drew-note10', 'QMgx4cmuUTfJ7RH4Q46b54tSQl4eISOmdEney17fnE8=', '10.5.0.112/32') }}
+{% elif host.name == 'plus' %}
+    {{ peer_block('bang',        'pAxirNVF08R6zYyudhTKjZ9fqC9UKMxknfLi5A39QVY=', '10.5.0.0/24', '10.1.0.1:1195', 50) }}
+{% else %}
+    {{ peer_block('bang',        'pAxirNVF08R6zYyudhTKjZ9fqC9UKMxknfLi5A39QVY=', '10.5.0.0/24', '10.1.0.1:1195', 50) }}
+{% endif %}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wireguard.py	Wed Nov 10 09:51:54 2021 -0800
@@ -0,0 +1,59 @@
+import subprocess
+
+from pyinfra import host
+from pyinfra.facts.files import FindInFile
+from pyinfra.operations import apt, files, systemd
+
+# other options:
+#   https://www.reddit.com/r/WireGuard/comments/fkr240/shortest_path_between_peers/
+#   https://github.com/k4yt3x/wireguard-mesh-configurator
+#   https://github.com/mawalu/wireguard-private-networking
+#
+
+
+def peer_block(hostname, public_key, allowed_ips, endpoint=None, keepalive=None):
+    out = f'''\
+
+[Peer]
+# {hostname}
+PublicKey = {public_key}
+AllowedIPs = {allowed_ips}
+'''
+    if endpoint is not None:
+        out += f'Endpoint = {endpoint}\n'
+    if keepalive is not None:
+        out += f'PersistentKeepalive = {keepalive}\n'
+    return out
+
+
+for wireguard_interface in ['wg0', 'bogasterisk']:
+    if wireguard_interface == 'bogasterisk' and host.name != 'prime':
+        continue
+
+    # note- this is specific to the wg0 setup. Other conf files don't use it.
+    wireguard_ip = host.host_data['wireguard_address']
+
+    apt.packages(packages=['wireguard'])
+    # new pi may fail with 'Unable to access interface: Protocol not supported'. reboot fixes.
+
+    priv_key_lines = host.get_fact(FindInFile, path=f'/etc/wireguard/{wireguard_interface}.conf', pattern=r'PrivateKey.*')
+    if not priv_key_lines:
+        priv_key = subprocess.check_output(['wg', 'genkey']).strip().decode('ascii')
+    else:
+        priv_key = priv_key_lines[0].split(' = ')[1]
+
+    pub_key = subprocess.check_output(['wg', 'pubkey'], input=priv_key.encode('ascii')).strip().decode('ascii')
+    # todo: if this was new, it should be added to a file of pubkeys that peer_block can refer to
+
+    files.template(
+        src=f'templates/wireguard_{wireguard_interface}.conf.j2',
+        dest=f'/etc/wireguard/{wireguard_interface}.conf',
+        mode='600',
+        wireguard_ip=wireguard_ip,
+        priv_key=priv_key,
+        peer_block=peer_block,
+    )
+    svc = f'wg-quick@{wireguard_interface}.service'
+    files.link(path=f'/etc/systemd/system/multi-user.target.wants/{svc}', target='/lib/systemd/system/wg-quick@.service')
+
+    systemd.service(service=svc, daemon_reload=True, running=True, enabled=True)