Skip to content

Commit

Permalink
[wireguard]: T1572 - Wireguard keyPair per interface
Browse files Browse the repository at this point in the history
  - param key location added in op-mode script
  - param delkey and listkey implemented in op-mode script
  - param delkey implemented in op-mode script
  - generate and store named keys
  - interface implementation tu use cli option
    'private-key'
  • Loading branch information
hagbard-01 committed Sep 10, 2019
1 parent f745636 commit 1017c81
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 73 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -42,6 +42,7 @@ op_mode_definitions:
rm -f $(OP_TMPL_DIR)/generate/node.def
rm -f $(OP_TMPL_DIR)/show/vpn/node.def
rm -f $(OP_TMPL_DIR)/show/system/node.def
rm -f $(OP_TMPL_DIR)/delete/node.def

.PHONY: all
all: clean interface_definitions op_mode_definitions
Expand Down
8 changes: 8 additions & 0 deletions interface-definitions/interfaces-wireguard.xml
Expand Up @@ -77,6 +77,14 @@
</constraint>
</properties>
</leafNode>
<leafNode name="private-key">
<properties>
<help>Private key to use on that interface</help>
<completionHelp>
<script>${vyos_op_scripts_dir}/wireguard.py --listkdir</script>
</completionHelp>
</properties>
</leafNode>
<tagNode name="peer">
<properties>
<help>peer alias</help>
Expand Down
53 changes: 52 additions & 1 deletion op-mode-definitions/wireguard.xml
Expand Up @@ -20,6 +20,12 @@
</properties>
<command>${vyos_op_scripts_dir}/wireguard.py --genpsk</command>
</leafNode>
<tagNode name="named-keypairs">
<properties>
<help>Generates named wireguard keypairs</help>
</properties>
<command>sudo ${vyos_op_scripts_dir}/wireguard.py --genkey --location "$4"</command>
</tagNode>
</children>
</node>
</children>
Expand All @@ -33,7 +39,7 @@
<children>
<leafNode name="pubkey">
<properties>
<help>show wireguard public key</help>
<help>Show wireguard public key</help>
</properties>
<command>${vyos_op_scripts_dir}/wireguard.py --showpub</command>
</leafNode>
Expand All @@ -43,6 +49,31 @@
</properties>
<command>${vyos_op_scripts_dir}/wireguard.py --showpriv</command>
</leafNode>
<node name="named-keypairs">
<properties>
<help>Shows named wireguard keys</help>
</properties>
<children>
<tagNode name="pubkey">
<properties>
<help>Show wireguard private named key</help>
<completionHelp>
<script>${vyos_op_scripts_dir}/wireguard.py --listkdir</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/wireguard.py --showpub --location "$5"</command>
</tagNode>
<tagNode name="privkey">
<properties>
<help>Show wireguard public named key</help>
<completionHelp>
<script>${vyos_op_scripts_dir}/wireguard.py --listkdir</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/wireguard.py --showpriv --location "$5"</command>
</tagNode>
</children>
</node>
</children>
</node>
<node name="interfaces">
Expand Down Expand Up @@ -81,5 +112,25 @@
</node>
</children>
</node>
<node name="delete">
<children>
<node name="wireguard">
<properties>
<help>Delete wireguard properties</help>
</properties>
<children>
<tagNode name="named-keypair">
<properties>
<help>Delete wireguard named keypair</help>
<completionHelp>
<script>${vyos_op_scripts_dir}/wireguard.py --listkdir</script>
</completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/wireguard.py --delkdir --location "$4"</command>
</tagNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>

11 changes: 9 additions & 2 deletions src/conf_mode/interface-wireguard.py
Expand Up @@ -29,6 +29,9 @@
ifname = str(os.environ['VYOS_TAGNODE_VALUE'])
intfc = WireGuardIf(ifname)

kdir = r'/config/auth/wireguard'


def check_kmod():
if not os.path.exists('/sys/module/wireguard'):
sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
Expand All @@ -52,7 +55,7 @@ def get_config():
'fwmark': 0x00,
'mtu': 1420,
'peer': {},
'pk' : '/config/auth/wireguard/private.key'
'pk': '{}/private.key'.format(kdir)
}
}

Expand All @@ -77,6 +80,9 @@ def get_config():
ifname + ' description')
if c.exists(ifname + ' mtu'):
config_data[ifname]['mtu'] = c.return_value(ifname + ' mtu')
if c.exists(ifname + ' private-key'):
config_data[ifname]['pk'] = "{0}/{1}/private.key".format(
kdir, c.return_value(ifname + ' private-key'))
if c.exists(ifname + ' peer'):
for p in c.list_nodes(ifname + ' peer'):
if not c.exists(ifname + ' peer ' + p + ' disable'):
Expand Down Expand Up @@ -107,13 +113,14 @@ def get_config():

return config_data


def verify(c):
if not c:
return None

if not os.path.exists(c[ifname]['pk']):
raise ConfigError(
"No keys found, generate them by executing: \'run generate wireguard keypair\'")
"No keys found, generate them by executing: \'run generate wireguard [keypair|named-keypairs]\'")

if c[ifname]['status'] != 'delete':
if not c[ifname]['addr']:
Expand Down
188 changes: 118 additions & 70 deletions src/op_mode/wireguard.py
Expand Up @@ -19,91 +19,139 @@
import argparse
import os
import sys
import shutil
import subprocess
import syslog as sl


from vyos import ConfigError

dir = r'/config/auth/wireguard'
pk = dir + '/private.key'
pub = dir + '/public.key'
psk = dir + '/preshared.key'


def check_kmod():
""" check if kmod is loaded, if not load it """
if not os.path.exists('/sys/module/wireguard'):
sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
if os.system('sudo modprobe wireguard') != 0:
sl.syslog(sl.LOG_ERR, "modprobe wireguard failed")
raise ConfigError("modprobe wireguard failed")

def generate_keypair():
""" generates a keypair which is stored in /config/auth/wireguard """
ret = subprocess.call(['wg genkey | tee ' + pk + '|wg pubkey > ' + pub], shell=True)
if ret != 0:
raise ConfigError("wireguard key-pair generation failed")
else:
sl.syslog(sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir)

def genkey():
""" helper function to check, regenerate the keypair """
old_umask = os.umask(0o077)
if os.path.exists(pk) and os.path.exists(pub):
try:
choice = input("You already have a wireguard key-pair already, do you want to re-generate? [y/n] ")
if choice == 'y' or choice == 'Y':
generate_keypair()
except KeyboardInterrupt:
sys.exit(0)
else:
""" if keypair is bing executed from a running iso """
if not os.path.exists(dir):
os.umask(old_umask)
subprocess.call(['sudo mkdir -p ' + dir], shell=True)
subprocess.call(['sudo chgrp vyattacfg ' + dir], shell=True)
subprocess.call(['sudo chmod 770 ' + dir], shell=True)
generate_keypair()
os.umask(old_umask)
""" check if kmod is loaded, if not load it """
if not os.path.exists('/sys/module/wireguard'):
sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
if os.system('sudo modprobe wireguard') != 0:
sl.syslog(sl.LOG_ERR, "modprobe wireguard failed")
raise ConfigError("modprobe wireguard failed")

def showkey(key):
""" helper function to show privkey or pubkey """
if key == "pub":
if os.path.exists(pub):
print ( open(pub).read().strip() )

def generate_keypair(pk, pub):
""" generates a keypair which is stored in /config/auth/wireguard """
old_umask = os.umask(0o027)
ret = subprocess.call(
['wg genkey | tee ' + pk + '|wg pubkey > ' + pub], shell=True)
if ret != 0:
raise ConfigError("wireguard key-pair generation failed")
else:
print("no public key found")
sl.syslog(
sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir)
os.umask(old_umask)

