CasperSecurity

Current Path : /lib/python3/dist-packages/cloudinit/config/
Upload File :
Current File : //lib/python3/dist-packages/cloudinit/config/cc_ssh.py

# Copyright (C) 2009-2010 Canonical Ltd.
# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Scott Moser <scott.moser@canonical.com>
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
#
# This file is part of cloud-init. See LICENSE file for license information.
"""SSH: Configure SSH and SSH keys"""

import glob
import logging
import os
import re
import sys
from typing import List, Optional, Sequence

from cloudinit import lifecycle, ssh_util, subp, util
from cloudinit.cloud import Cloud
from cloudinit.config import Config
from cloudinit.config.schema import MetaSchema
from cloudinit.distros import ALL_DISTROS, ug_util
from cloudinit.settings import PER_INSTANCE

# Note: We do not support *-sk key types because:
# 1) In the autogeneration case user interaction with the device is needed
# which does not fit with a cloud-context.
# 2) This type of keys are user-based, not hostkeys.

meta: MetaSchema = {
    "id": "cc_ssh",
    "distros": [ALL_DISTROS],
    "frequency": PER_INSTANCE,
    "activate_by_schema_keys": [],
}

LOG = logging.getLogger(__name__)

GENERATE_KEY_NAMES = ["rsa", "ecdsa", "ed25519"]
FIPS_UNSUPPORTED_KEY_NAMES = ["ed25519"]

KEY_FILE_TPL = "/etc/ssh/ssh_host_%s_key"
PUBLISH_HOST_KEYS = True
# By default publish all supported hostkey types.
HOST_KEY_PUBLISH_BLACKLIST: List[str] = []

CONFIG_KEY_TO_FILE = {}
PRIV_TO_PUB = {}
for k in GENERATE_KEY_NAMES:
    CONFIG_KEY_TO_FILE.update(
        {
            f"{k}_private": (KEY_FILE_TPL % k, 0o600),
            f"{k}_public": (f"{KEY_FILE_TPL % k}.pub", 0o644),
            f"{k}_certificate": (f"{KEY_FILE_TPL % k}-cert.pub", 0o644),
        }
    )
    PRIV_TO_PUB[f"{k}_private"] = f"{k}_public"

KEY_GEN_TPL = 'o=$(ssh-keygen -yf "%s") && echo "$o" root@localhost > "%s"'


def set_redhat_keyfile_perms(keyfile: str) -> None:
    """
    For fedora 37, centos 9 stream and below:
     - sshd version is earlier than version 9.
     - 'ssh_keys' group is present and owns the private keys.
     - private keys have permission 0o640.
    For fedora 38, centos 10 stream and above:
     - ssh version is atleast version 9.
     - 'ssh_keys' group is absent. 'root' group owns the keys.
     - private keys have permission 0o600, same as upstream.
    Public keys in all cases have permission 0o644.
    """
    permissions_public = 0o644
    ssh_version = ssh_util.get_opensshd_upstream_version()
    if ssh_version and ssh_version < lifecycle.Version(9, 0):
        # fedora 37, centos 9 stream and below has sshd
        # versions less than 9 and private key permissions are
        # set to 0o640 from sshd-keygen.
        # See sanitize permissions" section in sshd-keygen.
        permissions_private = 0o640
    else:
        # fedora 38, centos 10 stream and above. sshd-keygen sets
        # private key persmissions to 0o600.
        permissions_private = 0o600

    gid = util.get_group_id("ssh_keys")
    if gid != -1:
        # 'ssh_keys' group exists for fedora 37, centos 9 stream
        # and below. On these distros, 'ssh_keys' group own the private
        # keys. When 'ssh_keys' group is absent for newer distros,
        # 'root' group owns the private keys which is the default.
        os.chown(keyfile, -1, gid)
    os.chmod(keyfile, permissions_private)
    os.chmod(f"{keyfile}.pub", permissions_public)


def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:

    # 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
        cert_config = []
        for key, val in cfg["ssh_keys"].items():
            if key not in CONFIG_KEY_TO_FILE:
                if re.match(
                    "^(ecdsa-sk|ed25519-sk)_(private|public|certificate)$", key
                ):
                    reason = "unsupported"
                else:
                    reason = "unrecognized"
                LOG.warning('Skipping %s ssh_keys entry: "%s"', reason, key)
                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.append(("HostCertificate", str(tgt_fn)))

        if cert_config:
            ssh_util.append_ssh_config(cert_config)

        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
            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", public_file, private_file
                )
            except Exception:
                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
        )
        # remove keys that are not supported in fips mode if its enabled
        key_names = (
            genkeys
            if not util.fips_enabled()
            else [
                names
                for names in genkeys
                if names not in FIPS_UNSUPPORTED_KEY_NAMES
            ]
        )
        skipped_keys = set(genkeys).difference(key_names)
        if skipped_keys:
            LOG.debug(
                "skipping keys that are not supported in fips mode: %s",
                ",".join(skipped_keys),
            )

        for keytype in key_names:
            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, update_env={"LANG": "C"}
                    )
                    if not util.get_cfg_option_bool(
                        cfg, "ssh_quiet_keygen", False
                    ):
                        sys.stdout.write(util.decode_binary(out))

                    if cloud.distro.osfamily == "redhat":
                        set_redhat_keyfile_perms(keyfile)
                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: List[str] = []
        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!")


def apply_credentials(keys, user, disable_root, disable_root_opts):

    keys = set(keys)
    if user:
        ssh_util.setup_user_keys(keys, user)

    if disable_root:
        if not user:
            user = "NONE"
        key_prefix = disable_root_opts.replace("$USER", user)
        key_prefix = key_prefix.replace("$DISABLE_USER", "root")
    else:
        key_prefix = ""

    ssh_util.setup_user_keys(keys, "root", options=key_prefix)


def get_public_host_keys(blacklist: Optional[Sequence[str]] = None):
    """Read host keys from /etc/ssh/*.pub files and return them as a list.

    @param blacklist: List of key types to ignore. e.g. ['rsa']
    @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,)
    key_list = []
    blacklist_files = []
    if blacklist:
        # Convert blacklist to filenames:
        # 'rsa' -> '/etc/ssh/ssh_host_rsa_key.pub'
        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
    ]

    # Read host key files, retrieve first two fields as a tuple and
    # append that tuple to key_list.
    for file_name in file_list:
        file_contents = util.load_text_file(file_name)
        key_data = file_contents.split()
        if key_data and len(key_data) > 1:
            key_list.append(tuple(key_data[:2]))
    return key_list
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY