前言
SSH是linux系统远程登录及命令操作的常用协议与指令,基本用法非常简单。最近在做持续集成工作时候,在SSH上面遇到一些坑,因此在这里总结一下。
远程登录
SSH远程登录有两种方式,分别是口令登录及公钥登录。
口令登录
主要流程
口令登录即在登录时候输入远程主机的用户名及密码。其流程如下:
- 远程主机收到用户的登录请求,把自己公钥发给用户。
- 用户用远程主机的公钥将登录密码加密,发给远程主机。
- 远程主机用自己的私钥解密登录密码,判断是否正确,决定是否让用户登录。
known_hosts
上面用户收到远程主机的公钥后,如果是第一次连接该远程主机,则一般会先在shell里打印出公钥指纹,询问用户是否继续连接,如果选择继续则会把公钥加入到known_hosts文件里。如果要做自动化构建和部署的话,则不能用这种询问模式。解决办法有两种:
- 在用户的~/.ssh/config文件或/etc/ssh/ssh_config里加入这一行:
StrictHostKeyChecking no
- 提前获知远程主机的公钥,事先手动写入known_hosts文件中。
在写入known_hosts文件以后,之后再次登录就不会再询问了,而是在获取远程主机公钥后与known_hosts文件进行比对。如果远程主机更改了公钥,导致不一致了,则会产生异常。这时需要删除known_hosts里对应那一行的公钥信息,重新获取并写入。如果不想用known_hosts保存远程主机的公钥,则可以修改/etc/ssh/ssh_config,加入这一行:UserKnownHostsFile=/dev/null
~/.ssh/config是针对特定用户的配置文件,/etc/ssh/ssh_config和/etc/ssh/sshd_config都是公共的配置文件,其中前者针对ssh客户端,后者针对服务器端。
公钥登录
公钥登录不需要输入密码,是自动化技术的必备武器。需要事先将客户机的公钥拷贝到远程主机的~/.ssh/authorized_keys文件里。一般是用ssh-copy-id指令实现,可以用-i参数指定公钥文件。ssh-copy-id实际上相当于使用了这条指令:ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
主要流程
流程如下:
- 远程主机收到登录请求,向用户发送一段随机字符串。
- 用户用自己的私钥加密发到远程主机里。
- 远程主机再用事先存好的公钥解密。如果成功,则直接允许登录。
即便是公钥登录,客户机仍然会收到远程主机的公钥数据,并加到known_hosts中。
注意事项
有几种情况可能导致使用了ssh-copy-id但仍提示需要输入登录密码:
- 远程主机/etc/ssh/sshd_config这个文件下面几行注释没有去掉:
|
|
其中主要是第三行,前两行即便注释了默认都是yes。
- 远程主机~/.ssh/authorized_keys权限不足。需要让所有者用户可读写,可以用chmod解决:
|
|
- 远程主机~目录和.ssh目录不能让除了该用户其余的人具有写权限,这个需要格外注意。
- 出于某种原因,客户机的ssh-agent高速缓存内没有该私钥的信息。可以用
ssh-add -l
查看。如果的确没有,则要ssh-add进去。其中~/.ssh/id_rsa会自动加进去,一般不需要手动添加,但其他私钥需要手动添加。这个是放在内存里的临时缓存,重启后需要重新ssh-add私钥进去。
中间人攻击
前面提到过,客户机会收到远程主机的公钥后,会在shell打印出其指纹。因为在用户发出登录请求后,如果有第三方截获了该请求,并冒充远程主机将伪造的公钥发给用户,那么用户就会把远程主机的密码用伪造公钥加密发给第三方,从而被它获得远程主机的登录密码,使得这个过程存在着极高的风险。
客户机只要用返回的指纹和远程主机公示的指纹签名进行比对,就可以确定是否伪造了。
创建公钥私钥对
ssh-keygen命令可以创建。-N输入私钥密码,-f指定文件名,-C输入备注,-t指定加密算法,默认是rsa。
需要用ssh-add加入ssh-agent高速缓存内才有效。ssh-agent同时也可以作为自动化免去私钥密码的一项技术。事先将私钥加入ssh-agent,这时候要输入私钥密码。以后用ssh指令的时候就只会在缓存中直接调用私钥,不需要再输入密码了。
管理多个SSH key
最简单的就是上面那样用ssh-add把私钥都放到高速缓存中,客户端在用ssh指令的时候会按照一定的策略轮流尝试。但因为是放在内存中的,每次重启都会清空,有点不方便。
最正常的做法是放到~/.ssh/config文件中,配置示例如下:
|
|
config文件有很多种写法,还支持通配符。不仅可以用来管理ssh key,还可以用来省略输入用户名,简化hostname使得便于记忆等等。管理ssh key最常见的就是管理github和gitlab多个账户。