之前一直使用ip+密码登录,但是每次登录都能看到这个:

1Last failed login: Fri Mar 2 20:02:55 CST 2018 from xx.xx.xx.xx on ssh:notty There were 230 failed login attempts since the last successful login.

后来发现failed前面的数字越来越大,到后来每隔几十分钟就跳到三位数了,一天没登录直接四位数,简直胆(sang)战(xin)心(bing)惊(kuang),毕竟强密码用起来不方便,弱密码又很容易被破,那么就只有使用密钥+密码登录才放心了。

配置

首先使用ssh-keygen来生成RSA密钥和公钥

1ssh-keygen

也可以手动指定加密参数:

1ssh-keygen -b 4096 -t rsa
参数 含义
-t 即 type,用于指定加密算法
可选算法包括:rsa dsa ecdsa ecdsa_sk d25519 ed25519_sk xmss
证书登录常用的是 rsa,也是 ssh-keygen 默认使用的加密类型
-b 加密长度,默认的 rsa 长度是 2048,如果要加大密码强度,那么可以指定 4096 位的长度

生成密钥过程中会要求指定保存密钥的路径,按 Enter 键使用默认的路径 (~/.ssh/) 和文件名 (私钥 id_rsa 和公钥 id_rsa_pub)

1# 直接按Enter
2Enter file in which to save the key (/home/wenjinyu/.ssh/id_rsa):

公钥相当于锁,私钥相当于对应的钥匙,所以现在需要把锁(公钥)放到服务器上,登录时使用钥匙(私钥)解密

之后是输入密码来加密密钥,也就是使用密钥需要输入密码验证,直接按 Enter 跳过即可

1# 输入密码,可以直接Enter跳过,即只是用密钥,不用密码
2Enter passphrase (empty for no passphrase):
3
4# 再次输入,确认密码,直接enter
5Enter same passphrase again:

注意:如果要提高安全性而设置密码,那么密码至少要20位长度.

生成之后需要把公钥上传到服务器,保存为服务器端的 ~/.ssh/authorized_keys 文件,同时需要更改文件夹权限为 700 ,文件权限为 600 ,可以通过 scp 手动上传并更改,也可以直接使用 Linux 提供的工具 ssh-copy-id 自动完成这一操作

1ssh-copy-id username@server

ssh-copy-id 会自动查找当前用户家目录中 .ssh 下以 .pub 结尾的公钥,并上传至指定服务器

服务端配置的说明

公钥 id_rsa 可重命名为 authorized_keys,名字任意,只要和 /etc/ssh/sshd_config 中的配置一致即可

1AuthorsizedKeysFile .ssh/authorized_keys

存放完成后需要确保只有当前用户可读写,可以通过以下命令确保权限正确

1chown wenjinyu:wenjinyu ~/.ssh/
2chmod 700 ~/.ssh/
3chmod 600 ~/.ssh/authorized_keys

部署

使用ssh-copy-id之后一般是自动设置好authorized_keys的权限的,但如果是使用scp方式的话,就需要更改authorized_keys文件和.ssh文件夹的权限,分别是600和700权限

1chmod 700 /root/.ssh
2chmod 600 /root/.ssh/authorized_keys

ssh对密钥的权限要求很严苛,如果没有设置好权限的话,ssh会拒绝密钥登录,毕竟其他用户如果对密钥文件有操作权限的话也是很危险的。

然后就是修改ssh的配置文件,以便ssh使用密钥:

 1# 打开ssh配置文件
 2vim /etc/ssh/sshd_config
 3
 4# 将以下这项去掉注释并改为yes,以启用密钥验证
 5PubkeyAuthentication yes
 6
 7# 指定公钥数据库文件
 8AuthorsizedKeysFile .ssh/authorized_keys
 9
