MEschenbacher's Wireguard Saltstack Formula
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.4KB

  1. import yaml
  2. import os
  3. from tempfile import mkstemp
  4. __virtualname__ = 'wg'
  5. def __virtual__():
  6. # do checks for startup
  7. return __virtualname__
  8. def create(name):
  9. """
  10. create a wireguard interface. This will fail if it already exists.
  11. """
  12. ifaces = __salt__['network.interfaces']()
  13. if name not in ifaces.keys():
  14. __salt__['cmd.run']('ip link add %s type wireguard' % (name,))
  15. return {name: dict(new=name, old=None)}
  16. return 'Interface %s already exists' % (name,)
  17. def delete(name):
  18. """
  19. delete a interface (not neccessarily a wireguard interface). This will fail
  20. if it does not exist.
  21. """
  22. ifaces = __salt__['network.interfaces']()
  23. if name in ifaces.keys():
  24. __salt__['cmd.run']('ip link del %s' % (name,))
  25. return {name: dict(new=None, old=name)}
  26. return 'Interface %s does not exist' % (name,)
  27. def show(name=None, peer=None, hide_keys=True):
  28. if peer and not name:
  29. return 'If peer is given, name must also be given'
  30. if not name:
  31. return _wg_ifaces(hide_keys=hide_keys)
  32. elif peer:
  33. return _wg_ifaces(hide_keys=hide_keys).get(name).get('peers').get(peer)
  34. else:
  35. return _wg_ifaces(hide_keys=hide_keys).get(name)
  36. def showconf(name):
  37. return __salt__['cmd.run']('wg showconf %s' % (name,))
  38. def set(name, listen_port=None, fwmark=None, private_key=None, peer=None,
  39. preshared_key=None, endpoint=None, persistent_keepalive=None,
  40. allowed_ips=None, remove=False):
  41. s = 'wg set %s' % (name,)
  42. if remove:
  43. if not peer:
  44. return 'If remove is given, peer must also be given'
  45. return __salt__['cmd.run'](
  46. '%s peer %s remove' % (s, peer)
  47. )
  48. if listen_port:
  49. s = '%s listen-port %s' % (s, listen_port)
  50. if fwmark:
  51. s = '%s fwmark %s' % (s, fwmark)
  52. if private_key:
  53. fd, filename = mkstemp(text=True)
  54. with open(filename, 'w') as f:
  55. f.write(private_key)
  56. os.close(fd)
  57. s = '%s private-key %s' % (s, filename)
  58. if peer:
  59. s = '%s peer %s' % (s, peer)
  60. if preshared_key != None:
  61. if not peer:
  62. return 'If preshared_key is given, peer must also be given'
  63. fd2, filename2 = mkstemp(text=True)
  64. with open(filename2, 'w') as f:
  65. f.write(preshared_key)
  66. os.close(fd2)
  67. s = '%s preshared-key %s' % (s, filename2)
  68. if endpoint:
  69. if not peer:
  70. return 'If endpoint is given, peer must also be given'
  71. s = '%s endpoint %s' % (s, endpoint)
  72. if persistent_keepalive is not None:
  73. if not peer:
  74. return 'If persistent_keepalive is given, peer must also be given'
  75. s = '%s persistent-keepalive %s' % (s, persistent_keepalive)
  76. if allowed_ips:
  77. if not peer:
  78. return 'If allowed_ips is given, peer must also be given'
  79. s = '%s allowed-ips %s' % (s, allowed_ips)
  80. r = __salt__['cmd.run'](s)
  81. if private_key:
  82. os.unlink(filename)
  83. if preshared_key:
  84. os.unlink(filename2)
  85. return r
  86. def remove_peer(name, peer):
  87. return __salt__['cmd.run'](
  88. 'wg set %s peer %s remove' % (name, peer)
  89. )
  90. def genkey():
  91. return __salt__['cmd.run']('wg genkey')
  92. def genpsk():
  93. return __salt__['cmd.run']('wg genpsk')
  94. def setconf(name, path):
  95. return __salt__['cmd.run']('wg setconf %s %s' % (name, path))
  96. def addconf(name, path):
  97. return __salt__['cmd.run']('wg addconf %s %s' % (name, path))
  98. def _wg_ifaces(hide_keys=True):
  99. """
  100. Parse output from 'wg show'
  101. """
  102. # from https://github.com/saltstack/salt/blob/develop/salt/modules/linux_ip.py
  103. tmp = dict()
  104. tmpiface = dict()
  105. ifaces = dict()
  106. out = __salt__['cmd.run']('wg show all',
  107. env={'WG_HIDE_KEYS': 'always' if hide_keys else 'never'})
  108. for line in out.splitlines():
  109. if line.startswith('interface: '):
  110. k, v = _wg_splitline(line)
  111. ifaces[v] = dict(peers=dict())
  112. tmpiface = ifaces[v]
  113. tmp = tmpiface
  114. elif line.startswith('peer: '):
  115. k, v = _wg_splitline(line)
  116. tmpiface['peers'][v] = dict()
  117. tmp = tmpiface['peers'][v]
  118. elif line == '':
  119. continue
  120. k, v = _wg_splitline(line)
  121. if k == 'allowed ips':
  122. tmp[k] = [ s.strip() for s in v.split(',') ]
  123. else:
  124. tmp[k] = v
  125. return ifaces
  126. def _wg_splitline(line):
  127. parts = line.split(':', 1)
  128. return parts[0].strip(), parts[1].strip()