SSH常见问题及其解决方法

时间:2024-05-21 17:53:47

SSH是Linux中的基础服务,作为IT从业者,基本上每天都要SSH连接到服务器中,从事各种各样的工作。作为这样基础的不能再基础的服务,一旦出现问题,影响也是巨大的,连不上就无法对服务器进行配置和更改,所有的事情也就无从谈起。

在这篇文章中,我们会对SSH服务进行介绍,并对一些常见的问题进行分析,进而提供相应的解决方法。话不多说,我们进入主题。

一、SSH服务简介

SSH采用的是C/S架构,SSH server端一般运行在服务器中,这里的服务器可以是物理服务器,而现在随着云计算的推广,更大的可能性是云主机,比如AWS的EC2实例,阿里云的ECS实例等。SSH client端则千差万别,Linux中是ssh命令,一般是OpenSSH软件包的一部分;Windows中比较常见的是SecureCRT,X-Shell,Moba-Xterm等。

接下来,我们以Linux Mint作为SSH client端,以AWS EC2为SSH server端进行演示和分析。

我们首先来分析一个正常的SSH连接是如何进行的,在这里我们通过ssh命令的-vvv选项,来看一下SSH连接背后发生了什么。这里为了减少不必要的影响,略去了测试用的对端IP地址,Linux Mint的ssh配置文件默认指定了连接用户为ec2-user,指定了本地的私钥文件位置为/home/user/.ssh/user.pem。

################################################

