summaryrefslogtreecommitdiff
path: root/src/migration-scripts/interfaces/25-to-26
diff options
context:
space:
mode:
Diffstat (limited to 'src/migration-scripts/interfaces/25-to-26')
-rw-r--r--src/migration-scripts/interfaces/25-to-26329
1 files changed, 210 insertions, 119 deletions
diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26
index 7a4032d10..1f10e3dca 100644
--- a/src/migration-scripts/interfaces/25-to-26
+++ b/src/migration-scripts/interfaces/25-to-26
@@ -1,4 +1,4 @@
-# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,7 @@ from vyos.pki import encode_dh_parameters
from vyos.pki import encode_private_key
from vyos.pki import verify_crl
from vyos.utils.process import run
+from vyos.utils.file import read_file
def wrapped_pem_to_config_value(pem):
out = []
@@ -38,20 +39,28 @@ def wrapped_pem_to_config_value(pem):
out.append(line)
return "".join(out)
-def read_file_for_pki(config_auth_path):
- full_path = os.path.join(AUTH_DIR, config_auth_path)
- output = None
+def read_auth_file(config_auth_path):
+ full_path = os.path.normpath(os.path.join(AUTH_DIR, config_auth_path))
+
+ # If the file is not found under `/config/auth`, it may be because the `/config`
+ # partition has not been bind-mounted yet during early boot migration execution.
+ # Fall back to the equivalent path under `/opt/vyatta/etc/config/auth` which
+ # is accessible at all boot stages.
+ if not os.path.isfile(full_path) and full_path.startswith(f'{AUTH_DIR}/'):
+ full_path = AUTH_DIR_FALLBACK + full_path[len(AUTH_DIR): ]
if os.path.isfile(full_path):
if not os.access(full_path, os.R_OK):
- run(f'sudo chmod 644 {full_path}')
+ run(['sudo', 'chmod', '644', full_path])
+
+ return read_file(full_path)
- with open(full_path, 'r') as f:
- output = f.read()
+ return None
- return output
AUTH_DIR = '/config/auth'
+AUTH_DIR_FALLBACK = '/opt/vyatta/etc/config/auth'
+
pki_base = ['pki']
def migrate(config: ConfigTree) -> None:
@@ -69,13 +78,30 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['openvpn', 'shared-secret'])
key_file = config.return_value(base + [interface, 'shared-secret-key-file'])
- key = read_file_for_pki(key_file)
+ key = read_auth_file(key_file)
key_pki_name = f'{pki_name}_shared'
if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
+ # Check if OpenVPN shared-secret already exists - no need to check node
+ # existence as it is always created above when entering this context
+ secret_exists = None
+ for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']):
+ secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key']
+ if not config.exists(secret_path):
+ continue
+
+ secret = config.return_value(secret_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if secret == wrapped_pem_to_config_value(key):
+ secret_exists = secret_name
+ break
+
+ if secret_exists:
+ config.set(base + [interface, 'shared-secret-key'], value=secret_exists)
+ else:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'shared-secret-key'], value=key_pki_name)
else:
print(f'Failed to migrate shared-secret-key on openvpn interface {interface}')
@@ -90,13 +116,30 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['openvpn', 'shared-secret'])
key_file = config.return_value(base + [interface, 'tls', 'auth-file'])
- key = read_file_for_pki(key_file)
+ key = read_auth_file(key_file)
key_pki_name = f'{pki_name}_auth'
if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
+ # Check if OpenVPN auth key already exists - no need to check node
+ # existence as it is always created above when entering this context
+ secret_exists = None
+ for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']):
+ secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key']
+ if not config.exists(secret_path):
+ continue
+
+ secret = config.return_value(secret_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if secret == wrapped_pem_to_config_value(key):
+ secret_exists = secret_name
+ break
+
+ if secret_exists:
+ config.set(base + [interface, 'tls', 'auth-key'], value=secret_exists)
+ else:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name)
else:
print(f'Failed to migrate auth-key on openvpn interface {interface}')
@@ -108,13 +151,30 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['openvpn', 'shared-secret'])
key_file = config.return_value(base + [interface, 'tls', 'crypt-file'])
- key = read_file_for_pki(key_file)
+ key = read_auth_file(key_file)
key_pki_name = f'{pki_name}_crypt'
if key:
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
- config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
- config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
+ # Check if OpenVPN auth key already exists - no need to check node
+ # existence as it is always created above when entering this context
+ secret_exists = None
+ for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']):
+ secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key']
+ if not config.exists(secret_path):
+ continue
+
+ secret = config.return_value(secret_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if secret == wrapped_pem_to_config_value(key):
+ secret_exists = secret_name
+ break
+
+ if secret_exists:
+ config.set(base + [interface, 'tls', 'crypt-key'], value=secret_exists)
+ else:
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key))
+ config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1')
+ config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name)
else:
print(f'Failed to migrate crypt-key on openvpn interface {interface}')
@@ -128,28 +188,41 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['ca'])
cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- certs_str = f.read()
- certs_data = certs_str.split(CERT_BEGIN)
- index = 1
- for cert_data in certs_data[1:]:
- cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
-
- if cert:
- ca_certs[f'{pki_name}_{index}'] = cert
- cert_pem = encode_certificate(cert)
+ certs_str = read_auth_file(cert_file)
+
+ if certs_str:
+ certs_data = certs_str.split(CERT_BEGIN)
+ index = 1
+ for cert_data in certs_data[1:]:
+ cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
+
+ if cert:
+ ca_certs[f'{pki_name}_{index}'] = cert
+ cert_pem = encode_certificate(cert)
+
+ # Check if CA already exists - no need to check node existence as
+ # it is always created above when entering this context
+ ca_exists = None
+ for ca_name in config.list_nodes(pki_base + ['ca']):
+ ca_cert_path = pki_base + ['ca', ca_name, 'certificate']
+ if not config.exists(ca_cert_path):
+ continue
+
+ ca_base64 = config.return_value(ca_cert_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if ca_base64 == wrapped_pem_to_config_value(cert_pem):
+ ca_exists = ca_name
+ break
+
+ if ca_exists:
+ config.set(x509_base + ['ca-certificate'], value=ca_exists, replace=False)
+ else:
config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
- else:
- print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
- index += 1
+ index += 1
else:
print(f'Failed to migrate CA certificate on openvpn interface {interface}')
@@ -161,26 +234,36 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['ca'])
crl_file = config.return_value(x509_base + ['crl-file'])
- crl_path = os.path.join(AUTH_DIR, crl_file)
- crl = None
- crl_ca_name = None
-
- if os.path.isfile(crl_path):
- if not os.access(crl_path, os.R_OK):
- run(f'sudo chmod 644 {crl_path}')
+ crl_data = read_auth_file(crl_file)
- with open(crl_path, 'r') as f:
- crl_data = f.read()
- crl = load_crl(crl_data, wrap_tags=False)
+ crl = load_crl(crl_data, wrap_tags=False) if crl_data else None
+ crl_ca_name = None
- for ca_name, ca_cert in ca_certs.items():
- if verify_crl(crl, ca_cert):
- crl_ca_name = ca_name
- break
+ if crl:
+ for ca_name, ca_cert in ca_certs.items():
+ if verify_crl(crl, ca_cert):
+ crl_ca_name = ca_name
+ break
- if crl and crl_ca_name:
+ if crl_ca_name:
crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+
+ # Check if CRL already exists - no need to check node
+ # existence as it is always created above when entering this context
+ crl_exists = None
+ for ca_name in config.list_nodes(pki_base + ['ca']):
+ crl_path = pki_base + ['ca', ca_name, 'crl']
+ if not config.exists(crl_path):
+ continue
+
+ crl_base64 = config.return_value(crl_path)
+ # Check if CRL is a duplicate and we have already imported it
+ if crl_base64 == wrapped_pem_to_config_value(crl_pem):
+ crl_exists = ca_name
+ break
+
+ if not crl_exists:
+ config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
else:
print(f'Failed to migrate CRL on openvpn interface {interface}')
@@ -192,21 +275,31 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['certificate'])
cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
+ cert_data = read_auth_file(cert_file)
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
+ cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None
if cert:
cert_pem = encode_certificate(cert)
- config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['certificate'], value=pki_name)
+ # Check if certificate public key already exists - no need to check node
+ # existence as it is always created above when entering this context
+ cert_exists = None
+ for cert_name in config.list_nodes(pki_base + ['certificate']):
+ cert_path = pki_base + ['certificate', cert_name, 'certificate']
+ if not config.exists(cert_path):
+ continue
+
+ cert_base64 = config.return_value(cert_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if cert_base64 == wrapped_pem_to_config_value(cert_pem):
+ cert_exists = cert_name
+ break
+
+ if cert_exists:
+ config.set(x509_base + ['certificate'], value=cert_exists)
+ else:
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
else:
print(f'Failed to migrate certificate on openvpn interface {interface}')
@@ -214,20 +307,28 @@ def migrate(config: ConfigTree) -> None:
if config.exists(x509_base + ['key-file']):
key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
+ key_data = read_auth_file(key_file)
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False) if key_data else None
if key:
key_pem = encode_private_key(key, passphrase=None)
- config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+ # Check if certificate public key already exists - no need to check node
+ # existence as it is always created above when entering this context
+ key_exists = None
+ for key_name in config.list_nodes(pki_base + ['certificate']):
+ key_path = pki_base + ['certificate', key_name, 'private', 'key']
+ if not config.exists(key_path):
+ continue
+
+ key_base64 = config.return_value(key_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if key_base64 == wrapped_pem_to_config_value(key_pem):
+ key_exists = key_name
+ break
+
+ if not key_exists:
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
else:
print(f'Failed to migrate private key on openvpn interface {interface}')
@@ -239,21 +340,32 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['dh'])
dh_file = config.return_value(x509_base + ['dh-file'])
- dh_path = os.path.join(AUTH_DIR, dh_file)
- dh = None
-
- if os.path.isfile(dh_path):
- if not os.access(dh_path, os.R_OK):
- run(f'sudo chmod 644 {dh_path}')
+ dh_data = read_auth_file(dh_file)
- with open(dh_path, 'r') as f:
- dh_data = f.read()
- dh = load_dh_parameters(dh_data, wrap_tags=False)
+ dh = load_dh_parameters(dh_data, wrap_tags=False) if dh_data else None
if dh:
dh_pem = encode_dh_parameters(dh)
- config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
- config.set(x509_base + ['dh-params'], value=pki_name)
+
+ # Check if DH parameters already exists - no need to check node existence
+ # as it is always created above when entering this context
+ dh_exists = None
+ for dh_name in config.list_nodes(pki_base + ['dh']):
+ dh_param_path = pki_base + ['dh', dh_name, 'parameters']
+ if not config.exists(dh_param_path):
+ continue
+
+ dh_base64 = config.return_value(dh_param_path)
+ # Check for duplicate cert/key - and re-use if possible
+ if dh_base64 == wrapped_pem_to_config_value(dh_pem):
+ dh_exists = dh_name
+ break
+
+ if dh_exists:
+ config.set(x509_base + ['dh-params'], value=dh_exists)
+ else:
+ config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem))
+ config.set(x509_base + ['dh-params'], value=pki_name)
else:
print(f'Failed to migrate DH parameters on openvpn interface {interface}')
@@ -270,15 +382,15 @@ def migrate(config: ConfigTree) -> None:
if config.exists(private_key_path):
key_file = config.return_value(private_key_path)
- full_key_path = f'/config/auth/wireguard/{key_file}/private.key'
+ full_key_path = f'{AUTH_DIR}/wireguard/{key_file}/private.key'
+ key_data = read_auth_file(full_key_path)
- if not os.path.exists(full_key_path):
+ if not key_data:
print(f'Could not find wireguard private key for migration on interface "{interface}"')
continue
- with open(full_key_path, 'r') as f:
- key_data = f.read().strip()
- config.set(private_key_path, value=key_data)
+ key_data = key_data.strip()
+ config.set(private_key_path, value=key_data)
for peer in config.list_nodes(base + [interface, 'peer']):
config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key')
@@ -300,16 +412,9 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['ca'])
cert_file = config.return_value(x509_base + ['ca-cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
-
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
+ cert_data = read_auth_file(cert_file)
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
+ cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None
if cert:
cert_pem = encode_certificate(cert)
@@ -326,16 +431,9 @@ def migrate(config: ConfigTree) -> None:
config.set_tag(pki_base + ['certificate'])
cert_file = config.return_value(x509_base + ['cert-file'])
- cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
+ cert_data = read_auth_file(cert_file)
- if os.path.isfile(cert_path):
- if not os.access(cert_path, os.R_OK):
- run(f'sudo chmod 644 {cert_path}')
-
- with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
+ cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None
if cert:
cert_pem = encode_certificate(cert)
@@ -348,16 +446,9 @@ def migrate(config: ConfigTree) -> None:
if config.exists(x509_base + ['key-file']):
key_file = config.return_value(x509_base + ['key-file'])
- key_path = os.path.join(AUTH_DIR, key_file)
- key = None
-
- if os.path.isfile(key_path):
- if not os.access(key_path, os.R_OK):
- run(f'sudo chmod 644 {key_path}')
+ key_data = read_auth_file(key_file)
- with open(key_path, 'r') as f:
- key_data = f.read()
- key = load_private_key(key_data, passphrase=None, wrap_tags=False)
+ key = load_private_key(key_data, passphrase=None, wrap_tags=False) if key_data else None
if key:
key_pem = encode_private_key(key, passphrase=None)