OpenSSH 密鑰管理:ssh-agent和keychain

  • 摘要:ssh-agent 是專爲既令人愉快又安全的處理 RSA 和 DSA 密鑰而設計的特殊程序,它包括在OpenSSH分發內(請參閱 本系列文章的第 1 部分以得到關於 RSA 和 DSA 認證的介紹)。不同於 ssh , ssh-agent 是個長時間持續運行的守護進程(daemon),設計它的唯一目的就是對解密的專用密鑰進行高速緩存。

 

介紹 ssh-agent
ssh-agent 是專爲既令人愉快又安全的處理 RSA 和 DSA 密鑰而設計的特殊程序,它包括在OpenSSH分發內(請參閱 本系列文章的第 1 部分以得到關於 RSA 和 DSA 認證的介紹)。不同於 sshssh-agent 是個長時間持續運行的守護進程(daemon),設計它的唯一目的就是對解密的專用密鑰進行高速緩存。

ssh 包含的內建支持允許它同 ssh-agent 通信,允許 ssh 不必每次新連接時都提示您要密碼才能獲取解密的專用密鑰。對於 ssh-agent ,您只要使用 ssh-add 把專用密鑰添加到 ssh-agent 的高速緩存中。這是個一次性過程;用過 ssh-add 之後, ssh 將從 ssh-agent 獲取您的專用密鑰,而不會提示要密碼短語來煩您了。

使用 ssh-agent
讓我們看一下整個 ssh-agent 密鑰高速緩存系統的工作過程。 ssh-agent 啓動時,在脫離 shell(外殼程序)並繼續在後臺運行之前它會輸出一些重要的環境變量。以下是 ssh-agent 開始時生成的輸出的一些示例:

% ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-XX4LkMJS/agent.26916; export SSH_AUTH_SOCK;
SSH_AGENT_PID=26917; export SSH_AGENT_PID;
echo Agent pid 26917;

正如您所看到的,事實上 ssh-agent 的輸出是一系列 bash 命令;如果這些命令被執行,則將設置兩個環境變量:SSH_AUTH_SOCK 和 SSH_AGENT_PID。內含的 export 命令使這些環境變量對之後運行的任何附加命令都可用。唔, 如果 shell 真對這些行進行計算,這一切纔會發生,但是此時它們只是被打印到標準輸出(stdout)而已。要使之確定,我們可以象下面這樣調用 ssh-agent

eval `ssh-agent`

這個命令先讓 bash 運行 ssh-agent 後對 ssh-agent 的輸出進行計算。shell 以這種調用方式(使用反引號,而不是普通的單引號)設置並導出 SSH_AGENT_PID 及 SSH_AUTH_SOCK 變量,使這些變量對於您在登錄會話期間啓動的所有新進程都可用。

啓動 ssh-agent 的最佳方式就是把上面這行添加到您的 ~/.bash_profile 中;這樣,在您的登錄 shell 中啓動的所有程序都將看到環境變量,而且能夠定位 ssh-agent ,並在需要的時候向其查詢密鑰。尤其重要的環境變量是 SSH_AUTH_SOCK;SSH_AUTH_SOCK 包含有 sshscp 可以用來同 ssh-agent 建立對話的 UNIX 域套接字的路徑。

使用 ssh-add
但是 ssh-agent 啓動時高速緩存當然是空的,裏面不會有解密的專用密鑰。在我們真能使用 ssh-agent 之前,首先還需要使用 ssh-add 命令把我們的專用密鑰添加到 ssh-agent 的高速緩存中。下面的示例中,我使用 ssh-add 把我的 ~/.ssh/identity 專用 RSA 密鑰添加到 ssh-agent 的高速緩存中:

# ssh-add ~/.ssh/identity
Need passphrase for /home/drobbins/.ssh/identity
Enter passphrase for /home/drobbins/.ssh/identity 
(enter passphrase)

正如您所看到的, ssh-add 要我的密碼短語來對專用密鑰進行解密並存儲在 ssh-agent 的高速緩存中以備使用。一旦您已經用 ssh-add 把專用密鑰(或多個密鑰)添加到 ssh-agent 的高速緩存中, 在當前的 shell 中(如果您在 ~/.bash_profile 中啓動 ssh-agent ,情況應當是這樣)定義 SSH_AUTH_SOCK,那麼您可以使用 scpssh 同遠程系統建立連接而不必提供密碼短語。

ssh-agent 的不足之處
ssh-agent 確實棒,但是其缺省配置還是會留給我們一些小小的不便。讓我們來看一下這些不足吧。

首先,~/.bash_profile 中的 eval `ssh-agent` 使每次登錄會話都會啓動一個新的 ssh-agent 副本;這不僅僅是有一丁點兒浪費,而且還意味着您得使用 ssh-add 向每個新的 ssh-agent 副本添加專用密鑰。如果您只想打開系統上的一個終端或控制檯,這沒什麼大不了的,但是我們中大多數人打開相當多的終端,每次新打開控制檯都需要鍵入密碼短語。從技術角度講,既然一個 ssh-agent 進程的確應當足夠了,要是我們還需這樣做,這毫無道理。

