diff options
-rw-r--r-- | cloudinit/config/cc_vyos.py | 62 |
1 files changed, 39 insertions, 23 deletions
diff --git a/cloudinit/config/cc_vyos.py b/cloudinit/config/cc_vyos.py index e51ed7f2..6a1991d5 100644 --- a/cloudinit/config/cc_vyos.py +++ b/cloudinit/config/cc_vyos.py @@ -22,8 +22,6 @@ import os import re -import sys -import ast import ipaddress from cloudinit import stages @@ -31,7 +29,6 @@ from cloudinit import util from cloudinit.distros import ug_util from cloudinit.settings import PER_INSTANCE -from cloudinit import handlers from cloudinit import log as logging from vyos.configtree import ConfigTree @@ -42,12 +39,14 @@ logger.setLevel(logging.DEBUG) frequency = PER_INSTANCE + class VyosError(Exception): """Raised when the distro runs into an exception when setting vyos config. This may happen when the ssh pub key format is wrong. """ pass + # configure user account with password def set_pass_login(config, user, password, encrypted_pass): if encrypted_pass: @@ -57,13 +56,14 @@ def set_pass_login(config, user, password, encrypted_pass): config.set_tag(['system', 'login', 'user']) + # configure user account with ssh key def set_ssh_login(config, user, key_string, key_x): key_type = None key_data = None key_name = None - if key_string == '': + if key_string == '': logger.error("No keys found.") return @@ -74,7 +74,7 @@ def set_ssh_login(config, user, key_string, key_x): key_type = key if key.startswith('AAAAB3NzaC1yc2E') or key.startswith('AAAAB3NzaC1kc3M'): - key_data = key + key_data = key if not key_type: logger.error("Key type not defined, wrong ssh key format.") @@ -92,15 +92,31 @@ def set_ssh_login(config, user, key_string, key_x): else: key_name = "cloud-init-%s" % key_x - config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name , 'key'], value=key_data, replace=True) - config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name , 'type'], value=key_type, replace=True) + config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name, 'key'], value=key_data, replace=True) + config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name, 'type'], value=key_type, replace=True) config.set_tag(['system', 'login', 'user']) config.set_tag(['system', 'login', 'user', user, 'authentication', 'public-keys']) +# filter hostname to be sure that it can be applied +# NOTE: here we cannot attempt to deny anything prohibited, as it is too late. +# Therefore, we need only pass what is allowed, cutting everything else +def hostname_filter(hostname): + # define regex for alloweed characters and resulted hostname + regex_characters = re.compile(r'[a-z0-9.-]', re.IGNORECASE) + regex_hostname = re.compile(r'[a-z0-9](([a-z0-9-]\.|[a-z0-9-])*[a-z0-9])?', re.IGNORECASE) + # filter characters + filtered_characters = ''.join(regex_characters.findall(hostname)) + # check that hostname start and end by allowed characters and cut unsupported ones, limit to 64 characters total + filtered_hostname = regex_hostname.search(filtered_characters).group()[:64] + + # return safe to apply host-name value + return filtered_hostname + + # configure system parameters from OVF template def set_config_ovf(config, hostname, metadata): - ip_0 = metadata['ip0'] + ip_0 = metadata['ip0'] mask_0 = metadata['netmask0'] gateway = metadata['gateway'] DNS = list(metadata['DNS'].replace(' ', '').split(',')) @@ -109,8 +125,8 @@ def set_config_ovf(config, hostname, metadata): APIPORT = metadata['APIPORT'] APIDEBUG = metadata['APIDEBUG'] - if ip_0 and ip_0 != 'null' and mask_0 and mask_0 != 'null' and gateway and gateway != 'null': - cidr = str(ipaddress.IPv4Network('0.0.0.0/' + mask_0).prefixlen) + if ip_0 and ip_0 != 'null' and mask_0 and mask_0 != 'null' and gateway and gateway != 'null': + cidr = str(ipaddress.IPv4Network('0.0.0.0/' + mask_0).prefixlen) ipcidr = ip_0 + '/' + cidr config.set(['interfaces', 'ethernet', 'eth0', 'address'], value=ipcidr, replace=True) @@ -146,9 +162,9 @@ def set_config_ovf(config, hostname, metadata): config.set(['service', 'ssh'], replace=True) config.set(['service', 'ssh', 'port'], value='22', replace=True) - + if hostname and hostname != 'null': - config.set(['system', 'host-name'], value=hostname, replace=True) + config.set(['system', 'host-name'], value=hostname_filter(hostname), replace=True) else: config.set(['system', 'host-name'], value='vyos', replace=True) @@ -157,11 +173,11 @@ def set_config_ovf(config, hostname, metadata): def set_config_interfaces(config, iface_name, iface_config): # configure DHCP client if 'dhcp4' in iface_config: - if iface_config['dhcp4'] == True: + if iface_config['dhcp4'] is True: config.set(['interfaces', 'ethernet', iface_name, 'address'], value='dhcp', replace=True) config.set_tag(['interfaces', 'ethernet']) if 'dhcp6' in iface_config: - if iface_config['dhcp6'] == True: + if iface_config['dhcp6'] is True: config.set(['interfaces', 'ethernet', iface_name, 'address'], value='dhcp6', replace=True) config.set_tag(['interfaces', 'ethernet']) @@ -226,7 +242,7 @@ def set_config_ssh(config): # configure hostname def set_config_hostname(config, hostname): - config.set(['system', 'host-name'], value=hostname, replace=True) + config.set(['system', 'host-name'], value=hostname_filter(hostname), replace=True) # configure SSH, eth0 interface and hostname @@ -236,7 +252,7 @@ def set_config_cloud(config, hostname): config.set(['service', 'ssh', 'client-keepalive-interval'], value='180', replace=True) config.set(['interfaces', 'ethernet', 'eth0', 'address'], value='dhcp', replace=True) config.set_tag(['interfaces', 'ethernet']) - config.set(['system', 'host-name'], value=hostname, replace=True) + config.set(['system', 'host-name'], value=hostname_filter(hostname), replace=True) # main config handler @@ -253,7 +269,7 @@ def handle(name, cfg, cloud, log, _args): key_y = 0 # look at data that can be used for configuration - #print(dir(dc)) + # print(dir(dc)) if not os.path.exists(cfg_file_name): file_name = bak_file_name @@ -264,7 +280,7 @@ def handle(name, cfg, cloud, log, _args): config_file = f.read() config = ConfigTree(config_file) - if 'Azure' in dc.dsname: + if 'Azure' in dc.dsname: encrypted_pass = True for key, val in users.items(): user = key @@ -287,14 +303,14 @@ def handle(name, cfg, cloud, log, _args): password = util.get_cfg_option_str(cfg, 'password', None) if password and password != '': - hash = re.match("(^\$.\$)", password) + hash = re.match(r"(^\$.\$)", password) hash_count = password.count('$') if hash and hash_count >= 3: base64 = password.split('$')[3] base_64_len = len(base64) if ((hash.group(1) == '$1$' and base_64_len == 22) or - (hash.group(1) == '$5$' and base_64_len == 43) or - (hash.group(1) == '$6$' and base_64_len == 86)): + (hash.group(1) == '$5$' and base_64_len == 43) or + (hash.group(1) == '$6$' and base_64_len == 86)): encrypted_pass = True set_pass_login(config, user, password, encrypted_pass) @@ -319,7 +335,7 @@ def handle(name, cfg, cloud, log, _args): set_config_ssh(config) set_config_hostname(config, hostname) else: - set_config_dhcp(config) + set_config_dhcp(config) set_config_ssh(config) set_config_hostname(config, hostname) @@ -330,4 +346,4 @@ def handle(name, cfg, cloud, log, _args): with open(cfg_file_name, 'w') as f: f.write(config.to_string()) except Exception as e: - logger.error("Failed to write configs into file %s error %s", file_name, e) + logger.error("Failed to write configs into file {}: {}".format(cfg_file_name, e)) |