增加ssh無密碼信任連接的安全性


為了方便系統管理或者服務器運維自動化,我們通常要在服務器間做ssh無密碼信任連接。

環境:
目標主機    centos7    192.168.150.110
操作主機    centos7-cn 192.168.150.76    
第三主機    centos7-en 192.168.150.81

一、我們經常是這么做的
網上的教程大多數是這樣的。
在操作主機上,創建密鑰:

[root@centos7-cn ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
27:85:a5:ef:51:a0:61:0b:f6:9c:64:b1:76:66:0b:24 root@centos7-cn
The key's randomart image is:
+--[ RSA 2048]----+
|      E B.o      |
|     . X X .     |
|        % = .    |
|       . B o     |
|        S =      |
|         + .     |
|          .      |
|                 |
|                 |
+-----------------+
[root@centos7-cn ~]# 
[root@centos7-cn ~]# ls .ssh
id_rsa  id_rsa.pub  known_hosts
[root@centos7-cn ~]#

id_rsa是私鑰,id_rsa.pub是公鑰。復制公鑰到目標服務器,然后就可以無密碼登錄了:

[root@centos7-cn ~]# ssh-copy-id root@192.168.150.110
The authenticity of host '192.168.150.110 (192.168.150.110)' can't be established.
ECDSA key fingerprint is 99:e2:ca:93:ac:01:fc:df:e9:87:73:ec:0e:98:bb:77.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.150.110's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.150.110'"
and check to make sure that only the key(s) you wanted were added.

[root@centos7-cn ~]#
[root@centos7-cn ~]# ssh root@192.168.150.110
Last login: Tue Oct 28 11:41:12 2014 from centos7-cn
[root@centos7 ~]#
[root@centos7 ~]# ip a show enp0s3 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:15:35:d2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.150.110/24 brd 192.168.150.255 scope global enp0s3
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe15:35d2/64 scope link
       valid_lft forever preferred_lft forever
[root@centos7 ~]#

這固然方便,但是網上教程中在ssh-keygen創建密鑰的時候,
“Enter passphrase (empty for no passphrase):”
和下一行
“Enter same passphrase again:”
兩處都是直接回車,就是說沒有創建口令短語(passphrase)。

那么問題來了,學挖掘機嗎?;),如果你把私鑰文件 ~/.ssh/id_rsa 復制到其他Linux主機上,會怎么樣呢?做一下試試。

在第三主機上,注意用戶並不是root:

[opuser@centos7-en ~]$ mkdir .ssh
[opuser@centos7-en ~]$ scp root@192.168.150.76:~/.ssh/id_rsa ~/.ssh
root@192.168.150.76's password:
id_rsa                                                                                100% 1679     1.6KB/s   00:00
[opuser@centos7-en ~]$
[opuser@centos7-en ~]$ ssh root@192.168.150.110
Last login: Tue Oct 28 11:43:04 2014 from centos7-cn
[root@centos7 ~]#

已經順利的進入了。
就是說呢,如果操作主機上沒有口令短語的id_rsa文件被別人獲得,你的服務器基本就是人家的了。

二、使用口令短語
我們把目標主機的 /root/.ssh/authorized_keys 移走,在操作主機上重新生成一對兒密鑰,這回加上口令短語(至少5個字符),再ssh-copy-id 到目標主機,試試連接:

[root@centos7-cn ~]# ssh root@192.168.150.110
Enter passphrase for key '/root/.ssh/id_rsa': <輸入正確的口令短語>
Last login: Tue Oct 28 11:46:56 2014 from 192.168.150.76
[root@centos7 ~]#

必須輸入正確的口令短語才能登錄目標主機。

在第三主機上,把原來的id_rsa文件備份一下,把帶有口令短語的id_rsa文件復制過來:

[opuser@centos7-en ~]$ cp .ssh/id_rsa /tmp
[opuser@centos7-en ~]$ scp root@192.168.150.76:~/.ssh/id_rsa ~/.ssh
root@192.168.150.76's password:
id_rsa                                                                                100% 1766     1.7KB/s   00:00
[opuser@centos7-en ~]$
[opuser@centos7-en ~]$ ssh root@192.168.150.110
Enter passphrase for key '/home/opuser/.ssh/id_rsa': <輸入錯誤的口令短語>
Enter passphrase for key '/home/opuser/.ssh/id_rsa': <輸入錯誤的口令短語>
Enter passphrase for key '/home/opuser/.ssh/id_rsa': <輸入正確的口令短語>
Last login: Tue Oct 28 11:48:18 2014 from 192.168.150.76
[root@centos7 ~]#

依然是只有輸入正確的口令短語才能連接目標主機。
需要注意一點,第三主機僅僅復制了id_rsa,是不能做ssh-copy-id的,因為還沒復制id_rsa.pub。
比較兩個id_rsa文件,除了密鑰本身不同了,加口令后的文件還多了三行(含一個空行):

Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,395D869B2463C1038A189E373CEB0C43

刪除這三行並不能去除口令,呵呵;同時正確的口令也失效了,呵呵呵呵;而且呢,ssh-keygen的man page說了,如果口令短語忘了是沒有辦法找回的,只能重新生成密鑰。


三、增加口令短語
那么在生產環境里,已經部署了不帶口令短語的密鑰,怎么增加口令短語呢?這樣:

[root@centos7-cn ~]# ssh-keygen -p
Enter file in which the key is (/root/.ssh/id_rsa):
Key has comment '/root/.ssh/id_rsa'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.