有關 ssh-agent 的缺省設置的另外一個問題是它同 cron 作業不兼容。由於 cron 作業是 cron 進程啓動的,這些作業無法從它們的環境中繼承 SSH_AUTH_SOCK 變量,因而也無從知道 ssh-agent 進程正在運行以及如何同它聯繫。事實證明這個問題也是可以修補的。

開始用到 keychain
爲了解決這些問題,我編寫了一個有用的 ssh-agent 前端,它基於 bash,叫做 keychainkeychain 的特別之處在於它允許 每個系統使用一個 ssh-agent 進程,而非每次登錄會話。這意味着您只需對每個專用密鑰執行一次 ssh-add ,就一次。正如我們稍後將要看到的一樣, keychain 甚至有助於優化 ssh-add ,而這隻要它試圖向那些正在運行的 ssh-agent 添加其高速緩存中沒有的專用密鑰。

以下對 keychain 如何工作從頭到尾瀏覽一遍。從 ~/.bash_profile 中啓動時, keychain 將首先查看 ssh-agent 是否已經在運行了。如果沒有,它就啓動 ssh-agent 並把重要的 SSH_AUTH_SOCK 和 SSH_AGENT_PID 變量記錄在 ~/.ssh-agent 文件中,一方面爲了安全而保存,另一方面也是爲了以後的使用。這是啓動 keychain 的最佳途徑;同使用平淡無奇的老式 ssh-agent 一樣,我們在 ~/.bash_profile 內部執行必要的配置:

#!/bin/bash
#example ~/.bash_profile file
/usr/bin/keychain ~/.ssh/id_rsa
#redirect ~/.ssh-agent output to /dev/null to zap the annoying
#"Agent PID" message
source ~/.ssh-agent > /dev/null

正如您所看到的,對於 keychain 我們用 source 命令讀入並執行 ~/.ssh-agent 文件,而不是象我們直接使用 ssh-agent 時所做的對輸出進行計算。但是,結果是一樣的:定義了非常重要的 SSH_AUTH_SOCK,而且正運行 ssh-agent 以備使用。同時,因爲 SSH_AUTH_SOCK 被記錄在 ~/.ssh-agent 裏,只要用 source 命令讀入並執行 ~/.ssh-agent 文件,就可以輕易的把我們的 shell 腳本及 cron 作業同 ssh-agent 連接起來。 keychain 本身也利用了這個文件;您應該記住 keychain 啓動時,它會查看現有的 ssh-agent 是否正在運行。如果是,則它使用 ~/.ssh-agent 文件來獲得適當的 SSH_AUTH_SOCK 設置,這樣就使 keychain 能使用現有的代理程序而不必新啓動一個。只有在 ~/.ssh-agent 文件無效(指向一個不存在的 ssh-agent )或 ~/.ssh-agent 文件本身不存在時, keychain 纔會啓動新的 ssh-agent 進程。

安裝 keychain
安裝 keychain 很容易。首先,直接到 keychain 工程主頁下載可用的 keychain 源壓縮文檔的最新版本。然後,安裝如下:

# tar xzvf keychain-1.0.tar.gz
# cd keychain-1.0
# install -m0755 keychain /usr/bin

既然 keychain 在 /usr/bin/ 目錄下,就請把它添加到您的 ~/.bash_profile 中,並把您的專用密鑰路徑作爲參數。下面是一個既標準又好的啓用 keychain 的 ~/.bash_profile:

啓用 keychain 的 ~/.bash_profile 示例
#!/bin/bash
#on this next line, we start keychain and point it to the private keys that
#we'd like it to cache
/usr/bin/keychain ~/.ssh/id_rsa ~/.ssh/id_dsa
source ~/.ssh-agent > /dev/null
#sourcing ~/.bashrc is a good thing
source ~/.bashrc

Keychain 生效
您一爲每次登錄時調用 keychain 配置好了 ~/.bash_profile,就請先退出再登錄回來。在您再次登錄時, keychain 將啓動 ssh-agent ,並記錄下 ~/.ssh-agent 中的代理程序環境變量設置,然後提示您輸入在 ~/.bash_profile 中的 keychain 命令行指定的所有專用密鑰的密碼短語:

Keychain 首次啓動

您一輸入密碼短語,您的專用密鑰就會被高速緩存,同時 keychain 將退出。接着,用 source 命令讀入並執行 ~/.ssh-agent,初始化您的登錄會話以便同 ssh-agent 一起使用。現在,如果您退出,然後再登錄回來,將發現 keychain 會找到現有的 ssh-agent 進程;在您退出時,它並沒有終止。此外, keychain 將驗證您指定的專用密鑰是否已經在 ssh-agent 的高速緩存中了。如果沒有,那麼將會提示您輸入正確的密碼短語,但如果一切進展順利,則現有 ssh-agent 仍包含有您以前添加的專用密鑰;這意味着不會提示您輸入密碼:

Keychain 找到現有的 ssh-agent

祝賀您!您剛纔已經登錄了,應該能夠用 sshscp 連到遠程系統;您不必一登錄就使用 ssh-add ,而且 sshscp 也不會提示您輸入密碼短語。事實上,只要初始的 ssh-agent 進程一直在運行,您就能不提供密碼登錄並建立 ssh 連接。 ssh-agent 進程持續運行直到機器重新啓動也是很有可能的;由於您最可能在 Linux 系統上這樣設置,所以也許一連幾個月您都不必輸入密碼短語!歡迎來到安全的、使用 RSA 和 DSA 認證無密碼連接的世界。

繼續創建幾個新的登錄會話,您會發現每次 keychain 都會準確無誤的“鉤住”到同一 ssh-agent 進程。不要忘記您也可以使 cron 作業和腳本“鉤住”正在運行的 ssh-agent 進程。要在 shell 腳本和 cron 作業中使用 sshscp 命令,只要確保先用 source 命令讀入並執行 ~/.ssh-agent:

source ~/.ssh-agent

然後,隨後所有的 sshscp 命令就能夠找到當前正在運行的 ssh-agent ,並且象您在 shell 中一樣能建立安全的無密碼連接。

Keychain 選項
您啓動並運行 keychain 後,一定要鍵入 keychain --help 以熟悉 keychain 所有的命令行選項。我們要特別看一下這個選項: -clear 選項。

還記得我在第 1 部分裏闡釋了使用不加密專用密鑰是一種危險的做法,因爲這種做法允許其它人盜用您的專用密鑰不提供密碼就可以從所有系統登錄到您的遠程帳戶。唔,儘管 keychain 不易遭到這種濫用(只要您使用加密的專用密鑰就行),但仍存在有可能可以利用的弱點,同 keychain 使得“鉤住”長時間持續運行的 ssh-agent 進程如此容易這一事實直接相關。我想,如果闖入者以某種方式能想出我的密碼或密碼短語,還能登錄進入我的本地系統,會發生什麼事情呢?如果出於某種原因他們能以我的用戶名登錄,那麼 keychain 就會立刻授權他們訪問我的解密的專用密鑰,使他們可以輕而易舉的訪問我的其它帳戶。

現在,在繼續下面的內容之前,讓我們先客觀的表述一下安全威脅。如果由於某種原因一些惡意的用戶能以我的身份登錄, keychain 確實會允許他們訪問我的遠程帳戶。但,儘管如此,這位闖入者要偷到我的加密的專用密鑰非常困難,因爲它們仍舊在磁盤上保持着加密狀態。而且,得到我的專用密鑰訪問權要求用戶真的以我的身份 登錄,不單單是閱讀我的目錄中的文件而已。因此,濫用 ssh-agent 是比只偷到一個不加密的專用密鑰困難得多的一項任務,後者只需要闖入者通過某種手段獲得我在 ~/.ssh 裏的文件的訪問權,而不管是否是以我的身份登錄。不過,如果闖入者能夠成功的以我的身份登錄,通過使用我的加密專用密鑰他們造成相當多的額外損害。所以,如果您剛好在您不頻繁登錄或沒有對安全缺口進行密切監視的一臺服務器上使用 keychain ,那麼請您考慮使用 --clear 選項以提供附加的安全層。

--clear 選項允許您讓 keychain 假定把每次以您的帳戶的新登錄都當作是可能的安全缺口,直到能證明並非如此。當您啓動 keychain 時使用了 --clear 選項時,您登錄的時候 keychain 會立即刷新 ssh-agent 的高速緩存裏的所有專用密鑰,此後才執行它的常規職責。這樣,如果您是一位闖入者,則 keychain 會提示您輸入密碼短語而不會讓您訪問現有的高速緩存中的密鑰集合。但是,雖然這樣增強了安全性,卻使情況有點更不方便,尤其好象完全是 ssh-agent 在運行,而 keychain 並沒有運行。此處,情況常常是這樣,一個人可以選擇或者安全性更高,或更方便,但不能兩者兼得。

儘管如此,使用帶有 --clearkeychain 仍然比只用 ssh-agent 要好;請記住,當您使用 keychain --clear 時,您的 cron 作業和腳本仍然能建立無密碼連接;這是因爲專用密鑰是在 登錄時刷新,而不是在 退出時。由於從系統退出不會構成潛在的安全缺口,因而沒有理由要 keychain 來刷新 ssh-agent 的密鑰作爲響應。因此,對於不頻繁訪問又需要偶而執行安全拷貝任務的服務器而言,比如,備份服務器、防火牆及路由器, --clear 選項是一個理想的選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章