[email protected]:~$ ssh IP -vvv
OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n  7 Dec 2017
#本机的ssh客户端版本信息
.....
.....
debug1: Connecting to IP [IP] port 22.
debug1: Connection established.
#与对端TCP 22端口完成建联过程
debug1: key_load_public: No such file or directory
debug1: identity file /home/user/.ssh/user.pem type -1
#本地的key文件
.....
.....
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4
debug1: match: OpenSSH_7.4 pat OpenSSH* compat 0x04000000
#对端ssh服务器版本信息
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to IP:22 as 'ec2-user'
#本地配置文件中指定的用户信息
.....
.....
debug2: KEX algorithms: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c
debug2: host key algorithms: [email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,[email protected],[email protected],ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
#ssh客户端与服务器端交换支持的加密算法
.....
.....
debug3: authmethod_lookup publickey
debug3: remaining preferred: keyboard-interactive,password
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Trying private key: /home/user/.ssh/user.pem
#使用本地的private key进行**认证
debug3: sign_and_send_pubkey: RSA SHA256:imct6EHZzIK24fZ+H3bFzHAYpDLufFVELss7un64aZA
debug3: send packet: type 50
debug2: we sent a publickey packet, wait for reply
#本地的ssh客户端发送了publickey报文,等待ssh服务器端反馈
debug3: receive packet: type 52
#本地的ssh客户端收到来自ssh服务器端的反馈
debug1: Authentication succeeded (publickey).
#提示认证成功
Authenticated to IP ([IP]:22).
debug1: channel 0: new [client-session]
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open
#认证通过后,ssh服务器端打开一个channel,用于处理ssh请求
.....
.....
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: PTY allocation request accepted on channel 0
debug2: channel 0: rcvd adjust 2097152
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
#channel 0的shell申请被接受,ssh连接已经建立
Last login: Sat Nov  2 05:04:03 2019 from IP

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[[email protected] ~]$

#######################################

综合来看,SSH连接的第一阶段为TCP建联,也就是通常的TCP三次握手机制,服务器端一般为TCP 22端口,也不排除自定义配置,这里不再赘述。

当TCP 22建联完毕后,ssh客户端和ssh服务器端开始进行通信,交换一系列信息,例如双方支持的加密算法等。进而ssh客户端将本地**发送到ssh服务器端进行认证,认证完毕后,ssh服务器端会将认证结果反馈给ssh客户端。如果认证成功的话,ssh服务器端会开启一个channel,用于处理来自ssh客户端的业务请求,该channel会与PTY进行关联,并申请一个shell终端。如果认证、权限等一切正常,channel打开,ssh客户端和ssh服务器端的ssh连接可用。

以上为一个正常的SSH连接所经历的环节。接下来,我们看一下各个环节中可能会遇到的问题。

二、网络部分问题

通过上述分析,我们知道SSH连接首先要进行TCP 22端口的建联,如果这个时候网络部分出现问题,SSH连接肯定无法正常工作。这个时候,我们可以使用telnet命令来测试下到特定IP地址的TCP 22端口是否通畅。

以下为一个通畅的telnet测试,这里为了减少不必要的影响,略去了测试用的对端IP地址。

###################

[email protected]:~$ telnet IP 22
Trying IP...
Connected to IP.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.4

###################

除此之外,还有两种比较常见的情况,分列如下:

1、Connection timed out报错

##################

[email protected]:~$ telnet IP 22
Trying IP...
telnet: Unable to connect to remote host: Connection timed out

##################

此时的wireshark抓包显示如下:

可以看到本地客户端向服务器端发起了TCP的SYN包,但是服务器端一直没有响应,进而出发了TCP Retransmission,多次重传后,导致超时,也就是此处看到的Connection timed out.

SSH常见问题及其解决方法

2、Connection refused报错

####################

[email protected]:~$ telnet IP 22
Trying IP...
telnet: Unable to connect to remote host: Connection refused

####################

此时的wireshark抓包显示如下:

可以看到本地客户端向服务器端发起了TCP的SYN包,同时服务器端回了一个RST,ACK,将对应的TCP连接进行了重置。

SSH常见问题及其解决方法

将二者对比,我们可以发现,同样是无法进行TCP建联,二者有着不同的含义。

对于公有云实例来说,Connection timeout代表着流量还未到达实例,在中间的某个环节已经被阻断。最常见的场景是实例的安全组、网络ACL部分存在阻断,例如没有放行对应的端口到本地客户端所在的共有IP地址等问题。排查的时候,可以先检查下实例所在的安全组,并查看本地客户端的公有IP地址,进而确保安全组中放行了对应的端口给该公有IP地址。

而Connection refused这种情况,从抓包已经看到TCP报文已经到了服务器,但是服务器由于某些原因并未接收对应的TCP报文。这种场景通常对应着实例内部,也就是操作系统层面的某些设置,例如SSH服务器端进程没起来,或者监听在不同的端口上;也有可能实例上运行了防火墙(iptables、firewalld等),不允许来自客户端的公有IP与SSH服务器端建立连接。这种场景下的排障稍微复杂一些,尤其是AWS EC2实例,由于此时已经无法ssh登陆,通常需要关停实例,卸载根卷,挂在到其它的实例中,分析配置文件、日志等,确定可能存在的问题,进而做相应的修改后,再挂载回原来的实例中,重新启动实例,尝试看是否可以解决问题。而对于阿里云的ECS实例,相应的排查则要简单的多,因为阿里云ECS实例提供了VNC功能,可以直接在console端连接到实例内部,虽然会卡一些,但毕竟可以登录进去,有点类似于物理机的管理接口,例如惠普的ILO接口、戴尔的iDrac接口、VMware的管理控制台等。这里先挖个坑,后续我们会开设AWS EC2专栏,讲解如何对EC2的EBS卷做离线分析。

三、鉴权相关问题

如果前边的TCP建联已经通过,那么接下来的问题则多数集中在鉴权等相关问题上。这里最常见的就是Permission denied报错。

以下为我们的一个讲解案例,还是通过ssh开启verbose日志的方式(-vvv选项),我们来看一下这个过程中发生了什么:

##############

debug1: Next authentication method: publickey
debug1: Trying private key: /home/user/.ssh/user.pem
#调用本地的**文件
.....
.....
debug2: we sent a publickey packet, wait for reply
#本地客户端将publickey认证内容发送给服务器端
debug3: receive packet: type 51
#服务器端认证失败,返回相应的结果
.....
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic
debug2: we did not send a packet, disable method
debug1: No more authentication methods to try.
#此时已经没有其它可继续认证的方法
[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
#使用centos用户进行认证,返回Permission denied报错,认证失败

#################

从上述日志,我们能得到的有用信息主要包括以下几点:

首先,客户端和服务器端使用的是**认证方式;其次,客户端的**文件为 /home/user/.ssh/user.pem;第三,客户端使用的登录用户名为centos。

这个时候,客户端能做的排查包括以下几点:

第一,客户端尝试使用的认证方式是否正确,比如服务器端其实使用的是用户名和密码,而发送的命令格式为**认证

第二,确认**文件对应的登录用户名,也就是说此处的 /home/user/.ssh/user.pem是否为centos用户的**文件

第三,确认centos用户是不是正确的登录用户

而在服务器端,我们能看到的信息会更多一些,也更贴近报错本身的含义。一般来说,SSH登录相关的报错与安全息息相关,相应的日志一般记录在/var/log/secure文件中(比如Amazon Linux,CentOS,RHEL等操作系统)。

查看日志有一个小技巧,日志一般条目众多,此处我们可以根据发生的时间点有针对性的查看,极大的减少排查范围。以当前报错为例,查看到的日志内容如下:

#############

Nov  2 06:56:03 ip-xx-xx-xx-xx sshd[4495]: Invalid user centos from IP port 54632
Nov  2 06:56:03 ip-xx-xx-xx-xx sshd[4495]: input_userauth_request: invalid user centos [preauth]

#############

我们可以看到,这里的报错信息非常直观,invalid user centos,也就是说我们使用的登录用户名centos是无效的。

考虑到测试用的是AWS EC2实例,使用的是Amazon Linux操作系统,那么当前的问题的解法应该是将centos用户替换为ec2-user,即可顺利登录。

常言道,幸福的家庭千篇一律,不幸的家庭各部相同。对于SSH排障来说,这个说法也是很适用的。我们需要根据具体的报错内容,做进一步的分析,以确定可能存在的问题。

四、尾声

SSH作为一个基础服务,其涵盖的内容相当广泛,我们在这里分析的只是最最基础的一些,一些更为高级的话题,例如ssh集成ldap认证,PAM模块的应用及配置等内容,篇幅限制暂不详细展开,感兴趣的朋友们可以尝试一下。

希望上述内容能对你有所帮助。