這時候再試試連接目標主機,除了需要輸入口令短語,登錄服務器依舊不需要密碼。
但是僅僅增加口令短語並不能解決問題,因為改動的是操作主機上的id_rsa文件(私鑰),目標主機上保存的是毫無變化的公鑰,原來未加口令的私鑰依然有效!!

那么在操作主機上重新ssh-copy-id呢?試試:

[root@centos7-cn ~]# ssh-copy-id root@192.168.150.110
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
Enter passphrase for key '/root/.ssh/id_rsa':

/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.

首先,需要輸入口令短語;其次,提示說的明明白白,你的公鑰已經在遠程服務器上了,不會再次復制。
所以沒有辦法了,增加口令沒有太多實際意義。必須刪除目標主機原有的公鑰(保存在目標主機的 /root/.ssh/authorized_keys),刪除操作主機舊的密鑰並重新生成一套帶口令的,再ssh-copy-id到目標主機。這可能是個浩大的工程。。。

ssh-keygen -p 選項也可以修改口令短語,只是在輸入新口令之前需要先輸入舊口令。

四、讓系統記住口令短語
那么現在又一個問題來了,加了口令短語,私鑰安全了,但是登錄麻煩了,自動化運維也不可能了。怎么辦?
我們可以用ssh-agent(ssh代理守護進程)。

啟動代理守護進程:

[root@centos7-cn ~]# eval `ssh-agent`
Agent pid 11844
[root@centos7-cn ~]# 

將私鑰添加到代理守護進程:

[root@centos7-cn ~]# ssh-add
Enter passphrase for /root/.ssh/id_rsa:         【輸入口令短語】
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)
[root@centos7-cn ~]# 

試試連接目標主機:

[root@centos7-cn ~]# ssh root@192.168.150.110
Last login: Wed Oct 29 08:30:41 2014 from 192.168.150.100
[root@centos7 ~]#

OK了!

其他需要知道的:
列出代理守護進程保存的私鑰:

[root@centos7-cn ~]# ssh-add -l 2048 5f:10:15:3a:ac:61:01:79:29:ac:8c:d7:f0:84:c3:89 /root/.ssh/id_rsa (RSA)
[root@centos7-cn ~]# 

刪除代理守護進程保存的私鑰:

[root@centos7-cn ~]# ssh-add -D
All identities removed.
[root@centos7-cn ~]#

再試試連接目標主機:

[root@centos7-cn ~]# ssh root@192.168.150.110
Enter passphrase for key '/root/.ssh/id_rsa':

這時候又需要口令短語了。
 
參考:http://docs.oracle.com/cd/E26926_01/html/E25889/sshuser-15.html


五、順便說說eval
這個bash內部指令非常有意思,它是將后面的 `` 符號(鍵盤左上角跟~符一起的那個,不是單引號哈!)內的指令執行之后,把輸出結果再執行一遍,比如上文的 eval `ssh-agent`。

先看看 ssh-agent 單獨執行結果:

[root@centos7-cn ~]# ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-CDZB3GtAT0MT/agent.11758; export SSH_AUTH_SOCK;
SSH_AGENT_PID=11759; export SSH_AGENT_PID;
echo Agent pid 11759;
[root@centos7-cn ~]#

eval `ssh-agent` 就是將ssh-agent的輸出結果再執行一次,相當於:

[root@centos7-cn ~]# SSH_AUTH_SOCK=/tmp/ssh-CDZB3GtAT0MT/agent.11758; export SSH_AUTH_SOCK;
[root@centos7-cn ~]# SSH_AGENT_PID=11759; export SSH_AGENT_PID;
[root@centos7-cn ~]# echo Agent pid 11759;

所以 eval `ssh-agent` 的執行結果就是:
后台運行ssh-agent,並且在當前會話輸出兩個環境變量SSH_AUTH_SOCK、SSH_AGENT_PID,然后再顯示 Agent pid 11759 。

我們試一下:

[root@centos7-cn ~]# eval `ssh-agent`
Agent pid 11877
[root@centos7-cn ~]# echo $SSH_AUTH_SOCK /tmp/ssh-2Aq37RrIkeOH/agent.11876
[root@centos7-cn ~]# echo $SSH_AGENT_PID 11877
[root@centos7-cn ~]# 

注意,這里得到的Pid跟單獨執行的ssh-agent不同了,pgrep ssh-agent 會看到兩個進程號:

[root@centos7-cn ~]# pgrep ssh-agent
11759
11877
[root@centos7-cn ~]#

還要注意,退出當前會話並不會殺死ssh-agent進程。手工殺死進程除了上述的 pgrep 指令,還有ssh-agent -k 可以。試試:

[root@centos7-cn ~]# ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-gm8UdqqlTXeb/agent.14140; export SSH_AUTH_SOCK;
SSH_AGENT_PID=14141; export SSH_AGENT_PID;
echo Agent pid 14141;
[root@centos7-cn ~]#
[root@centos7-cn ~]# ssh-agent -k
SSH_AGENT_PID not set, cannot kill agent

找不到SSH_AGENT_PID環境變量,這個指令選項無效。那么手工輸出一下吧:

[root@centos7-cn ~]#
[root@centos7-cn ~]# SSH_AGENT_PID=14141; export SSH_AGENT_PID;
[root@centos7-cn ~]#
[root@centos7-cn ~]# ssh-agent -k
unset SSH_AUTH_SOCK;
unset SSH_AGENT_PID;
echo Agent pid 14141 killed;
[root@centos7-cn ~]#

這回可以了。所以 ssh-agent 命令最好還是用 eval `ssh-agent` 執行更方便,但是要記住不能重復執行,ssh-agent -k 只負責最后一個進程,道理呢?參考ssh-agent -k指令輸出,自己琢磨一下吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM