Maximilian Eschenbacher před 6 roky
revize
91a21e2e40
8 změnil soubory, kde provedl 346 přidání a 0 odebrání
  1. +27
    -0
      README.md
  2. +120
    -0
      _modules/wireguard.py
  3. +120
    -0
      _states/wireguard.py
  4. +22
    -0
      pillar.example
  5. +5
    -0
      wireguard/defaults.yaml
  6. +35
    -0
      wireguard/init.sls
  7. +15
    -0
      wireguard/map.jinja
  8. +2
    -0
      wireguard/osmap.yaml

+ 27
- 0
README.md Zobrazit soubor

@@ -0,0 +1,27 @@
# wireguard-formula

currently with only `_modules` and `_states`.

# Install

Add the path to the wireguard-formula to the master configuration file under option
`file_roots` or as `gitfs_remotes`.

# Use as module

`salt-call wg.create wgtest`
`salt-call wg.show wgtest`
`salt-call wg.set interface listen_port=1337`
`salt-call wg.delete wgtest`

# Use as state

```
wgtest:
wg.present:
- listen_port: 1337

1ymBfBty05PNhD/QJKUlu4aL2p4jKSWVVqVQWIQG6wM=:
wg.peer_present:
- interface: wgtest
```

+ 120
- 0
_modules/wireguard.py Zobrazit soubor

@@ -0,0 +1,120 @@
import yaml
import os

__virtualname__ = 'wg'

def __virtual__():
# do checks for startup
return __virtualname__

def create(name):
"""
create a wireguard interface. This will fail if it already exists.
"""
__salt__['cmd.run']('ip link add %s type wireguard' % (name,))
return show(name)

def delete(name):
"""
delete a wireguard interface. This will fail if it does not exist.
"""
return __salt__['cmd.run']('ip link del %s type wireguard' % (name,))


def show(name=None, peer=None):
if peer and not name:
return 'If peer is given, name must also be given'
if not name:
return _wg_ifaces()
elif peer:
return _wg_ifaces().get(name).get('peers').get(peer)
else:
return _wg_ifaces().get(name)

def showconf(name):
return __salt__['cmd.run']('wg showconf %s' % (name,))

def set(name, listen_port=None, fwmark=None, private_key=None, peer=None,
preshared_key=None, endpoint=None, persistent_keepalive=None,
allowed_ips=None, remove=False):
s = 'wg set %s' % (name,)
if remove:
if not peer:
return 'If remove is given, peer must also be given'
return __salt__['cmd.run'](
'%s peer %s remove' % (s, peer)
)
if listen_port:
s = '%s listen-port %s' % (s, listen_port)
if fwmark:
s = '%s fwmark %s' % (s, fwmark)
if private_key:
assert os.stat(private_key)
# TODO private key must be given as file
s = '%s private-key %s' % (s, private_key)
if peer:
s = '%s peer %s' % (s, peer)
if preshared_key:
s = '%s preshared-key %s' % (s, preshared_key)
if endpoint:
s = '%s endpoint %s' % (s, endpoint)
if persistent_keepalive:
s = '%s persistent-keepalive %s' % (s, persistent_keepalive)
if allowed_ips:
s = '%s allowed-ips %s' % (s, allowed_ips)
return __salt__['cmd.run'](s)

def remove_peer(name, peer):
return __salt__['cmd.run'](
'wg set %s peer %s remove' % (name, peer)
)

# def add_peer(name, public_key, allowed_ips=None):
# base = 'wg set %s peer %s' % (name, peer)
#
# return __salt__['cmd.run'](
# )

def genkey():
return __salt__['cmd.run']('wg genkey')

def genpsk():
return __salt__['cmd.run']('wg genpsk')

def setconf(name, path):
return __salt__['cmd.run']('wg setconf %s %s' % (name, path))

def addconf(name, path):
return __salt__['cmd.run']('wg addconf %s %s' % (name, path))

def _wg_ifaces():
"""
Parse output from 'wg show'
"""
# from https://github.com/saltstack/salt/blob/develop/salt/modules/linux_ip.py
tmp = dict()
tmpiface = dict()
ifaces = dict()
out = __salt__['cmd.run']('wg', env={'WG_HIDE_KEYS': 'never'})
for line in out.splitlines():
if line.startswith('interface: '):
k, v = _wg_splitline(line)
ifaces[v] = dict(peers=dict())
tmpiface = ifaces[v]
tmp = tmpiface
elif line.startswith('peer: '):
k, v = _wg_splitline(line)
tmpiface['peers'][v] = dict()
tmp = tmpiface['peers'][v]
elif line == '':
continue
k, v = _wg_splitline(line)
if k == 'allowed ips':
tmp[k] = [ s.strip() for s in v.split(',') ]
else:
tmp[k] = v
return ifaces

def _wg_splitline(line):
parts = line.split(':', 1)
return parts[0].strip(), parts[1].strip()

+ 120
- 0
_states/wireguard.py Zobrazit soubor

@@ -0,0 +1,120 @@
__virtualname__ = 'wg'

def __virtual__():
if 'wg.show' in __salt__:
return __virtualname__
return False


def present(name, listen_port=None, fwmark=None, private_key=None,
preshared_key=None):
"""
Make sure a wireguard interface exists.
"""

ret = dict(name=name, changes=dict(), result=False, comment=None)

interface = __salt__['wg.show'](name)
if not interface:
interface = __salt__['wg.create'](name)
ret['changes'][name] = 'Interface created.'

show = __salt__['wg.show'](name)

if int(show.get('listening port', 0)) != int(listen_port):
__salt__['wg.set'](name, listen_port=listen_port)
ret['changes']['listening port'] = dict(
old=show.get('listening port', 0),
new=listen_port,
)

if show.get('fwmark', None) != fwmark:
__salt__['wg.set'](name, fwmark=fwmark)
ret['changes']['fwmark'] = dict(
old=show.get('fwmark', None),
new=fwmark,
)

if show.get('private key') != private_key:
__salt__['wg.set'](name, private_key=private_key)
ret['changes']['private key'] = 'private key changed.'

if show.get('preshared key') != preshared_key:
__salt__['wg.set'](name, preshared_key=preshared_key)
ret['changes']['preshared key'] = 'preshared key changed.'

ret['result'] = True

return ret


def absent(name):
"""
Make sure a wireguard interface is absent.
"""

ret = dict(name=name, changes=dict(), result=False, comment=None)

interface = __salt__['wg.show'](name)
if not interface:
ret['comment'] = 'Interface %s already absent.' % (name,)
ret['result'] = True
return ret

__salt__['wg.delete'](name)
ret['changes'][name] = dict(old=name, new=None)
ret['result'] = True
return ret


def peer_present(name, interface, endpoint=None, persistent_keepalive=None,
allowed_ips=None):
ret = dict(name=name, changes=dict(), result=False, comment=None)

show = __salt__['wg.show'](interface)
if not show:
ret['comment'] = 'Interface %s does not exist.' % (interface)
return ret

show = __salt__['wg.show'](name=interface, peer=name)
if not show:
__salt__['wg.set'](interface, peer=name, endpoint=endpoint,
persistent_keepalive=persistent_keepalive,
allowed_ips=','.join(allowed_ips))
ret['changes'][name] = 'Peer created.'
ret['result'] = True
return ret

if show.get('endpoint') != endpoint:
__salt__['wg.set'](interface, peer=name, endpoint=endpoint)
ret['changes']['endpoint'] = 'Endpoint changed.'

if show.get('persistent keepalive', None) != persistent_keepalive:
__salt__['wg.set'](interface, peer=name,
persistent_keepalive=persistent_keepalive)
ret['changes']['persistent keepalive'] = 'persistent keepalive changed.'

ret['result'] = True

return ret


def peer_absent(name, interface):

ret = dict(name=name, changes=dict(), result=False, comment=None)

show = __salt__['wg.show'](interface)
if not show:
ret['comment'] = 'Interface %s does not exist.' % (interface)
return ret

show = __salt__['wg.show'](name=interface, peer=name)
if not show:
ret['comment'] = 'Peer %s already absent.' % (name)
ret['result'] = True
return ret

__salt__['wg.set'](interface, peer=name, remove=True)
ret['changes'][name] = dict(old=name, new=None)
ret['result'] = True
return ret

+ 22
- 0
pillar.example Zobrazit soubor

@@ -0,0 +1,22 @@
wireguard:
interfaces:
wgtest:
listen_port: 1337
fwmark: 0x1
private_key: secret
preshared_key: secret
peers:
wgtest:
-
peer: 1ymBfBty05PNhD/QJKUlu4aL2p4jKSWVVqVQWIQG6wM=
endpoint: '127.0.0.1:1338'
allowed_ips:
- 10.0.0.2/32
- 'fdff::2/128'
persistent_keepalive: 25
-
peer: 2ymBfBty05PNhD/QJKUlu4aL2p4jKSWVVqVQWIQG6wM=
endpoint: '127.0.0.1:1339'
allowed_ips:
- 10.0.0.3/32
- 'fdff::3/128'

+ 5
- 0
wireguard/defaults.yaml Zobrazit soubor

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# vim: ft=yaml

wireguard:
package: wireguard

+ 35
- 0
wireguard/init.sls Zobrazit soubor

@@ -0,0 +1,35 @@
{% from "wireguard/map.jinja" import wireguard with context %}

wireguard:
pkg.installed:
- name: {{ wireguard.package }}

{% for name, values in salt['pillar.get']('wireguard:interfaces', {}).items() %}
wireguard_{{ name }}:
wg.present:
- name: {{ name }}
{% for k, v in values.items() %}
- {{k}}: {{v}}
{% endfor %}
{% endfor %}

{% for interface, peerlist in salt['pillar.get']('wireguard:peers', {}).items() %}
{% for peer in peerlist %}
wireguard_{{ interface }}_peer_{{ peer.get('peer') }}:
wg.peer_present:
- interface: {{ interface }}
- name: {{ peer.get('peer') }}
{% if peer.get('endpoint') != None %}
- endpoint: {{ peer.get('endpoint') }}
{% endif %}
{% if peer.get('persistent_keepalive') != None %}
- persistent_keepalive: {{ peer.get('persistent_keepalive') }}
{% endif %}
{% if peer.get('allowed_ips') != None %}
- allowed_ips:
{% for subnet in peer.get('allowed_ips', []) %}
- {{subnet}}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

+ 15
- 0
wireguard/map.jinja Zobrazit soubor

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# vim: ft=jinja

{% import_yaml "wireguard/defaults.yaml" as defaults %}
{% import_yaml "wireguard/osmap.yaml" as osmap %}

{% set wireguard = salt['grains.filter_by'](
defaults,
merge=salt['grains.filter_by'](
osmap,
grain='os',
merge=salt['pillar.get']('wireguard:lookup', {}),
),
base='wireguard')
%}

+ 2
- 0
wireguard/osmap.yaml Zobrazit soubor

@@ -0,0 +1,2 @@
Debian:
foo: bar

Načítá se…
Zrušit
Uložit