def handle_ssh_pwauth(pw_auth, distro):
    """Apply sshd PasswordAuthentication changes.

    @param pw_auth: config setting from 'pw_auth'.
                    Best given as True, False, or "unchanged".
    @param distro: an instance of the distro class for the target distribution

    @return: None"""
    cfg_name = "PasswordAuthentication"

    if util.is_true(pw_auth):
        cfg_val = "yes"
    elif util.is_false(pw_auth):
        cfg_val = "no"
    else:
        bmsg = "Leaving SSH config '%s' unchanged." % cfg_name
        if pw_auth is None or pw_auth.lower() == "unchanged":
            LOG.debug("%s ssh_pwauth=%s", bmsg, pw_auth)
        else:
            LOG.warning("%s Unrecognized value: ssh_pwauth=%s", bmsg, pw_auth)
        return

    updated = update_ssh_config({cfg_name: cfg_val})
    if not updated:
        LOG.debug("No need to restart SSH service, %s not updated.", cfg_name)
        return

    distro.manage_service("restart", distro.get_option("ssh_svcname", "ssh"))
    LOG.debug("Restarted the SSH daemon.")
Пример #2
0
 def test_not_modified(self):
     mycfg = self.tmp_path("ssh_config_2")
     util.write_file(mycfg, self.cfgdata)
     with patch("cloudinit.ssh_util.util.write_file") as m_write_file:
         ret = ssh_util.update_ssh_config({"MyKey": "ORIG_VAL"}, mycfg)
     self.assertFalse(ret)
     self.assertEqual(self.cfgdata, util.load_file(mycfg))
     m_write_file.assert_not_called()
Пример #3
0
 def test_not_modified(self):
     mycfg = self.tmp_path("ssh_config_2")
     util.write_file(mycfg, self.cfgdata)
     with patch("cloudinit.ssh_util.util.write_file") as m_write_file:
         ret = ssh_util.update_ssh_config({"MyKey": "ORIG_VAL"}, mycfg)
     self.assertFalse(ret)
     self.assertEqual(self.cfgdata, util.load_file(mycfg))
     m_write_file.assert_not_called()
Пример #4
0
 def test_modified(self):
     mycfg = self.tmp_path("ssh_config_1")
     util.write_file(mycfg, self.cfgdata)
     ret = ssh_util.update_ssh_config({"MyKey": "NEW_VAL"}, mycfg)
     self.assertTrue(ret)
     found = util.load_file(mycfg)
     self.assertEqual(self.cfgdata.replace("ORIG_VAL", "NEW_VAL"), found)
     # assert there is a newline at end of file (LP: #1677205)
     self.assertEqual('\n', found[-1])
Пример #5
0
 def test_modified(self):
     mycfg = self.tmp_path("ssh_config_1")
     util.write_file(mycfg, self.cfgdata)
     ret = ssh_util.update_ssh_config({"MyKey": "NEW_VAL"}, mycfg)
     self.assertTrue(ret)
     found = util.load_file(mycfg)
     self.assertEqual(self.cfgdata.replace("ORIG_VAL", "NEW_VAL"), found)
     # assert there is a newline at end of file (LP: #1677205)
     self.assertEqual('\n', found[-1])
Пример #6
0
def handle_ssh_pwauth(pw_auth, service_cmd=None, service_name="ssh"):
    """Apply sshd PasswordAuthentication changes.

    @param pw_auth: config setting from 'pw_auth'.
                    Best given as True, False, or "unchanged".
    @param service_cmd: The service command list (['service'])
    @param service_name: The name of the sshd service for the system.

    @return: None"""
    cfg_name = "PasswordAuthentication"
    if service_cmd is None:
        service_cmd = ["service"]

    if util.is_true(pw_auth):
        cfg_val = 'yes'
    elif util.is_false(pw_auth):
        cfg_val = 'no'
    else:
        bmsg = "Leaving ssh config '%s' unchanged." % cfg_name
        if pw_auth is None or pw_auth.lower() == 'unchanged':
            LOG.debug("%s ssh_pwauth=%s", bmsg, pw_auth)
        else:
            LOG.warning("%s Unrecognized value: ssh_pwauth=%s", bmsg, pw_auth)
        return

    updated = update_ssh_config({cfg_name: cfg_val})
    if not updated:
        LOG.debug("No need to restart ssh service, %s not updated.", cfg_name)
        return

    if 'systemctl' in service_cmd:
        cmd = list(service_cmd) + ["restart", service_name]
    else:
        cmd = list(service_cmd) + [service_name, "restart"]
    util.subp(cmd)
    LOG.debug("Restarted the ssh daemon.")
Пример #7
0
def handle_ssh_pwauth(pw_auth, service_cmd=None, service_name="ssh"):
    """Apply sshd PasswordAuthentication changes.

    @param pw_auth: config setting from 'pw_auth'.
                    Best given as True, False, or "unchanged".
    @param service_cmd: The service command list (['service'])
    @param service_name: The name of the sshd service for the system.

    @return: None"""
    cfg_name = "PasswordAuthentication"
    if service_cmd is None:
        service_cmd = ["service"]

    if util.is_true(pw_auth):
        cfg_val = 'yes'
    elif util.is_false(pw_auth):
        cfg_val = 'no'
    else:
        bmsg = "Leaving ssh config '%s' unchanged." % cfg_name
        if pw_auth is None or pw_auth.lower() == 'unchanged':
            LOG.debug("%s ssh_pwauth=%s", bmsg, pw_auth)
        else:
            LOG.warning("%s Unrecognized value: ssh_pwauth=%s", bmsg, pw_auth)
        return

    updated = update_ssh_config({cfg_name: cfg_val})
    if not updated:
        LOG.debug("No need to restart ssh service, %s not updated.", cfg_name)
        return

    if 'systemctl' in service_cmd:
        cmd = list(service_cmd) + ["restart", service_name]
    else:
        cmd = list(service_cmd) + [service_name, "restart"]
    util.subp(cmd)
    LOG.debug("Restarted the ssh daemon.")
