def _connect(self, host, socket=None):
        """
        Order of precedence for SSH connection parameters:

        1. If user supplies parameters via action parameters, we use them to connect.
        2. For parameters not supplied via action parameters, if there is an entry
           for host in SSH config file, we use those. Note that this is a merge operation.
        3. If user does not supply certain action parameters (username and key file location)
           and there is no entry for host in SSH config file, we use values supplied in
           st2 config file for those parameters.

        :type host: ``str``
        :param host: Host to connect to

        :type socket: :class:`paramiko.Channel` or an opened :class:`socket.socket`
        :param socket: If specified, won't open a socket for communication to the specified host
                       and will use this instead

        :return: A connected SSHClient
        :rtype: :class:`paramiko.SSHClient`
        """

        conninfo = {
            "hostname": host,
            "allow_agent": False,
            "look_for_keys": False,
            "timeout": self.ssh_connect_timeout,
        }

        ssh_config_file_info = {}
        if cfg.CONF.ssh_runner.use_ssh_config:
            ssh_config_file_info = self._get_ssh_config_for_host(host)

        ssh_config_username = ssh_config_file_info.get("user", None)
        ssh_config_port = ssh_config_file_info.get("port", None)

        self.username = (
            self.username or ssh_config_username or cfg.CONF.system_user.user
        )

        # If a custom non-default port is provided in the SSH config file we use that over the
        # default port value provided via runner parameter
        if ssh_config_port and (self.port == DEFAULT_SSH_PORT or not self.port):
            self.port = int(ssh_config_port)
        else:
            self.port = self.port or DEFAULT_SSH_PORT

        # If both key file and key material are provided as action parameters,
        # throw an error informing user only one is required.
        if self.key_files and self.key_material:
            msg = "key_files and key_material arguments are mutually exclusive. Supply only one."
            raise ValueError(msg)

        # If neither key material nor password is provided, only then we look at key file and decide
        # if we want to use the user supplied one or the one in SSH config.
        if not self.key_material and not self.password:
            self.key_files = (
                self.key_files
                or ssh_config_file_info.get("identityfile", None)
                or cfg.CONF.system_user.ssh_key_file
            )

        if self.passphrase and not (self.key_files or self.key_material):
            raise ValueError("passphrase should accompany private key material")

        credentials_provided = self.password or self.key_files or self.key_material

        if not credentials_provided:
            msg = (
                "Either password or key file location or key material should be supplied "
                + "for action. You can also add an entry for host %s in SSH config file %s."
                % (host, self.ssh_config_file)
            )
            raise ValueError(msg)

        conninfo["username"] = self.username
        conninfo["port"] = self.port

        if self.password:
            conninfo["password"] = self.password

        if self.key_files:
            conninfo["key_filename"] = self.key_files

            passphrase_reqd = self._is_key_file_needs_passphrase(self.key_files)
            if passphrase_reqd and not self.passphrase:
                msg = (
                    "Private key file %s is passphrase protected. Supply a passphrase."
                    % self.key_files
                )
                raise paramiko.ssh_exception.PasswordRequiredException(msg)

            if self.passphrase:
                # Optional passphrase for unlocking the private key
                conninfo["password"] = self.passphrase

        if self.key_material:
            conninfo["pkey"] = self._get_pkey_object(
                key_material=self.key_material, passphrase=self.passphrase
            )

        if not self.password and not (self.key_files or self.key_material):
            conninfo["allow_agent"] = True
            conninfo["look_for_keys"] = True

        extra = {
            "_hostname": host,
            "_port": self.port,
            "_username": self.username,
            "_timeout": self.ssh_connect_timeout,
        }
        self.logger.debug("Connecting to server", extra=extra)

        self.socket = socket or ssh_config_file_info.get("sock", None)
        if self.socket:
            conninfo["sock"] = socket

        client = paramiko.SSHClient()
        # FIXME: Allow the admin or end user control the host key policy
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # nosec

        extra = {"_conninfo": conninfo}
        self.logger.debug("Connection info", extra=extra)

        try:
            client.connect(**conninfo)
        except SSHException as e:
            paramiko_msg = six.text_type(e)

            if conninfo.get("password", None):
                conninfo["password"] = "<redacted>"

            msg = (
                "Error connecting to host %s " % host
                + "with connection parameters %s." % conninfo
                + "Paramiko error: %s." % paramiko_msg
            )
            raise SSHException(msg)

        return client

        Order of precedence for SSH connection parameters:

        1. If user supplies parameters via action parameters, we use them to connect.
        2. For parameters not supplied via action parameters, if there is an entry
           for host in SSH config file, we use those. Note that this is a merge operation.
        3. If user does not supply certain action parameters (username and key file location)
           and there is no entry for host in SSH config file, we use values supplied in
           st2 config file for those parameters.

        :type host: ``str``
        :param host: Host to connect to

        :type socket: :class:`paramiko.Channel` or an opened :class:`socket.socket`
        :param socket: If specified, won't open a socket for communication to the specified host
                       and will use this instead

        :return: A connected SSHClient
        :rtype: :class:`paramiko.SSHClient`
        
st2common/st2common/runners/paramiko_ssh.py