summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/pki.py40
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py47
-rwxr-xr-xsrc/init/vyos-router4
-rwxr-xr-xsrc/migration-scripts/dhcpv6-server/4-to-568
-rwxr-xr-xsrc/migration-scripts/ipsec/6-to-72
-rwxr-xr-xsrc/migration-scripts/rpki/1-to-222
6 files changed, 167 insertions, 16 deletions
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py
index 4be40e99e..3ab6ac5c3 100755
--- a/src/conf_mode/pki.py
+++ b/src/conf_mode/pki.py
@@ -24,11 +24,12 @@ from vyos.config import config_dict_merge
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
from vyos.configdict import node_changed
-from vyos.configdiff import Diff
from vyos.defaults import directories
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
from vyos.pki import load_public_key
+from vyos.pki import load_openssh_public_key
+from vyos.pki import load_openssh_private_key
from vyos.pki import load_private_key
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
@@ -64,6 +65,10 @@ sync_search = [
'path': ['interfaces', 'sstpc'],
},
{
+ 'keys': ['key'],
+ 'path': ['protocols', 'rpki', 'cache'],
+ },
+ {
'keys': ['certificate', 'ca_certificate', 'local_key', 'remote_key'],
'path': ['vpn', 'ipsec'],
},
@@ -86,7 +91,8 @@ sync_translate = {
'remote_key': 'key_pair',
'shared_secret_key': 'openvpn',
'auth_key': 'openvpn',
- 'crypt_key': 'openvpn'
+ 'crypt_key': 'openvpn',
+ 'key': 'openssh',
}
def certbot_delete(certificate):
@@ -150,6 +156,11 @@ def get_config(config=None):
if 'changed' not in pki: pki.update({'changed':{}})
pki['changed'].update({'key_pair' : tmp})
+ tmp = node_changed(conf, base + ['openssh'], recursive=True)
+ if tmp:
+ if 'changed' not in pki: pki.update({'changed':{}})
+ pki['changed'].update({'openssh' : tmp})
+
tmp = node_changed(conf, base + ['openvpn', 'shared-secret'], recursive=True)
if tmp:
if 'changed' not in pki: pki.update({'changed':{}})
@@ -241,6 +252,17 @@ def is_valid_private_key(raw_data, protected=False):
return True
return load_private_key(raw_data, passphrase=None, wrap_tags=True)
+def is_valid_openssh_public_key(raw_data, type):
+ # If it loads correctly we're good, or return False
+ return load_openssh_public_key(raw_data, type)
+
+def is_valid_openssh_private_key(raw_data, protected=False):
+ # If it loads correctly we're good, or return False
+ # With encrypted private keys, we always return true as we cannot ask for password to verify
+ if protected:
+ return True
+ return load_openssh_private_key(raw_data, passphrase=None, wrap_tags=True)
+
def is_valid_crl(raw_data):
# If it loads correctly we're good, or return False
return load_crl(raw_data, wrap_tags=True)
@@ -322,6 +344,20 @@ def verify(pki):
if not is_valid_private_key(private['key'], protected):
raise ConfigError(f'Invalid private key on key-pair "{name}"')
+ if 'openssh' in pki:
+ for name, key_conf in pki['openssh'].items():
+ if 'public' in key_conf and 'key' in key_conf['public']:
+ if 'type' not in key_conf['public']:
+ raise ConfigError(f'Must define OpenSSH public key type for "{name}"')
+ if not is_valid_openssh_public_key(key_conf['public']['key'], key_conf['public']['type']):
+ raise ConfigError(f'Invalid OpenSSH public key "{name}"')
+
+ if 'private' in key_conf and 'key' in key_conf['private']:
+ private = key_conf['private']
+ protected = 'password_protected' in private
+ if not is_valid_openssh_private_key(private['key'], protected):
+ raise ConfigError(f'Invalid OpenSSH private key "{name}"')
+
if 'x509' in pki:
if 'default' in pki['x509']:
default_values = pki['x509']['default']
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index 0fc14e868..a59ecf3e4 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -16,16 +16,22 @@
import os
+from glob import glob
from sys import exit
from vyos.config import Config
+from vyos.pki import wrap_openssh_public_key
+from vyos.pki import wrap_openssh_private_key
from vyos.template import render_to_string
-from vyos.utils.dict import dict_search
+from vyos.utils.dict import dict_search_args
+from vyos.utils.file import write_file
from vyos import ConfigError
from vyos import frr
from vyos import airbag
airbag.enable()
+rpki_ssh_key_base = '/run/frr/id_rpki'
+
def get_config(config=None):
if config:
conf = config
@@ -33,7 +39,8 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'rpki']
- rpki = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ rpki = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True, with_pki=True)
# Bail out early if configuration tree does not exist
if not conf.exists(base):
rpki.update({'deleted' : ''})
@@ -63,22 +70,40 @@ def verify(rpki):
preferences.append(preference)
if 'ssh' in peer_config:
- files = ['private_key_file', 'public_key_file']
- for file in files:
- if file not in peer_config['ssh']:
- raise ConfigError('RPKI+SSH requires username and public/private ' \
- 'key file to be defined!')
+ if 'username' not in peer_config['ssh']:
+ raise ConfigError('RPKI+SSH requires username to be defined!')
+
+ if 'key' not in peer_config['ssh'] or 'openssh' not in rpki['pki']:
+ raise ConfigError('RPKI+SSH requires key to be defined!')
- filename = peer_config['ssh'][file]
- if not os.path.exists(filename):
- raise ConfigError(f'RPKI SSH {file.replace("-","-")} "{filename}" does not exist!')
+ if peer_config['ssh']['key'] not in rpki['pki']['openssh']:
+ raise ConfigError('RPKI+SSH key not found on PKI subsystem!')
return None
def generate(rpki):
+ for key in glob(f'{rpki_ssh_key_base}*'):
+ os.unlink(key)
+
if not rpki:
return
+
+ if 'cache' in rpki:
+ for cache, cache_config in rpki['cache'].items():
+ if 'ssh' in cache_config:
+ key_name = cache_config['ssh']['key']
+ public_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'key')
+ public_key_type = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'type')
+ private_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'private', 'key')
+
+ cache_config['ssh']['public_key_file'] = f'{rpki_ssh_key_base}_{cache}.pub'
+ cache_config['ssh']['private_key_file'] = f'{rpki_ssh_key_base}_{cache}'
+
+ write_file(cache_config['ssh']['public_key_file'], wrap_openssh_public_key(public_key_data, public_key_type))
+ write_file(cache_config['ssh']['private_key_file'], wrap_openssh_private_key(private_key_data))
+
rpki['new_frr_config'] = render_to_string('frr/rpki.frr.j2', rpki)
+
return None
def apply(rpki):
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 2b4fac5ef..eac3e7e47 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -449,7 +449,7 @@ start ()
run_postconfig_scripts
tmp=$(${vyos_libexec_dir}/read-saved-value.py --path "protocols rpki cache")
- if [ ! -z $tmp ]; then
+ if [[ ! -z "$tmp" ]]; then
vtysh -c "rpki start"
fi
}
diff --git a/src/migration-scripts/dhcpv6-server/4-to-5 b/src/migration-scripts/dhcpv6-server/4-to-5
new file mode 100755
index 000000000..e808edbe0
--- /dev/null
+++ b/src/migration-scripts/dhcpv6-server/4-to-5
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# T5993: Check if subnet is locally accessible and assign interface to subnet
+
+import sys
+from ipaddress import ip_network
+from vyos.configtree import ConfigTree
+
+if (len(sys.argv) < 1):
+ print("Must specify file name!")
+ sys.exit(1)
+
+file_name = sys.argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['service', 'dhcpv6-server', 'shared-network-name']
+config = ConfigTree(config_file)
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+def find_subnet_interface(subnet):
+ subnet_net = ip_network(subnet)
+
+ for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ if_base = ['interfaces', iftype, ifname]
+
+ if config.exists(if_base + ['address']):
+ for addr in config.return_values(if_base + ['address']):
+ if ip_network(addr, strict=False) == subnet_net:
+ return ifname
+
+ return False
+
+for network in config.list_nodes(base):
+ if not config.exists(base + [network, 'subnet']):
+ continue
+
+ for subnet in config.list_nodes(base + [network, 'subnet']):
+ subnet_interface = find_subnet_interface(subnet)
+
+ if subnet_interface:
+ config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface)
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
index 71fbbe8a1..f8b6de560 100755
--- a/src/migration-scripts/ipsec/6-to-7
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -63,7 +63,7 @@ if config.exists(ipsec_site_base):
changes_made = True
peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509']
- pki_name = 'peer_' + peer.replace(".", "-")
+ pki_name = 'peer_' + peer.replace(".", "-").replace("@", "")
if config.exists(peer_x509_base + ['cert-file']):
cert_file = config.return_value(peer_x509_base + ['cert-file'])
diff --git a/src/migration-scripts/rpki/1-to-2 b/src/migration-scripts/rpki/1-to-2
index 559440bba..50d4a3dfc 100755
--- a/src/migration-scripts/rpki/1-to-2
+++ b/src/migration-scripts/rpki/1-to-2
@@ -19,7 +19,11 @@
from sys import exit
from sys import argv
+
from vyos.configtree import ConfigTree
+from vyos.pki import OPENSSH_KEY_BEGIN
+from vyos.pki import OPENSSH_KEY_END
+from vyos.utils.file import read_file
if len(argv) < 2:
print("Must specify file name!")
@@ -43,6 +47,24 @@ if config.exists(base + ['cache']):
if config.exists(ssh_node + ['known-hosts-file']):
config.delete(ssh_node + ['known-hosts-file'])
+ if config.exists(base + ['cache', cache, 'ssh']):
+ private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
+ private_key_file = config.return_value(private_key_node)
+ private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
+
+ public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
+ public_key_file = config.return_value(public_key_node)
+ public_key = read_file(public_key_file).split()
+
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
+ config.set_tag(['pki', 'openssh'])
+ config.set(ssh_node + ['key'], value=f'rpki-{cache}')
+
+ config.delete(private_key_node)
+ config.delete(public_key_node)
+
try:
with open(file_name, 'w') as f:
f.write(config.to_string())