10# 为了减少被扫描端口的次数,把端口从22改为其他端口,如2333
11Port 2333
12
13# 需要使用root用户登录,要确保这一行为yes
14PermitRootLogin yes
15
16# StrictModes修改为no,默认为yes.
17# 如果不修改用key登陆是出现server refused our key.
18# 如果StrictModes为yes必需保证存放公钥的文件夹的拥有与登陆用户名是相同的.
19# “StrictModes”设置ssh在接收登录请求之前是否检查用户家目录和rhosts文件的权限和所有权。
20# 很有有必要这样做,因为新手经常会把自己的目录和文件设成任何人都有写权限。
21StrictModes no

之后需要重启一下ssh以便修改的配置生效

1#ubuntu系统
2service ssh restart
3
4#debian系统
5/etc/init.d/ssh restart
6
7# CentOS 使用以下命令
8systemctl restart sshd.service

然后就可以在本地试一下使用密钥登录了

1ssh -i .ssh/id_rsa -p 2333 root@1.2.3.4
  • 注意
  • 密钥是保存在root用户文件夹下的,所以登录的时候密钥路径必须选择/root/.ssh/id_rsa,否则会报错: sign_and_send_pubkey: signing failed: agent refused operation root@xx.xx.xx.xx: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

在可以正常登录之后,就可以禁用ip+密码登录服务器了

1vim /etc/ssh/sshd_config
2
3# 禁用密码验证
4PasswordAuthentication no

也可以通过下方的命令指定使用密码登录,同时禁用密钥验证,这样可以确保一定是通过密钥登录

1ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no wenjinyu@1.2.3.4

使用技巧

使用别称

当然,每次输入一长串的命令登录比较麻烦,所以可以通过设置别称,从而简化登录命令,命令别称可以在主目录文件.bashrc中添加,例如服务器在纽约,可以使用别称ny

1# 编辑配置文件
2vim ~/.bashrc
3
4# 添加别称
5alias ny='ssh -p 23 -i ~/.ssh/id_rsa root@1.2.3.4'

这样,以后就可以直接输入ny就可以登录服务器了。

题外话 别称还是很有用的,对于经常需要输入一长串命令的情况来说,别称就可以做的很简单,比如linux上的“任务管理器”:top,这个命令可以查看当前运行的程序还有设备运行情况,但是默认刷新时间是3秒,要调快成每1秒刷新就可以输入top -d 1,把这个作为别称,则可以在.bashrc文件中插入alias top='top -d 1',这样子以后每次输入top都是每1秒刷新一次了,当然,top刷新时间也支持小数,如每0.5秒刷新一次:top -d 0.5

使用非root用户登录

直接使用root用户登录服务器比较危险,毕竟root权限真的可以为所欲为,所以还是新建一个普通用户用于登录服务器,如果需要root权限的时候再用sudo就可以了。

 1# 新建用户wenjinyu
 2adduser wenjinyu
 3
 4# 设置用户密码
 5passwd wenjinyu
 6
 7# 把用户wenjinyu添加进wheel用户组,用于给予wenjinyu用户sudo权限
 8gpasswd -a wenjinyu wheel
 9
10# 查询wheel用户组里是否有刚添加的用户
11lid -g wheel
12
13# 删除用户和相应目录
14userdel -r wenjinyu

创建用户有两个命令:useraddadduseruseradd 只是添加用户,但是这样的用户没有/home家目录,也没有提示设置密码,而 adduser 则家目录和密码都有。此时新增了用户 wenjinyu ,要用此用户登录服务器还需要复制公钥文件到 wenjinyu 用户目录下:

1# 复制公钥所在文件夹 /root/.ssh 到 wenjinyu 用户目录下
2cp -r /root/.ssh /home/wenjinyu
3
4# 因为是用 root 用户复制的文件,所以还需要将 wenjinyu 用户目录下的 .ssh 文件夹和其中的文件所有者设置为 wenjinyu
5chown -R wenjinyu:wenjinyu .ssh

此时可以尝试用 wenjinyu 用户登录,如果能登录成功,那么就在服务器禁用root用户登录

1# 编辑ssh配置文件
2sudo vim /etc/ssh/sshd_config
3
4# 将允许root用户登录一行中的yes改为no
5PermitRootLogin no

改完记得重启sshd

1systemctl restart sshd