Пример #8
0
def handle(_name, cfg, cloud, log, _args):

    # remove the static keys from the pristine image
    if cfg.get("ssh_deletekeys", True):
        key_pth = os.path.join("/etc/ssh/", "ssh_host_*key*")
        for f in glob.glob(key_pth):
            try:
                util.del_file(f)
            except Exception:
                util.logexc(log, "Failed deleting key file %s", f)

    if "ssh_keys" in cfg:
        # if there are keys and/or certificates in cloud-config, use them
        for (key, val) in cfg["ssh_keys"].items():
            # skip entry if unrecognized
            if key not in CONFIG_KEY_TO_FILE:
                continue
            tgt_fn = CONFIG_KEY_TO_FILE[key][0]
            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}
                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"]:
                continue
            pair = (CONFIG_KEY_TO_FILE[priv][0], CONFIG_KEY_TO_FILE[pub][0])
            cmd = ["sh", "-xc", KEY_GEN_TPL % pair]
            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])
            except Exception:
                util.logexc(
                    log,
                    "Failed generated a key for %s from %s",
                    pair[0],
                    pair[1],
                )
    else:
        # if not, generate them
        genkeys = util.get_cfg_option_list(cfg, "ssh_genkeytypes",
                                           GENERATE_KEY_NAMES)
        lang_c = os.environ.copy()
        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]

            # TODO(harlowja): Is this guard needed?
            with util.SeLinuxGuard("/etc/ssh", recursive=True):
                try:
                    out, err = subp.subp(cmd, capture=True, env=lang_c)
                    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"):
                        log.debug("ssh-keygen: unknown key type '%s'", keytype)
                    else:
                        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,
        )
        publish_hostkeys = util.get_cfg_option_bool(
            cfg["ssh_publish_hostkeys"], "enabled", PUBLISH_HOST_KEYS)
    else:
        host_key_blacklist = HOST_KEY_PUBLISH_BLACKLIST
        publish_hostkeys = PUBLISH_HOST_KEYS

    if publish_hostkeys:
        hostkeys = get_public_host_keys(blacklist=host_key_blacklist)
        try:
            cloud.datasource.publish_host_keys(hostkeys)
        except Exception:
            util.logexc(log, "Publishing host keys failed!")

    try:
        (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)

        keys = []
        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")

        if "ssh_authorized_keys" in cfg:
            cfgkeys = cfg["ssh_authorized_keys"]
            keys.extend(cfgkeys)

        apply_credentials(keys, user, disable_root, disable_root_opts)
    except Exception:
        util.logexc(log, "Applying SSH credentials failed!")
Пример #9
0
def handle_ssh_pwauth(pw_auth, distro: Distro):
    """Apply sshd PasswordAuthentication changes.

    @param pw_auth: config setting from 'pw_auth'.
                    Best given as True, False, or "unchanged".
    @param distro: an instance of the distro class for the target distribution

    @return: None"""
    service = distro.get_option("ssh_svcname", "ssh")
    restart_ssh = True
    try:
        distro.manage_service("status", service)
    except subp.ProcessExecutionError as e:
        uses_systemd = distro.uses_systemd()
        if not uses_systemd:
            LOG.debug(
                "Writing config 'ssh_pwauth: %s'. SSH service '%s'"
                " will not be restarted because it is not running or not"
                " available.",
                pw_auth,
                service,
            )
            restart_ssh = False
        elif e.exit_code == 3:
            # Service is not running. Write ssh config.
            LOG.debug(
                "Writing config 'ssh_pwauth: %s'. SSH service '%s'"
                " will not be restarted because it is stopped.",
                pw_auth,
                service,
            )
            restart_ssh = False
        elif e.exit_code == 4:
            # Service status is unknown
            LOG.warning(
                "Ignoring config 'ssh_pwauth: %s'."
                " SSH service '%s' is not installed.",
                pw_auth,
                service,
            )
            return
        else:
            LOG.warning(
                "Ignoring config 'ssh_pwauth: %s'."
                " SSH service '%s' is not available. Error: %s.",
                pw_auth,
                service,
                e,
            )
            return

    cfg_name = "PasswordAuthentication"

    if isinstance(pw_auth, str):
        LOG.warning(
            "DEPRECATION: The 'ssh_pwauth' config key should be set to "
            "a boolean value. The string format is deprecated and will be "
            "removed in a future version of cloud-init.")
    if util.is_true(pw_auth):
        cfg_val = "yes"
    elif util.is_false(pw_auth):
        cfg_val = "no"
    else:
        bmsg = "Leaving SSH config '%s' unchanged." % cfg_name
        if pw_auth is None or pw_auth.lower() == "unchanged":
            LOG.debug("%s ssh_pwauth=%s", bmsg, pw_auth)
        else:
            LOG.warning("%s Unrecognized value: ssh_pwauth=%s", bmsg, pw_auth)
        return

    updated = update_ssh_config({cfg_name: cfg_val})
    if not updated:
        LOG.debug("No need to restart SSH service, %s not updated.", cfg_name)
        return

    if restart_ssh:
        distro.manage_service("restart", service)
        LOG.debug("Restarted the SSH daemon.")
    else:
        LOG.debug("Not restarting SSH service: service is stopped.")