diff options
author | zsdc <taras@vyos.io> | 2022-03-25 20:58:01 +0200 |
---|---|---|
committer | zsdc <taras@vyos.io> | 2022-03-25 21:42:00 +0200 |
commit | 31448cccedd8f841fb3ac7d0f2e3cdefe08a53ba (patch) | |
tree | 349631a02467dae0158f6f663cc8aa8537974a97 /cloudinit/config/cc_ssh.py | |
parent | 5c4b3943343a85fbe517e5ec1fc670b3a8566b4b (diff) | |
parent | 8537237d80a48c8f0cbf8e66aa4826bbc882b022 (diff) | |
download | vyos-cloud-init-31448cccedd8f841fb3ac7d0f2e3cdefe08a53ba.tar.gz vyos-cloud-init-31448cccedd8f841fb3ac7d0f2e3cdefe08a53ba.zip |
T2117: Cloud-init updated to 22.1
Merged with 22.1 tag from the upstream Cloud-init repository.
Our modules were slightly modified for compatibility with the new
version.
Diffstat (limited to 'cloudinit/config/cc_ssh.py')
-rwxr-xr-x | cloudinit/config/cc_ssh.py | 133 |
1 files changed, 86 insertions, 47 deletions
diff --git a/cloudinit/config/cc_ssh.py b/cloudinit/config/cc_ssh.py index 05a16dbc..64486b9c 100755 --- a/cloudinit/config/cc_ssh.py +++ b/cloudinit/config/cc_ssh.py @@ -17,7 +17,7 @@ keys. Authorized Keys ^^^^^^^^^^^^^^^ -Authorized keys are a list of public SSH keys that are allowed to connect to a +Authorized keys are a list of public SSH keys that are allowed to connect to a user account on a system. They are stored in `.ssh/authorized_keys` in that account's home directory. Authorized keys for the default user defined in ``users`` can be specified using ``ssh_authorized_keys``. Keys @@ -89,6 +89,10 @@ optionally, ``<key type>_certificate``, e.g. ``rsa_private: <key>``, key types. Not all key types have to be specified, ones left unspecified will not be used. If this config option is used, then no keys will be generated. +When host keys are generated the output of the ssh-keygen command(s) can be +displayed on the console using the ``ssh_quiet_keygen`` configuration key. +This settings defaults to False which displays the keygen output. + .. note:: when specifying private host keys in cloud-config, care should be taken to ensure that the communication between the data source and the instance is @@ -151,33 +155,33 @@ config flags are: ssh_publish_hostkeys: enabled: <true/false> (Defaults to true) blacklist: <list of key types> (Defaults to [dsa]) + ssh_quiet_keygen: <true/false> """ import glob import os import sys +from cloudinit import ssh_util, subp, util from cloudinit.distros import ug_util -from cloudinit import ssh_util -from cloudinit import subp -from cloudinit import util - -GENERATE_KEY_NAMES = ['rsa', 'dsa', 'ecdsa', 'ed25519'] -KEY_FILE_TPL = '/etc/ssh/ssh_host_%s_key' +GENERATE_KEY_NAMES = ["rsa", "dsa", "ecdsa", "ed25519"] +KEY_FILE_TPL = "/etc/ssh/ssh_host_%s_key" PUBLISH_HOST_KEYS = True # Don't publish the dsa hostkey by default since OpenSSH recommends not using # it. -HOST_KEY_PUBLISH_BLACKLIST = ['dsa'] +HOST_KEY_PUBLISH_BLACKLIST = ["dsa"] CONFIG_KEY_TO_FILE = {} PRIV_TO_PUB = {} for k in GENERATE_KEY_NAMES: CONFIG_KEY_TO_FILE.update({"%s_private" % k: (KEY_FILE_TPL % k, 0o600)}) CONFIG_KEY_TO_FILE.update( - {"%s_public" % k: (KEY_FILE_TPL % k + ".pub", 0o600)}) + {"%s_public" % k: (KEY_FILE_TPL % k + ".pub", 0o600)} + ) CONFIG_KEY_TO_FILE.update( - {"%s_certificate" % k: (KEY_FILE_TPL % k + "-cert.pub", 0o600)}) + {"%s_certificate" % k: (KEY_FILE_TPL % k + "-cert.pub", 0o600)} + ) PRIV_TO_PUB["%s_private" % k] = "%s_public" % k KEY_GEN_TPL = 'o=$(ssh-keygen -yf "%s") && echo "$o" root@localhost > "%s"' @@ -204,57 +208,86 @@ def handle(_name, cfg, cloud, log, _args): tgt_perms = CONFIG_KEY_TO_FILE[key][1] util.write_file(tgt_fn, val, tgt_perms) # set server to present the most recently identified certificate - if '_certificate' in key: - cert_config = {'HostCertificate': tgt_fn} + if "_certificate" in key: + cert_config = {"HostCertificate": tgt_fn} ssh_util.update_ssh_config(cert_config) - for (priv, pub) in PRIV_TO_PUB.items(): - if pub in cfg['ssh_keys'] or priv not in cfg['ssh_keys']: + for private_type, public_type in PRIV_TO_PUB.items(): + if ( + public_type in cfg["ssh_keys"] + or private_type not in cfg["ssh_keys"] + ): continue - pair = (CONFIG_KEY_TO_FILE[priv][0], CONFIG_KEY_TO_FILE[pub][0]) - cmd = ['sh', '-xc', KEY_GEN_TPL % pair] + private_file, public_file = ( + CONFIG_KEY_TO_FILE[private_type][0], + CONFIG_KEY_TO_FILE[public_type][0], + ) + cmd = ["sh", "-xc", KEY_GEN_TPL % (private_file, public_file)] try: # TODO(harlowja): Is this guard needed? with util.SeLinuxGuard("/etc/ssh", recursive=True): subp.subp(cmd, capture=False) - log.debug("Generated a key for %s from %s", pair[0], pair[1]) + log.debug( + f"Generated a key for {public_file} from {private_file}" + ) except Exception: - util.logexc(log, "Failed generated a key for %s from %s", - pair[0], pair[1]) + util.logexc( + log, + "Failed generating a key for " + f"{public_file} from {private_file}", + ) else: # if not, generate them - genkeys = util.get_cfg_option_list(cfg, - 'ssh_genkeytypes', - GENERATE_KEY_NAMES) + genkeys = util.get_cfg_option_list( + cfg, "ssh_genkeytypes", GENERATE_KEY_NAMES + ) lang_c = os.environ.copy() - lang_c['LANG'] = 'C' + lang_c["LANG"] = "C" for keytype in genkeys: keyfile = KEY_FILE_TPL % (keytype) if os.path.exists(keyfile): continue util.ensure_dir(os.path.dirname(keyfile)) - cmd = ['ssh-keygen', '-t', keytype, '-N', '', '-f', keyfile] + cmd = ["ssh-keygen", "-t", keytype, "-N", "", "-f", keyfile] # TODO(harlowja): Is this guard needed? with util.SeLinuxGuard("/etc/ssh", recursive=True): try: out, err = subp.subp(cmd, capture=True, env=lang_c) - sys.stdout.write(util.decode_binary(out)) + if not util.get_cfg_option_bool( + cfg, "ssh_quiet_keygen", False + ): + sys.stdout.write(util.decode_binary(out)) + + gid = util.get_group_id("ssh_keys") + if gid != -1: + # perform same "sanitize permissions" as sshd-keygen + os.chown(keyfile, -1, gid) + os.chmod(keyfile, 0o640) + os.chmod(keyfile + ".pub", 0o644) except subp.ProcessExecutionError as e: err = util.decode_binary(e.stderr).lower() - if (e.exit_code == 1 and - err.lower().startswith("unknown key")): + if e.exit_code == 1 and err.lower().startswith( + "unknown key" + ): log.debug("ssh-keygen: unknown key type '%s'", keytype) else: - util.logexc(log, "Failed generating key type %s to " - "file %s", keytype, keyfile) + util.logexc( + log, + "Failed generating key type %s to file %s", + keytype, + keyfile, + ) if "ssh_publish_hostkeys" in cfg: host_key_blacklist = util.get_cfg_option_list( - cfg["ssh_publish_hostkeys"], "blacklist", - HOST_KEY_PUBLISH_BLACKLIST) + cfg["ssh_publish_hostkeys"], + "blacklist", + HOST_KEY_PUBLISH_BLACKLIST, + ) publish_hostkeys = util.get_cfg_option_bool( - cfg["ssh_publish_hostkeys"], "enabled", PUBLISH_HOST_KEYS) + cfg["ssh_publish_hostkeys"], "enabled", PUBLISH_HOST_KEYS + ) else: host_key_blacklist = HOST_KEY_PUBLISH_BLACKLIST publish_hostkeys = PUBLISH_HOST_KEYS @@ -270,15 +303,18 @@ def handle(_name, cfg, cloud, log, _args): (users, _groups) = ug_util.normalize_users_groups(cfg, cloud.distro) (user, _user_config) = ug_util.extract_default(users) disable_root = util.get_cfg_option_bool(cfg, "disable_root", True) - disable_root_opts = util.get_cfg_option_str(cfg, "disable_root_opts", - ssh_util.DISABLE_USER_OPTS) + disable_root_opts = util.get_cfg_option_str( + cfg, "disable_root_opts", ssh_util.DISABLE_USER_OPTS + ) keys = [] - if util.get_cfg_option_bool(cfg, 'allow_public_ssh_keys', True): + if util.get_cfg_option_bool(cfg, "allow_public_ssh_keys", True): keys = cloud.get_public_ssh_keys() or [] else: - log.debug('Skipping import of publish SSH keys per ' - 'config setting: allow_public_ssh_keys=False') + log.debug( + "Skipping import of publish SSH keys per " + "config setting: allow_public_ssh_keys=False" + ) if "ssh_authorized_keys" in cfg: cfgkeys = cfg["ssh_authorized_keys"] @@ -298,12 +334,12 @@ def apply_credentials(keys, user, disable_root, disable_root_opts): if disable_root: if not user: user = "NONE" - key_prefix = disable_root_opts.replace('$USER', user) - key_prefix = key_prefix.replace('$DISABLE_USER', 'root') + key_prefix = disable_root_opts.replace("$USER", user) + key_prefix = key_prefix.replace("$DISABLE_USER", "root") else: - key_prefix = '' + key_prefix = "" - ssh_util.setup_user_keys(keys, 'root', options=key_prefix) + ssh_util.setup_user_keys(keys, "root", options=key_prefix) def get_public_host_keys(blacklist=None): @@ -313,18 +349,21 @@ def get_public_host_keys(blacklist=None): @returns: List of keys, each formatted as a two-element tuple. e.g. [('ssh-rsa', 'AAAAB3Nz...'), ('ssh-ed25519', 'AAAAC3Nx...')] """ - public_key_file_tmpl = '%s.pub' % (KEY_FILE_TPL,) + public_key_file_tmpl = "%s.pub" % (KEY_FILE_TPL,) key_list = [] blacklist_files = [] if blacklist: # Convert blacklist to filenames: # 'dsa' -> '/etc/ssh/ssh_host_dsa_key.pub' - blacklist_files = [public_key_file_tmpl % (key_type,) - for key_type in blacklist] + blacklist_files = [ + public_key_file_tmpl % (key_type,) for key_type in blacklist + ] # Get list of public key files and filter out blacklisted files. - file_list = [hostfile for hostfile - in glob.glob(public_key_file_tmpl % ('*',)) - if hostfile not in blacklist_files] + file_list = [ + hostfile + for hostfile in glob.glob(public_key_file_tmpl % ("*",)) + if hostfile not in blacklist_files + ] # Read host key files, retrieve first two fields as a tuple and # append that tuple to key_list. |