if key == "pk":
if os.path.exists(pk):
print ( open(pk).read().strip() )

def genkey(location):
""" helper function to check, regenerate the keypair """
pk = "{}/private.key".format(location)
pub = "{}/public.key".format(location)
old_umask = os.umask(0o027)
if os.path.exists(pk) and os.path.exists(pub):
try:
choice = input(
"You already have a wireguard key-pair, do you want to re-generate? [y/n] ")
if choice == 'y' or choice == 'Y':
generate_keypair(pk, pub)
except KeyboardInterrupt:
sys.exit(0)
else:
""" if keypair is bing executed from a running iso """
if not os.path.exists(location):
subprocess.call(['sudo mkdir -p ' + location], shell=True)
subprocess.call(['sudo chgrp vyattacfg ' + location], shell=True)
subprocess.call(['sudo chmod 750 ' + location], shell=True)
generate_keypair(pk, pub)
os.umask(old_umask)


def showkey(key):
""" helper function to show privkey or pubkey """
if os.path.exists(key):
print (open(key).read().strip())
else:
print("no private key found")
print ("{} not found".format(key))


def genpsk():
""" generates a preshared key and shows it on stdout, it's stroed only in the config """
subprocess.call(['wg genpsk'], shell=True)
"""
generates a preshared key and shows it on stdout,
it's stored only in the cli config
"""

subprocess.call(['wg genpsk'], shell=True)


def list_key_dirs():
""" lists all dirs under /config/auth/wireguard """
if os.path.exists(dir):
nks = next(os.walk(dir))[1]
for nk in nks:
print (nk)


def del_key_dir(kname):
""" deletes /config/auth/wireguard/<kname> """
kdir = "{0}/{1}".format(dir, kname)
if not os.path.isdir(kdir):
print ("named keypair {} not found".format(kname))
return 1
shutil.rmtree(kdir)


if __name__ == '__main__':
check_kmod()

parser = argparse.ArgumentParser(description='wireguard key management')
parser.add_argument('--genkey', action="store_true", help='generate key-pair')
parser.add_argument('--showpub', action="store_true", help='shows public key')
parser.add_argument('--showpriv', action="store_true", help='shows private key')
parser.add_argument('--genpsk', action="store_true", help='generates preshared-key')
args = parser.parse_args()

try:
if args.genkey:
genkey()
if args.showpub:
showkey("pub")
if args.showpriv:
showkey("pk")
if args.genpsk:
genpsk()

except ConfigError as e:
print(e)
sys.exit(1)
check_kmod()
parser = argparse.ArgumentParser(description='wireguard key management')
parser.add_argument(
'--genkey', action="store_true", help='generate key-pair')
parser.add_argument(
'--showpub', action="store_true", help='shows public key')
parser.add_argument(
'--showpriv', action="store_true", help='shows private key')
parser.add_argument(
'--genpsk', action="store_true", help='generates preshared-key')
parser.add_argument(
'--location', action="store", help='key location within {}'.format(dir))
parser.add_argument(
'--listkdir', action="store_true", help='lists named keydirectories')
parser.add_argument(
'--delkdir', action="store_true", help='removes named keydirectories')
args = parser.parse_args()

try:
if args.genkey:
if args.location:
genkey("{0}/{1}".format(dir, args.location))
else:
genkey(dir)

if args.showpub:
if args.location:
showkey("{0}/{1}/public.key".format(dir, args.location))
else:
showkey("{}/public.key".format(dir))
if args.showpriv:
if args.location:
showkey("{0}/{1}/private.key".format(dir, args.location))
else:
showkey("{}/private".format(dir))
if args.genpsk:
genpsk()
if args.listkdir:
list_key_dirs()
if args.delkdir:
del_key_dir(args.location)

except ConfigError as e:
print(e)
sys.exit(1)

0 comments on commit 1017c81

Please sign in to comment.