用户名密码登陆
1 | [root@node1 ~]# ssh root@10.211.55.36 |
2 | The authenticity of host '10.211.55.36 (10.211.55.36)' can't be established. |
3 | RSA key fingerprint is 4a:26:57:1f:d8:aa:88:2f:73:9c:d5:df:44:b6:17:c1. |
4 | Are you sure you want to continue connecting (yes/no)? yes |
5 | Warning: Permanently added '10.211.55.36' (RSA) to the list of known hosts. |
6 | root@10.211.55.36's password: |
这里输入密码,即可登陆远程主机,这里需要我们验证的是远程主机是不是我们请求的目标主机,如果选择是,客户端会在~/.ssh/known_hosts中记录下远程主机的机器特征码,这样做的好处就是当该ip被给到别的主机或者网络中有人恶意模仿远程主机的ip,这里的验证就会通不过,这里也将提醒系统管理员是不是此ip的主机是不是做过修改。
如果远程主机ip与客户端记录的机器特征码不一致,会得到如下的警告信息,并且ssh会立即中断连接:
1 | [root@node1 .ssh]# ssh root@10.211.55.36 |
2 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
3 | @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ |
4 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
5 | IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! |
6 | Someone could be eavesdropping on you right now (man-in-the-middle attack)! |
7 | It is also possible that the RSA host key has just been changed. |
8 | The fingerprint for the RSA key sent by the remote host is |
9 | 80:26:e2:26:6a:8b:f0:59:f4:42:58:15:12:df:c8:e1. |
10 | Please contact your system administrator. |
11 | Add correct host key in /root/.ssh/known_hosts to get rid of this message. |
12 | Offending key in /root/.ssh/known_hosts:1 |
13 | RSA host key for 10.211.55.36 has changed and you have requested strict checking. |
14 | Host key verification failed. |
这样的确认机制是为ssh增加了安全,但是一些脚本中需要ssh连接新机器的时候这样验证是有碍自动化的实现的,以下方式可以忽略这样的确认机制:
bash脚本:
1 | [root@node2 ~]# ssh -o StrictHostKeyChecking=no 10.211.55.35 |
2 | Warning: Permanently added '10.211.55.35' (RSA) to the list of known hosts. |
3 | root@10.211.55.35's password: |
python脚本:
1 | import paramiko |
2 | ssh = paramiko.SSHClient() |
3 | #允许连接不在know_hosts的主机 |
4 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
公私钥登陆
首先让我们来去区分下加密与认证这两个基本概念:
- 加密是将数据资料加密,使得非法用户即使取得加密过的资料,也无法获取正确的资料内容数据,防止监听攻击。
- 认证是用来鉴定某个用户身份的合法性,确认身份后,系统才可以根据不同的身份给予不同权限。
基于公开密钥的加密过程
比如有两个用户Alice和Bob,Alice想把一段明文通过双钥加密技术发送给Bob,Bob有一对公钥和私钥,那么加密过程如下:
- Bob将他的公开密钥传给Alice。
- Alice用Bob的公开秘钥加密加密他的消息,然后传给Bob。
- Bob用他的私人密钥解密Alice的消息。
基于公开秘钥的认证过程
身份认证和加密就不同了,主要用户鉴别用户的真伪。这里我们只要鉴别一个用户的私钥是正确的,就可以鉴别这个用户的真伪。
- Alice用他的私人密钥对文件加密,从而对文件签名。
- Alice将签名的文件传送给Bob。
- Bob用Alice的公钥解密文件,从而验证签名。
Linux 公私钥登陆的实现
创建公私钥
1 | root@node2 ~]# ssh-keygen -t rsa |
2 | Generating public/private rsa key pair. |
3 | Enter file in which to save the key (/root/.ssh/id_rsa): |
4 | Enter passphrase (empty for no passphrase): |
5 | Enter same passphrase again: |
6 | Your identification has been saved in /root/.ssh/id_rsa. |
7 | Your public key has been saved in /root/.ssh/id_rsa.pub. |
8 | The key fingerprint is: |
9 | e2:ee:1a:7d:2d:12:0c:e8:45:29:05:e4:d4:d5:d6:75 root@node2 |
10 | The key's randomart image is: |
11 | +--[ RSA 2048]----+ |
12 | | .++oo.. . .. E | |
13 | | o.oo o . . | |
14 | | o.o . | |
15 | | . . o | |
16 | | . + S | |
17 | | o o . | |
18 | | . + o . | |
19 | | o o . | |
20 | | .oo | |
21 | +-----------------+ |
ssh-keygen [opotion]
- -t [rsa | dsa]:选择加密方式(默认rsa)
- -f /path/to/key: 创建后的密钥存放的目录(默认~/.ssh/)
- -N passphrase: 指定密码(可以在公私钥上再加一层密码认证)
将公钥给远程主机
在公私钥创建的目录下有id_rsa,id_rsa.pub,可以很容易知道id_rsa.pub为公钥,将里面的内容复制给远程主机的~/.ssh/authorized_keys里,这样我们就可以实现公私钥登陆了。我们来试试命令方式将密钥给远程主机:
1 | [root@node2 .ssh]# ssh-copy-id root@10.211.55.35 |
2 | The authenticity of host '10.211.55.35 (10.211.55.35)' can't be established. |
3 | RSA key fingerprint is bf:be:66:93:b3:6a:b2:c1:ec:55:04:eb:12:97:4d:ea. |
4 | Are you sure you want to continue connecting (yes/no)? yes |
5 | Warning: Permanently added '10.211.55.35' (RSA) to the list of known hosts. |
6 | root@10.211.55.35's password: |
7 | Now try logging into the machine, with "ssh 'root@10.211.55.35'", and check in: |
8 | |
9 | .ssh/authorized_keys |
10 | |
11 | to make sure we haven't added extra keys that you weren't expecting. |
这样我们就可以只需要输入一次密码,就可以免密码登陆了,这里未指定将哪个公钥传给远程主机,默认的公钥都是~/.ssh/id_rsd.pub,我们可以使用-i选项来指定公钥,那么问题又来了,用户只要盗取这机器上的私钥就可以登陆这台能登陆的所有机器,当然这里我们还可以为公私钥再设置密码,两层保护,但是这又回到每次需要密码的的阶段,双机互信的便利性有没有了,怎么做到既要安全又要便利呢?
SSH代理:密码+密钥,但无需输入密码
ssh-agent ssh代理
首先我们需要创建一个带密码的公私钥,并将公钥给远程主机,这时我们即使有私钥也需要密码登陆。
1 | [root@node1 .ssh]# eval `ssh-agent` |
2 | Agent pid 17239 |
3 | [root@node1 .ssh]# ssh-add ~/.ssh/id_rsa |
4 | Enter passphrase for /root/.ssh/id_rsa: |
5 | Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa) |
6 | [root@node1 .ssh]# ssh 10.211.55.36 |
7 | Last login: Mon Feb 13 05:15:28 2017 from 10.211.55.35 |
8 | [root@node2 ~]# exit |
9 | logout |
10 | Connection to 10.211.55.36 closed. |
11 | [root@node1 .ssh]# ssh 10.211.55.36 |
12 | Last login: Mon Feb 13 05:16:54 2017 from 10.211.55.35 |
我们只需要输入一次密码,就不需要输入密码登陆了,ssh-add 要我的密码短语来对专用密钥进行解密并存储在 ssh-agent 的高速缓存中以备使用。一旦您已经用 ssh-add 把专用密钥(或多个密钥)添加到 ssh-agent 的高速缓存中,那么您可以使用 scp 和 ssh 同远程系统建立连接而不必提供密码短语。
但是ssh-agent的不足处,当我们退出当前shell的时候,下次登陆我们还是需要重复上次操作,ssh-agent是存储在高速缓存中数据,所以如果我们需要当每次登陆的时候自动提醒输入密码,我设计了一个脚本:
1 | [root@node1 profile.d]# cat ssh-agent.sh |
2 | #!/bin/sh |
3 | if [ -f ~/.agent.env ]; then |
4 | . ~/.agent.env >/dev/null |
5 | if ! kill -0 $SSH_AGENT_PID >/dev/null 2>&1; then |
6 | echo “Stale agent file found. Spawning new agent…” |
7 | eval `ssh-agent |tee ~/.agent.env` |
8 | ssh-add |
9 | fi |
10 | else |
11 | echo “Starting ssh-agent…” |
12 | eval `ssh-agent |tee ~/.agent.env` |
13 | ssh-add |
14 | fi |
当然这还是很不方便,关键是这个无需要第三方程序即可实现,下面我们来使用第三方工具keychain来实现。
keychain 钥匙扣
1 | [root@test ~]# wget http://www.funtoo.org/archive/keychain/keychain-2.7.1.tar.bz2 |
2 | [root@test ~]# tar jxvf keychain-2.7.1.tar.bz2 |
3 | [root@test ~]# cd keychain-2.7.1 |
4 | [root@test keychain-2.7.1]# install -m 0755 keychain /usr/bin/ |
5 | [root@test ~]# vim .bash_profile |
6 | 在最后加入下面内容 |
7 | hostname=`uname -n` |
8 | pidf=~/.keychain/${hostname}-sh |
9 | keychain ~/.ssh/id_rsa |
10 | source $pidf > /dev/null |
11 | source ~/.bashrc |
这里我们我只需要输入一次公私钥的密码,就可以不需要输入密码登陆远程主机,即使退出当前shell,下次登入我们一样可以免密码登陆远程主机,真正实现密钥+密码,但是不需要密码,这样的好处,即使别人盗取私钥,还需要密码,而我们却不影响正常使用。