SSH 默認采用密碼登錄,這種方法有很多缺點,簡單的密碼不安全,復雜的密碼不容易記憶,每次手動輸入也很麻煩。密鑰登錄是比密碼登錄更好的解決方案。
密鑰(key)是一個非常大的數(shù)字,通過加密算法得到。對稱加密只需要一個密鑰,非對稱加密需要兩個密鑰成對使用,分為公鑰(public key)和私鑰(private key)。
SSH 密鑰登錄采用的是非對稱加密,每個用戶通過自己的密鑰登錄。其中,私鑰必須私密保存,不能泄漏;公鑰則是公開的,可以對外發(fā)送。它們的關(guān)系是,公鑰和私鑰是一一對應的,每一個私鑰都有且僅有一個對應的公鑰,反之亦然。
如果數(shù)據(jù)使用公鑰加密,那么只有使用對應的私鑰才能解密,其他密鑰都不行;反過來,如果使用私鑰加密(這個過程一般稱為“簽名”),也只有使用對應的公鑰解密。
SSH 密鑰登錄分為以下的步驟。
預備步驟,客戶端通過ssh-keygen
生成自己的公鑰和私鑰。
第一步,手動將客戶端的公鑰放入遠程服務(wù)器的指定位置。
第二步,客戶端向服務(wù)器發(fā)起 SSH 登錄的請求。
第三步,服務(wù)器收到用戶 SSH 登錄的請求,發(fā)送一些隨機數(shù)據(jù)給用戶,要求用戶證明自己的身份。
第四步,客戶端收到服務(wù)器發(fā)來的數(shù)據(jù),使用私鑰對數(shù)據(jù)進行簽名,然后再發(fā)還給服務(wù)器。
第五步,服務(wù)器收到客戶端發(fā)來的加密簽名后,使用對應的公鑰解密,然后跟原始數(shù)據(jù)比較。如果一致,就允許用戶登錄。
ssh-keygen
命令:生成密鑰
密鑰登錄時,首先需要生成公鑰和私鑰。OpenSSH 提供了一個工具程序ssh-keygen
命令,用來生成密鑰。
直接輸入ssh-keygen
,程序會詢問一系列問題,然后生成密鑰。
$ ssh-keygen
通常做法是使用-t
參數(shù),指定密鑰的加密算法。
$ ssh-keygen -t dsa
上面示例中,-t
參數(shù)用來指定密鑰的加密算法,一般會選擇 DSA 算法或 RSA 算法。如果省略該參數(shù),默認使用 RSA 算法。
輸入上面的命令以后,ssh-keygen
會要求用戶回答一些問題。
$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_dsa): press ENTER
Enter passphrase (empty for no passphrase): ********
Enter same passphrase again: ********
Your identification has been saved in /home/username/.ssh/id_dsa.
Your public key has been saved in /home/username/.ssh/id_dsa.pub.
The key fingerprint is:
14:ba:06:98:a8:98:ad:27:b5:ce:55:85:ec:64:37:19 username@shell.isp.com
上面示例中,執(zhí)行ssh-keygen
命令以后,會出現(xiàn)第一個問題,詢問密鑰保存的文件名,默認是~/.ssh/id_dsa
文件,這個是私鑰的文件名,對應的公鑰文件~/.ssh/id_dsa.pub
是自動生成的。用戶的密鑰一般都放在主目錄的.ssh
目錄里面。
如果選擇rsa
算法,生成的密鑰文件默認就會是~/.ssh/id_rsa
(私鑰)和~/.ssh/id_rsa.pub
(公鑰)。
接著,就會是第二個問題,詢問是否要為私鑰文件設(shè)定密碼保護(passphrase)。這樣的話,即使入侵者拿到私鑰,還是需要破解密碼。如果為了方便,不想設(shè)定密碼保護,可以直接按回車鍵,密碼就會為空。后面還會讓你再輸入一次密碼,兩次輸入必須一致。注意,這里“密碼”的英文單詞是 passphrase,這是為了避免與 Linux 賬戶的密碼單詞 password 混淆,表示這不是用戶系統(tǒng)賬戶的密碼。
最后,就會生成私鑰和公鑰,屏幕上還會給出公鑰的指紋,以及當前的用戶名和主機名作為注釋,用來識別密鑰的來源。
公鑰文件和私鑰文件都是文本文件,可以用文本編輯器看一下它們的內(nèi)容。公鑰文件的內(nèi)容類似下面這樣。
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com
上面示例中,末尾的username@shell.isp.com
是公鑰的注釋,用來識別不同的公鑰,表示這是哪臺主機(shell.isp.com
)的哪個用戶(username
)的公鑰,不是必需項。
注意,公鑰只有一行。因為它太長了,所以上面分成三行顯示。
下面的命令可以列出用戶所有的公鑰。
$ ls -l ~/.ssh/id_*.pub
生成密鑰以后,建議修改它們的權(quán)限,防止其他人讀取。
$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub
ssh-keygen
的命令行配置項,主要有下面這些。
(1)-b
-b
參數(shù)指定密鑰的二進制位數(shù)。這個參數(shù)值越大,密鑰就越不容易破解,但是加密解密的計算開銷也會加大。
一般來說,-b
至少應該是1024
,更安全一些可以設(shè)為2048
或者更高。
(2)-C
-C
參數(shù)可以為密鑰文件指定新的注釋,格式為username@host
。
下面命令生成一個4096位 RSA 加密算法的密鑰對,并且給出了用戶名和主機名。
$ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com"
(3)-f
-f
參數(shù)指定生成的私鑰文件。
$ ssh-keygen -t dsa -f mykey
上面命令會在當前目錄生成私鑰文件mykey
和公鑰文件mykey.pub
。
(4)-F
-F
參數(shù)檢查某個主機名是否在known_hosts
文件里面。
$ ssh-keygen -F example.com
(5)-N
-N
參數(shù)用于指定私鑰的密碼(passphrase)。
$ ssh-keygen -t dsa -N secretword
(6)-p
-p
參數(shù)用于重新指定私鑰的密碼(passphrase)。它與-N
的不同之處在于,新密碼不在命令中指定,而是執(zhí)行后再輸入。ssh 先要求輸入舊密碼,然后要求輸入兩遍新密碼。
(7)-R
-R
參數(shù)將指定的主機公鑰指紋移出known_hosts
文件。
$ ssh-keygen -R example.com
(8)-t
-t
參數(shù)用于指定生成密鑰的加密算法,一般為dsa
或rsa
生成密鑰以后,公鑰必須上傳到服務(wù)器,才能使用公鑰登錄。
OpenSSH 規(guī)定,用戶公鑰保存在服務(wù)器的~/.ssh/authorized_keys
文件。你要以哪個用戶的身份登錄到服務(wù)器,密鑰就必須保存在該用戶主目錄的~/.ssh/authorized_keys
文件。只要把公鑰添加到這個文件之中,就相當于公鑰上傳到服務(wù)器了。每個公鑰占據(jù)一行。如果該文件不存在,可以手動創(chuàng)建。
用戶可以手動編輯該文件,把公鑰粘貼進去,也可以在本機計算機上,執(zhí)行下面的命令。
$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
上面示例中,user@host
要替換成你所要登錄的用戶名和主機名。
注意,authorized_keys
文件的權(quán)限要設(shè)為644
,即只有文件所有者才能寫。如果權(quán)限設(shè)置不對,SSH 服務(wù)器可能會拒絕讀取該文件。
$ chmod 644 ~/.ssh/authorized_keys
只要公鑰上傳到服務(wù)器,下次登錄時,OpenSSH 就會自動采用密鑰登錄,不再提示輸入密碼。
$ ssh -l username shell.isp.com
Enter passphrase for key '/home/you/.ssh/id_dsa': ************
Last login: Mon Mar 24 02:17:27 2014 from ex.ample.com
shell.isp.com>
上面例子中,SSH 客戶端使用私鑰之前,會要求用戶輸入密碼(passphrase),用來解開私鑰。
OpenSSH 自帶一個ssh-copy-id
命令,可以自動將公鑰拷貝到遠程服務(wù)器的~/.ssh/authorized_keys
文件。如果~/.ssh/authorized_keys
文件不存在,ssh-copy-id
命令會自動創(chuàng)建該文件。
用戶在本地計算機執(zhí)行下面的命令,就可以把本地的公鑰拷貝到服務(wù)器。
$ ssh-copy-id -i key_file user@host
上面命令中,-i
參數(shù)用來指定公鑰文件,user
是所要登錄的賬戶名,host
是服務(wù)器地址。如果省略用戶名,默認為當前的本機用戶名。執(zhí)行完該命令,公鑰就會拷貝到服務(wù)器。
注意,公鑰文件可以不指定路徑和.pub
后綴名,ssh-copy-id
會自動在~/.ssh
目錄里面尋找。
$ ssh-copy-id -i id_rsa user@host
上面命令中,公鑰文件會自動匹配到~/.ssh/id_rsa.pub
。
ssh-copy-id
會采用密碼登錄,系統(tǒng)會提示輸入遠程服務(wù)器的密碼。
注意,ssh-copy-id
是直接將公鑰添加到authorized_keys
文件的末尾。如果authorized_keys
文件的末尾不是一個換行符,會導致新的公鑰添加到前一個公鑰的末尾,兩個公鑰連在一起,使得它們都無法生效。所以,如果authorized_keys
文件已經(jīng)存在,使用ssh-copy-id
命令之前,務(wù)必保證authorized_keys
文件的末尾是換行符(假設(shè)該文件已經(jīng)存在)。
私鑰設(shè)置了密碼以后,每次使用都必須輸入密碼,有時讓人感覺非常麻煩。比如,連續(xù)使用scp
命令遠程拷貝文件時,每次都要求輸入密碼。
ssh-agent
命令就是為了解決這個問題而設(shè)計的,它讓用戶在整個 Bash 對話(session)之中,只在第一次使用 SSH 命令時輸入密碼,然后將私鑰保存在內(nèi)存中,后面都不需要再輸入私鑰的密碼了。
第一步,使用下面的命令新建一次命令行對話。
$ ssh-agent bash
上面命令中,如果你使用的命令行環(huán)境不是 Bash,可以用其他的 Shell 命令代替。比如zsh
和fish
。
如果想在當前對話啟用ssh-agent
,可以使用下面的命令。
$ eval `ssh-agent`
上面命令中,ssh-agent
會先自動在后臺運行,并將需要設(shè)置的環(huán)境變量輸出在屏幕上,類似下面這樣。
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-22841-agent; export SSH_AUTH_SOCK;
SSH_AGENT_PID=22842; export SSH_AGENT_PID; echo Agent pid 22842;
eval
命令的作用,就是運行上面的ssh-agent
命令的輸出,設(shè)置環(huán)境變量。
第二步,在新建的 Shell 對話里面,使用ssh-add
命令添加默認的私鑰(比如~/.ssh/id_rsa
,或~/.ssh/id_dsa
,或~/.ssh/id_ecdsa
,或~/.ssh/id_ed25519
)。
$ ssh-add
Enter passphrase for /home/you/.ssh/id_dsa: ********
Identity added: /home/you/.ssh/id_dsa (/home/you/.ssh/id_dsa)
上面例子中,添加私鑰時,會要求輸入密碼。以后,在這個對話里面再使用密鑰時,就不需要輸入私鑰的密碼了,因為私鑰已經(jīng)加載到內(nèi)存里面了。
如果添加的不是默認私鑰,ssh-add
命令需要顯式指定私鑰文件。
$ ssh-add my-other-key-file
上面的命令中,my-other-key-file
就是用戶指定的私鑰文件。
第三步,使用 ssh 命令正常登錄遠程服務(wù)器。
$ ssh remoteHost
上面命令中,remoteHost
是遠程服務(wù)器的地址,ssh 使用的是默認的私鑰。這時如果私鑰設(shè)有密碼,ssh 將不再詢問密碼,而是直接取出內(nèi)存里面的私鑰。
如果要使用其他私鑰登錄服務(wù)器,需要使用 ssh 命令的-i
參數(shù)指定私鑰文件。
$ ssh –i OpenSSHPrivateKey remoteHost
最后,如果要退出ssh-agent
,可以直接退出子 Shell(按下 Ctrl + d),也可以使用下面的命令。
$ ssh-agent -k
ssh-add
命令
ssh-add
命令用來將私鑰加入ssh-agent
,它有如下的參數(shù)。
(1)-d
-d
參數(shù)從內(nèi)存中刪除指定的私鑰。
$ ssh-add -d name-of-key-file
(2)-D
-D
參數(shù)從內(nèi)存中刪除所有已經(jīng)添加的私鑰。
$ ssh-add -D
(3)-l
-l
參數(shù)列出所有已經(jīng)添加的私鑰。
$ ssh-add -l
為了安全性,啟用密鑰登錄之后,最好關(guān)閉服務(wù)器的密碼登錄。
對于 OpenSSH,具體方法就是打開服務(wù)器 sshd 的配置文件/etc/ssh/sshd_config
,將PasswordAuthentication
這一項設(shè)為no
。
PasswordAuthentication no
修改配置文件以后,不要忘了重新啟動 sshd,否則不會生效。