跳至內容

SSH 密鑰

出自 Arch Linux 中文维基

這篇文章的某些內容需要擴充。

原因:The intro and Background section ignore the server perspective. (在 Talk:SSH 密鑰 中討論)

對於使用公鑰加密質詢-應答式認證的 SSH 伺服器,SSH 密鑰可以作為證明身份的方法。基於密鑰的認證主要優點在於,與密碼認證相比,它不易遭受暴力破解攻擊,且在伺服器被攻破的情況下也不會洩露您的有效憑證(詳細信息請參考 RFC 4251 9.4.4)。

不僅如此,SSH 密鑰認證也會比傳統的密碼認證更加方便。當與被稱作 SSH agent 的程序共用時,SSH 密鑰可以讓您無需記住或輸入每個系統的密碼,就能夠連接到一個或多個伺服器。

基於密鑰的認證並非沒有缺點,可能也並非適用於一切環境,但在很多情況下可以提供一些有力的優勢。對 SSH 密鑰如何工作的概略理解會幫助您決定如何以及何時使用它們,以滿足您的需求。

本文假定您已經對於安全外殼協議有了基本理解,並安裝openssh 軟體包。

背景[編輯 | 編輯原始碼]

SSH 密鑰都是成對生成的,其一稱為公鑰,另一則稱為私鑰。私鑰只由您所知,必須安全保管。相對地,公鑰可以向您想連接的任何 SSH 伺服器自由地共享。

如果一個 SSH 伺服器在文件中存有您的公鑰,並收到了您的連接請求,就會使用您的公鑰構建一個質詢問題並發送給您。這一質詢問題是一條加密信息,必須得到正確應答,伺服器才能允許您訪問。這條編碼信息特別安全是在於,只有私鑰持有者才能理解它。公鑰可以用來加密信息,但不能用來解密同一條信息。只有您,私鑰的持有者,能夠正確理解這一質詢問題並產生合適的應答。

這一質詢-應答過程發生在後台,對用戶不可見。只要您持有私鑰(一般存放在 ~/.ssh/ 目錄下),您的 SSH 客戶端就應當能夠向伺服器回復正確的應答。

私鑰是受保護的秘密,因此建議以加密形式將其存儲在磁碟上。當需要被加密的私鑰時,為了解密它,需要先輸入密碼。雖然這在表面上可能像是您在向 SSH 伺服器提供登錄密碼,但該密碼只用於解密本地系統上的私鑰。該密碼並未通過網絡傳輸。

生成密鑰對[編輯 | 編輯原始碼]

通過運行 ssh-keygen 命令可以生成密鑰對,具體「一般被認為充足」且應當兼容於幾乎所有客戶端和伺服器的選項請參考 ssh-keygen(1)

$ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):
Created directory '/home/username/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:RLy4JBv7jMK5qYhRKwHB3af0rpMKYwE2PBhALCBV3G8 username@hostname
The key's randomart image is:
+--[ED25519 256]--+
|%oooo. ..        |
|== ..o.o.        |
|==  . +o..       |
|+ o o.ooE        |
|...  *.oS        |
| o..o ..         |
|o=.. +o          |
|+o*..+o          |
|+.o+. .          |
+----[SHA256]-----+

randomart 圖像作為一種簡便的密鑰指紋視覺辨識方式在 OpenSSH 5.1 中引入。

注意:可以使用 -a 開關來指定密碼加密的 KDF rounds 數量。

也可以用 -C 開關對公鑰添加可選的注釋欄,從而更容易在 ~/.ssh/known_hosts~/.ssh/authorized_keys 以及 ssh-add -L 輸出等處進行辨識。例如:

$ ssh-keygen -C "$(whoami)@$(uname -n)-$(date -I)"

會添加一條注釋,說明是哪個用戶何時在哪台機器上創建的密鑰。

選擇認證密鑰類別[編輯 | 編輯原始碼]

OpenSSH(對於認證密鑰)支持數種簽名算法,按照所採用的數學性質可分為兩類:

  1. Ed25519 以及 ECDSA,依賴於橢圓曲線離散對數問題(ECDLP);(例子
  2. RSA,依賴於對兩個大質數之積進行分解的實際困難度

橢圓曲線密碼學(ECC)算法是對於公鑰密碼體制的較新發展。其主要優勢之一是以較小密鑰提供同等安全性的能力,使得計算密集操作更少(也就是密鑰創建、加密及解密更快)且存儲及傳輸的要求更低。

由於安全問題,DSA 密鑰已被廢棄,且 SSH 實現正逐漸將其移除。OpenSSH 9.8 構建默認不帶 DSA 密鑰支持,Dropbear 2022.83 禁用了 DSA 密鑰支持,libssh 0.11.0 完全移除了 DSA 密鑰支持。因此密碼體制的選擇範圍就限定在了 RSA 或兩種 ECC 之一當中。

#RSA 密鑰會提供最大的可移植性,而 #Ed25519 會提供最佳的安全性,但需要新版本的客戶端與伺服器[1]。. #ECDSA 兼容性可能比 Ed25519 更好(雖然還是不如 RSA),但存在對於其安全性的懷疑(見下文)。

默認的 Ed25519 會提供最佳安全性和不錯的性能。ECDSA 比 Ed25519 更慢,但比 RSA 快,在安全性上存在些疑問(具體參見下文)。RSA 密鑰提供了對舊伺服器的最佳兼容性,但需要更大的密鑰才能提供足夠的安全性。

注意:這些密鑰只用於認證您的身份;選擇更強的密鑰並不會在通過 SSH 傳輸數據時加重 CPU 負擔。
提示:為防止 SSH 密鑰從設備上外洩,可以將密鑰儲存在 FIDO/U2F 實體認證器可信平台模塊中。
  • 在生成密鑰時,可以使用特殊的「安全密鑰」類型將 Ed25519 或 ECDSA 密鑰儲存在 FIDO/U2F 實體認證器上。具體信息請參考 #FIDO/U2F
  • 可信平台模塊支持 ECDSA 和 RSA,因此可以將 SSH 密鑰封裝在 TPM 內。具體信息請參考 可信平台模塊#SSH

Ed25519[編輯 | 編輯原始碼]

Ed25519 在2014年1月被引入 OpenSSH 6.5:「Ed25519 是一種能夠提供比 ECDSA 及 DSA 更佳安全性及良好性能的橢圓曲線簽名體系」。其主要長處在於速度、時間恆定運行時(從而能夠對抗側信道攻擊)以及無需晦暗不明的硬編碼常數。[2] 關於其工作方式,參見由一位 Mozilla 開發者撰寫的博客文章

它已經在眾多應用及庫中得到實現,並且在 OpenSSH 中是默認的密鑰交換算法(與密鑰簽名不同)。

Ed25519 密鑰對生成方法如下:

ssh-keygen(1) 默認使用 Ed25519,因此不需要使用 -t ed25519 選項進行指定。使用以下命令生成密鑰:

$ ssh-keygen

所有 Ed25519 密鑰都是 256 位,故無需設置密鑰尺寸。

注意較老的 SSH 客戶端與伺服器可能不支持這些密鑰。

ECDSA[編輯 | 編輯原始碼]

橢圓曲線數字簽名算法(ECDSA)是 OpenSSH 5.7(2011-01-24)到 OpenSSH 6.5(2014-01-30)間的首選認證(密鑰交換)算法。

對於它的擔憂有兩種:

  1. 政治上的擔憂:在 NSA(美國國家安全局)被曝在軟體、硬體組件及發布的標準中蓄意植入後門之後,由 NIST(美國國家標準技術研究所)產生的曲線的可信性受到了質疑;密碼領域的知名人士對於 NIST 曲線的設計方式表示 懷疑,並且之前已經有主動的污染 證實
  2. 技術上的擔憂:對於正確實現該標準的困難以及在實現不夠謹慎情況下降低安全性的遲緩與設計缺陷

libssh curve25519 介紹當中很好地總結了上述擔憂。儘管政治上的擔憂仍受到爭議,但有明確的共識認為 #Ed25519 技術上更優越,因此應當優先採用。

可以使用以下方法生成 ECDSA 密鑰對:

$ ssh-keygen -t ecdsa

ECDSA 密鑰支持三種橢圓曲線大小:256,384 和 521 位,默認使用 256 位。如果想要生成更安全的 ECDSA 密鑰對,可以使用 -b 選項進行指定:

$ ssh-keygen -t ecdsa -b 384

RSA[編輯 | 編輯原始碼]

RSA 提供所有算法當中最佳的兼容性,但提供充足安全性所需的密鑰尺寸較大。最低密鑰大小為 1024 位,默認為 3072(具體請參考 ssh-keygen(1)),最大為 16384。

使用以下命令生成 RSA 密鑰對:

$ ssh-keygen -t rsa

如果您想生成較強的 RSA 密鑰對(例如為了防範先進或未知攻擊以及較高級的攻擊者),只需為 -b 選項指定比默認更高的位值:

$ ssh-keygen -t rsa -b 4096

需要明白的是,使用更長的密鑰存在收益遞減。[3][4] GnuPG 常見問答記載:「如果你需要的安全性比 RSA-2048 所提供的更強,應該做的是改用橢圓曲線密碼學——而不是接著使用 RSA。」[5]

另一方面,最新版本的 NSA Fact Sheet Suite B Cryptography 建議對於 RSA 使用最少 3072 位的模,同時「為即將到來的抗量子算法遷移(做準備)」。[6]

FIDO/U2F[編輯 | 編輯原始碼]

這篇文章的某些內容需要擴充。

原因:OpenSSH 8.2 版本添加了 FIDO2 resident 密鑰支持,可以將 SSH 密鑰存放在實體令牌上。 (在 Talk:SSH 密鑰 中討論)

OpenSSH 8.2 版本添加了 FIDO/U2F 實體認證器支持,可以使用上文描述的兩種橢圓曲線簽名方案。這使得可以將連接的實體令牌作為多重驗證方案與私鑰搭配使用。

實體令牌需要用到 libfido2

注意:
  • 客戶端和伺服器都需要支持 ed25519-skecdsa-sk 密鑰類型。
  • OpenSSH 使用中間件庫來與實體令牌通信,其帶有支持 USB 令牌的內部中間件。如果要使用其它中間件,可以通過sshd_config(5) § SecurityKeyProvider 配置項或為 ssh-keygenssh-add 配置 SSH_SK_PROVIDER 環境變量來實現。

連接兼容的 FIDO 密鑰後,使用以下命令生成密鑰對:

$ ssh-keygen -t ed25519-sk

這一步通常需要輸入 PIN 碼並/或觸摸令牌進行確認。除非在生成時使用了 -O no-touch-required 命令行選項或伺服器指定了 sshd(8) § no-touch-required authorized_keys 選項,否則連接伺服器時通常需要觸摸令牌進行確認。

要生成不需要觸摸確認的密鑰,需在生成密鑰對時使用 no-touch-required 選項,例如:

$ ssh-keygen -O no-touch-required -t ed25519-sk
注意:並不是所有實體令牌都支持該選項。如果你使用的是 YubiKey,需要 5.2.3 固件版本才能使用 ed25519-sk 類型密鑰。[7]

另外,sshd 默認會拒絕 no-touch-required 密鑰。為使用通過該選項生成的密鑰,需在 authorized_keys 文件內對每個密鑰單獨進行啟用:

no-touch-required sk-ssh-ed25519@openssh.com AAAAInN... user@example.com

或是在 /etc/ssh/sshd_config 中對整個系統進行啟用:

PubkeyAuthOptions none
提示:GitHubGitLab 不支持 no-touch-required

基於 ECDSA 的密鑰對可通過 ecdsa-sk 密鑰類型生成,但同樣會有 #ECDSA 一節提到的問題:

$ ssh-keygen -t ecdsa-sk

選擇密鑰存儲位置以及密碼短語[編輯 | 編輯原始碼]

運行 ssh-keygen 時,它會詢問您希望的私鑰文件名稱及位置。默認情況下,密鑰保存到 ~/.ssh 目錄下,並根據所使用的加密類型命名。為使下文中的示例代碼正確工作,建議您接受默認的名稱和位置。

當系統向您詢問密碼短語時,如果您在乎私鑰的安全性,請選擇難以猜到的密碼。更長、更隨機的密碼一般會更強,當私鑰落入賊人之手時更不容易被破解掉。

在沒有密碼短語的情況下生成私鑰也是可能的。雖然也許很方便,但您需要明白隨之而來的風險。在沒有密碼短語的情況下,您的私鑰會以未加密形式存儲在硬碟上。任何能接觸到您私鑰文件的人之後都能夠在您使用基於密鑰認證連接的任何 SSH 伺服器面前冒用您的身份。更進一步,沒有密碼短語,您也必須信任 root 用戶,因為他可以繞過文件權限並能夠隨時訪問您未加密的私鑰文件。

注意:從前,私鑰密碼都是以一種不安全的方式編碼的:僅一遍 MD5 散列。OpenSSH 6.5 及之後版本支持一種新的、更安全的格式來編碼您的私鑰。從 OpenSSH 7.8 版本開始默認使用該格式。Ed25519 密鑰一直採用新的編碼格式。只需按下節所述更改密鑰的密碼短語即可升級到新格式。

不修改密鑰對的情況下修改密碼短語[編輯 | 編輯原始碼]

如果不希望使用原本選擇的 SSH 密鑰密碼短語或者必須更換,可以使用 ssh-keygen 命令來修改密碼短語,而無需改動實際密鑰。此法也可用於將密碼編碼格式改為新標準。

$ ssh-keygen -f ~/.ssh/id_rsa -p

管理多組密鑰對[編輯 | 編輯原始碼]

如果你有多個 SSH 身份,可以在配置文件中通過 HostIdentityFile 為不同的主機和遠程用戶使用不同的密鑰:

~/.ssh/config
Host SERVER1
   IdentitiesOnly yes
   IdentityFile ~/.ssh/id_rsa_IDENTITY1

Host SERVER2 SERVER3
   IdentitiesOnly yes
   IdentityFile ~/.ssh/id_ed25519_IDENTITY2

對於這些選項的完整描述見 ssh_config(5)

在硬體令牌上存儲 SSH 密鑰[編輯 | 編輯原始碼]

SSH 密鑰也可以存儲在智慧卡或 USB 令牌等安全令牌上。這樣做的好處是私鑰安全地存儲在令牌上,而不是存儲在磁碟中。當使用安全令牌時,敏感的私鑰也從來不會存在於 PC 的內存當中;密碼學操作在令牌自身上進行。密碼學令牌還有一點好處是,它不與單台電腦綁定;可以將其從一台電腦上輕鬆取下,四處攜帶之後在其他電腦上使用。

硬體令牌的例子可參考:

將公鑰複製到遠程伺服器上[編輯 | 編輯原始碼]

這篇文章的某些內容需要擴充。

原因:強制公鑰認證的情況下如何實現? (在 Talk:SSH 密鑰 中討論)

創建好密鑰對之後,您需要將公鑰上傳到遠程伺服器上,以便用於 SSH 密鑰認證登錄。公鑰和私鑰的文件名相同,只不過公鑰文件帶有擴展名 .pub 而私鑰文件名則沒有。千萬不要將私鑰上傳,私鑰應該保存在本地。

簡易方式[編輯 | 編輯原始碼]

如果您的公鑰文件為 ~/.ssh/id_rsa.pub,只需要輸入命令:

$ ssh-copy-id remote-server.org

如果您的遠程伺服器用戶名與本地的不同,您需要在遠程主機名前以 @ 隔開指定用戶名:

$ ssh-copy-id username@remote-server.org

如果您的公鑰文件名不是默認的 ~/.ssh/id_rsa.pub,會出現報錯 /usr/bin/ssh-copy-id: ERROR: No identities found。這種情況下,您需要顯式提供公鑰的位置:

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub username@remote-server.org

如果遠程伺服器監聽埠不是默認的 22,請在主機參數中指明:

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 221 username@remote-server.org

手動方式[編輯 | 編輯原始碼]

對於 OpenSSH,默認需要將公鑰添加到 ~/.ssh/authorized_keys。先從複製公鑰到遠程伺服器開始。

$ scp ~/.ssh/id_ecdsa.pub username@remote-server.org:

以上示例通過 scp 將公鑰(id_ecdsa.pub)複製到您在遠程伺服器上的主目錄。別忘了加上伺服器地址末尾的 :。並請注意,您的公鑰名稱可能與此例所示不同。

在遠程伺服器上,如果還沒有 ~/.ssh 目錄,您需要創建一個;然後將您的公鑰追加到 authorized_keys 文件內。

$ ssh username@remote-server.org
username@remote-server.org's password:
$ install -dm700 ~/.ssh
$ cat ~/id_ecdsa.pub >> ~/.ssh/authorized_keys
$ rm ~/id_ecdsa.pub
$ chmod 600 ~/.ssh/authorized_keys

上面最後兩個命令將公鑰文件從伺服器上刪除,並設置 authorized_keys 文件的權限,這樣只有作為文件擁有者的您能夠讀取及寫入。

SSH 代理[編輯 | 編輯原始碼]

如果您的私鑰使用密碼短語來加密了的話,每一次試圖連接到使用公鑰認證的 SSH 伺服器的時候,您都必須輸入密碼短語。每次喚起 sshscp 時都需要密碼短語來解密您的私鑰以便認證能夠繼續。

而 SSH 代理程序能夠將您的已解密的私鑰緩存起來,並代表您將其提供給 SSH 客戶端。這樣子,您就只需要將私鑰加入 SSH 代理緩存的時候輸入一次密碼短語就可以了。在經常使用 SSH 連接時,將會提供不少便利。

SSH 代理一般會設置成在登錄會話的時候自動啟動,並在整個會話中保持運行。有多種代理、前端及配置都能夠達成這一效果。本節概述了多種不同的解決方案,能夠適應以滿足您的特定需求。

ssh-agent[編輯 | 編輯原始碼]

ssh-agent 是 OpenSSH 自帶的默認代理。它可以直接使用,或者作為下文所述的幾種前端解決方案的後端。ssh-agent 運行時會自動 fork 到後台,然後列印出其所需的環境變量,例如:

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-vEGjCM2147/agent.2147; export SSH_AUTH_SOCK;
SSH_AGENT_PID=2148; export SSH_AGENT_PID;
echo Agent pid 2148;

要使用這些環境變量,請使用 eval 命令來運行它。如果使用的是 fish shell,需要轉而使用 ssh-agent -c

$ eval $(ssh-agent)
Agent pid 2157

ssh-agent 運行起來之後,您還需要將您的私鑰加入它的緩存。

$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/user/.ssh/id_ed25519:
Identity added: /home/user/.ssh/id_ed25519 (/home/user/.ssh/id_ed25519)

如果您的私鑰已加密,ssh-add 會提示您輸入密碼短語。一旦您的私鑰被成功添加到代理,您不需要再輸入密碼短語就能夠建立 SSH 連接了。

提示:要讓包括 git 在內的所有 ssh 客戶端在第一次使用時就把密鑰存儲在代理中,請將配置 AddKeysToAgent yes 添加到 ~/.ssh/config。其他可能的值有 confirmaskno(默認)。

為了自動啟動代理並確保同一時間只有一個 ssh-agent 進程在運行,添加以下內容到您的 ~/.bashrc

if ! pgrep -u "$USER" ssh-agent > /dev/null; then
    ssh-agent -t 1h > "$XDG_RUNTIME_DIR/ssh-agent.env"
fi
if [[ ! -f "$SSH_AUTH_SOCK" ]]; then
    source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null
fi

如果還沒有 ssh-agent 進程在運行的話,該腳本會自動啟動一個,並保存其輸出。如果已經有一個在運行了,就會讀取緩存的 ssh-agent 輸出並執行之,從而設置必要的環境變量。解密密鑰的存活時間設置為1小時。

本節後面會介紹幾種 ssh-agent 的前端及其它代理,也能夠避免這一問題。

用 systemd user 啟動 ssh-agent[編輯 | 編輯原始碼]

如果想要在登錄時運行 SSH agent 而不論 X 是否在運行的話,從 9.4p1-3 版本開始 openssh 提供了 ssh-agent.service,可以作為用戶單元啟用

然後將環境變量 SSH_AUTH_SOCK 設為 $XDG_RUNTIME_DIR/ssh-agent.socket

注意:如果您使用 GNOME,該環境變量默認會被覆蓋。見 GNOME/Keyring#禁用鑰匙環的守護進程組件

轉發 ssh-agent[編輯 | 編輯原始碼]

本文或本章節的語言、語法或風格需要改進。參考:幫助:風格

原因:This is not specific to ssh-agent, e.g. gpg-agent uses the same environment variable: GnuPG#Forwarding gpg-agent and ssh-agent to remote(在Talk:SSH 密鑰討論)

When forwarding a local ssh-agent to remote (e.g., through command-line argument ssh -A remote or through ForwardAgent yes in the configuration file), it is important for the remote machine not to overwrite the environment variable SSH_AUTH_SOCK. So if the remote machine uses a systemd unit shown previously to start the agent, SSH_AUTH_SOCK must not be set in the environment when a user is logged in through SSH. Otherwise, the forwarding may fail, and you may see errors (for example: The agent has no identities) when checking the existing keys with ssh-add -l on the remote machine.

For example, if using bash, the .bashrc could be something like:

~/.bashrc
...
if [[ -z "${SSH_CONNECTION}" ]]; then
    export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
fi
...

In this way, SSH_AUTH_SOCK is only set when the current session is not a SSH login. And when this is a SSH session, SSH_AUTH_SOCK on the remote machine is then set by the local machine to make the forwarding work.

作為包裝程序運行 ssh-agent[編輯 | 編輯原始碼]

加州大學伯克利分校實驗室的這份 ssh-agent 教程還介紹了一種隨每個 X 會話啟動 ssh-agent 的方法。基本用法是,如果您使用命令 startx 正常啟動 X,您可以改成像這樣在前面加上 ssh-agent

$ ssh-agent startx

您也可以在 .bash_aliases 或等同文件中設置別名,就不用再費心了:

alias startx='ssh-agent startx'

這樣做可以避免多個會話中存在多餘的 ssh-agent 進程。整個 X 會話中只會有一個 ssh-agent 在運行。

注意:ssh-askpass 需要 DISPLAYWAYLAND_DISPLAY 環境變量才能正常工作,所以你可能會需要在 ~/.xinitrc 中運行 ssh-agent 以配置 DISPLAY 選項,而不是使用 ssh-agent startx(如將 exec ssh-agent dbus-launch i3 添加到 ~/.xinitrc)。或者也可以將 eval $(ssh-agent) 添加到 ~/.xinitrc 以使用 ssh-agent 作為包裝程序運行。

下文有關協同使用 x11-ssh-askpass 與 ssh-add 的說明了解如何立即將密鑰添加到 agent。

OpenPGP card ssh-agent[編輯 | 編輯原始碼]

This ssh-agent specializes on OpenPGP card integration. It uses private keys that are stored in OpenPGP card authentication slots.

注意: When also using GnuPG while running this agent, it is required to use it with pcscd and configure shared access with pcscd.

Install openpgp-card-ssh-agent and enable and start the openpgp-card-ssh-agent.socket user unit.

Afterwards add the relevant environment variable for this agent:

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/openpgp-card/ssh-agent.sock"

User PIN handling[編輯 | 編輯原始碼]

The user PIN for the OpenPGP card is persisted via an org.freedesktop.secrets provider (such as GNOME Keyring, KeePassXC or KDE Wallet) by default. The PIN storage backend is configurable and extendable.

The user PIN needs to be persisted only once for each OpenPGP card. Prior to the first SSH connection with this agent, list the available SSH public keys and add their respective card identifiers:

$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJUz6VnFprMe33G88Pq8NLw3wnIKOsBg0CDrwFeUVrU6 FFFE:01234567
$ ssh-add -s FFFE:01234567
Enter passphrase for PKCS#11:
注意: The prompt mentions PKCS#11 as it is a hardcoded message in ssh-add(1). However, in this context the OpenPGP card user PIN must be entered.

GnuPG Agent[編輯 | 編輯原始碼]

gpg-agent 模擬了 OpenSSH 的代理協議,必要配置請參考 GnuPG#SSH 代理

Keychain[編輯 | 編輯原始碼]

Keychain 是一個用來方便管理 SSH 密鑰對的程序,它能盡最大努力去減少對用戶的打擾。實際上,它就是一個 shell 腳本,驅動 ssh-agent 或者 gpg-add 來工作。一個值得注意的特性是,Keychain 在多個會話中重複使用同一個 ssh-agent 進程。這意味著您只需要在機器啟動時輸入一次密碼短語即可。

安裝[編輯 | 編輯原始碼]

安裝 keychain 軟體包。

配置[編輯 | 編輯原始碼]

警告:直至 2015-09-26 為止,-Q, --quick 選項存在預期之外的副作用,導致 keychain 在重新登錄時切換到新產生的 ssh-agent (至少在使用 GNOME 的系統上如此),使您不得不重新添加所有先前註冊的密鑰。

將類似以下的行加入到您 shell 的配置文件中,例如若您使用Bash

~/.bashrc
eval $(keychain --eval --quiet id_ed25519 id_rsa ~/.keys/my_custom_key)
注意:之所以使用 ~/.bashrc 而非上游建議的 ~/.bash_profile,是因為在 Arch 上登錄與非登錄 shell 都會使用它,因此同樣適用於文字與圖形環境。關於二者之間差異的更多信息見Bash#調用

上例當中,

  • --eval 開關可以輸出供 eval 命令執行的行;這樣可以設置必要的環境變量,讓 SSH 客戶端能夠找到您的 agent。
  • --quiet 會把輸出限制為只包含警告、錯誤及用戶提示。

如例子所示,可在命令行中指定多個密鑰。Keychain 默認會在 ~/.ssh/ 目錄中尋找密鑰對,但對於位於非標準位置的密鑰可以使用絕對路徑。也可使用 --confhost 選項告知 keychain 在 ~/.ssh/config 中尋找為特定主機定義的 IdentityFile 設置,並使用這些路徑來定位密鑰。

關於如何為其他 shell 設置 keychain 的詳情請參考 keychain --helpkeychain(1)

要測試 Keychain,只需打開一個終端模擬器,或註銷當前會話再重新登錄。它應該會使用 $SSH_ASKPASS 中設置的程序或在終端上提示您輸入指定私鑰的密碼短語(如果有)。

因為 Keychain 重新使用之前的登錄中的 ssh-agent 進程,所以您再次登錄或打開新終端時應該就無需輸入密碼短語了。每當您重啟機器時,您才會被要求再次輸入密碼短語。

提示[編輯 | 編輯原始碼]

  • keychain 需要公鑰文件存放在相應私鑰的同一目錄下,並帶有 .pub 擴展名。如私鑰為符號連結,公鑰需要與符號連結一起存放或與符號連結目標在同一目錄下(該功能需要系統上有 readlink 命令)。
  • 要禁用圖形提示,以始終在終端中輸入密碼短語,請使用 --nogui 選項。舉例來說,這樣可以從密碼管理器中複製粘貼長密碼。
  • 如果您想要等到需要時再提示解鎖密鑰,而不是一開始就提示,請使用 --noask 選項。
注意:Keychain 能夠以同樣的方式管理 GPG 密鑰。它默認只會嘗試啟動 ssh-agent,但使用 --agents 選項可以改變這一行為,例如 --agents ssh,gpg。詳細信息請參考 keychain(1)
注意:
  • Keychain 能夠以同樣的方式管理 GPG 密鑰。它默認只會嘗試啟動 ssh-agent,但使用 --agents 選項可以改變這一行為,例如 --agents ssh,gpg。詳細信息請參考 keychain(1)
  • 根據 keychain issue 148,在使用 Wayland 時可能需要添加 --inherit any-once 參數。

x11-ssh-askpass[編輯 | 編輯原始碼]

The x11-ssh-askpass package provides a graphical dialog for entering your passhrase when running an X session. x11-ssh-askpass depends only on the libx11 and libxt libraries, and the appearance of x11-ssh-askpass is customizable. While it can be invoked by the ssh-add program, which will then load your decrypted keys into ssh-agent, the following instructions will, instead, configure x11-ssh-askpass to be invoked by the aforementioned Keychain script.

Install the keychain and x11-ssh-askpass packages.

Edit your ~/.xinitrc file to include the following lines, replacing the name and location of your private key if necessary. Be sure to place these commands before the line which invokes your window manager.

~/.xinitrc
keychain ~/.ssh/id_ecdsa
[ -f ~/.keychain/$HOSTNAME-sh ] && . ~/.keychain/$HOSTNAME-sh 2>/dev/null
[ -f ~/.keychain/$HOSTNAME-sh-gpg ] && . ~/.keychain/$HOSTNAME-sh-gpg 2>/dev/null
...
exec openbox-session

In the above example, the first line invokes keychain and passes the name and location of your private key. If this is not the first time keychain was invoked, the following two lines load the contents of $HOSTNAME-sh and $HOSTNAME-sh-gpg, if they exist. These files store the environment variables of the previous instance of keychain.

Calling x11-ssh-askpass with ssh-add[編輯 | 編輯原始碼]

The ssh-add manual page specifies that, in addition to needing the DISPLAY or WAYLAND_DISPLAY variable defined, you also need SSH_ASKPASS set to the name of your askpass program (in this case x11-ssh-askpass). It bears keeping in mind that the default Arch Linux installation places the x11-ssh-askpass binary in /usr/lib/ssh/, which will not be in most people's PATH. This is a little annoying, not only when declaring the SSH_ASKPASS variable, but also when theming. You have to specify the full path everywhere. Both inconveniences can be solved simultaneously by symlinking:

$ ln -sv /usr/lib/ssh/x11-ssh-askpass ~/bin/ssh-askpass

This is assuming that ~/bin is in your PATH. So now in your .xinitrc, before calling your window manager, one just needs to export the SSH_ASKPASS environment variable:

$ export SSH_ASKPASS=ssh-askpass

and your X resources will contain something like:

ssh-askpass*background: #000000

Doing it this way works well with the above method on using ssh-agent as a wrapper program. You start X with ssh-agent startx and then add ssh-add to your window manager's list of start-up programs.

Theming[編輯 | 編輯原始碼]

The appearance of the x11-ssh-askpass dialog can be customized by setting its associated X resources. Some examples are the .ad files at https://github.com/sigmavirus24/x11-ssh-askpass. See x11-ssh-askpass(1) for full details.

Alternative passphrase dialogs[編輯 | 編輯原始碼]

There are other passphrase dialog programs which can be used instead of x11-ssh-askpass. The following list provides some alternative solutions.

pam_ssh[編輯 | 編輯原始碼]

pam_ssh 項目為 SSH 私鑰提供了一個可插拔認證模塊(PAM),該模塊可以為 SSH 連接提供類似單點登錄驗證的特性。在認證完成後,pam_ssh 模塊會讓 ssh-agent 在整個會話期間緩存您已解密的私鑰。

要在 tty 模式下使用單點登錄特性,需要安裝非官方的 pam_sshAUR 包。

注意:pam_ssh 2.0 要求所有用於認證的私鑰文件必須保存在 ~/.ssh/login-keys.d/ 下。

可以為您的私鑰文件創建一個軟連結,並放到 ~/.ssh/login-keys.d/。將以下案例中的 id_rsa 替換為你的私鑰的名稱:

$ mkdir ~/.ssh/login-keys.d/
$ cd ~/.ssh/login-keys.d/
$ ln -s ../id_rsa

編輯 /etc/pam.d/login,將下面例子中高亮加粗的那幾行加進去。請注意配置內容的順序會影響到登錄行為,應當按照例子中的來。

警告:PAM 配置錯誤會導致系統中的所有用戶被鎖定。因此,在進行任何更改前,你需要大致了解 PAM 配置的工作方式,並確保具有備用的 PAM 配置文件訪問手段(如 Arch Live CD),以確保被鎖定後仍能撤回更改。可以參閱 IBM developerWorks 的 這篇文章 詳細了解一下 PAM 的配置細節。
/etc/pam.d/login
#%PAM-1.0

auth       required     pam_securetty.so
auth       requisite    pam_nologin.so
auth       include      system-local-login
auth       optional     pam_ssh.so        try_first_pass
account    include      system-local-login
session    include      system-local-login
session    optional     pam_ssh.so

在上面的例子中,登錄認證在起始階段正常進行,並要求用戶輸入登錄密碼。附加到認證棧末尾的額外 auth 認證規則會讓 pam_ssh 嘗試解密 ~/.ssh/login-keys.d 目錄下的所有私鑰。try_first_pass 選項會被傳遞給 pam_ssh 模塊,要求它嘗試使用用戶之前輸入的密碼解密 SSH 私鑰。如果用戶密碼與私鑰密碼一致,用戶就無需再次輸入相同的密碼。如果兩者不同,pam_ssh 模塊會在用戶輸入登錄密碼後要求輸入私鑰密碼。optional 選項可以保證在沒有私鑰時用戶也能正常登錄系統。這樣,沒有 SSH 私鑰的用戶對 pam_ssh 是無感的。

如果你使用 X11 顯示管理器(如 SLiMXDM)等其它方式進行登錄,必須仿照如上配置編輯 PAM 配置文件。提供 PAM 支持的軟體包通常會將默認配置文件放置在 /etc/pam.d/ 目錄下。

Further details on how to use pam_ssh and a list of its options can be found in the pam_ssh(8) man page.

使用不同密碼解鎖 SSH 密鑰[編輯 | 編輯原始碼]

If you want to unlock the SSH keys or not depending on whether you use your key's passphrase or the (different!) login password, you can modify /etc/pam.d/system-auth to

/etc/pam.d/system-auth
#%PAM-1.0

auth      [success=1 new_authtok_reqd=1 ignore=ignore default=ignore]  pam_unix.so     try_first_pass nullok
auth      required  pam_ssh.so      use_first_pass
auth      optional  pam_permit.so
auth      required  pam_env.so

account   required  pam_unix.so
account   optional  pam_permit.so
account   required  pam_time.so

password  required  pam_unix.so     try_first_pass nullok sha512 shadow
password  optional  pam_permit.so

session   required  pam_limits.so
session   required  pam_unix.so
session   optional  pam_permit.so
session   optional  pam_ssh.so

For an explanation, see [8].

pam_ssh 已知問題[編輯 | 編輯原始碼]

pam_ssh 項目並不活躍,其提供的文檔也比較少。你需要注意該軟體未提及的一些使用限制,比如:

  • 2.0 版本前的 pam_ssh 不支持 ECDSA(橢圓曲線)SSH 密鑰,需要使用舊版本的必須使用 RSA 密鑰。
  • pam_ssh 調用的 ssh-agent 進程僅限於當前用戶登錄,無法在多次登錄間持久化。如果你在登錄期間保留了一個 GNU Screen 會話,會發現重新連接 screen 會話後無法與 ssh-agent 進行通信。這是因為 GNU Screen 環境和其子進程仍在引用調用 screen 時存在的 ssh-agent,但其已隨上次登出被關閉。上文提到的 Keychain 前端可以在多次登錄間保留 ssh-agent 進程,從而避免該問題。

pam_exec-ssh[編輯 | 編輯原始碼]

As an alternative to pam_ssh you can use pam_exec-ssh-gitAUR. It is a shell script that uses pam_exec. Help for configuration can be found upstream.

GNOME Keyring[編輯 | 編輯原始碼]

GNOME Keyring 可用作 ssh-agent 的封裝,並提供圖形界面和/或密鑰自動解鎖功能。詳情請參考 GNOME Keyring#SSH密鑰

使用 Kwallet 存儲 SSH 密鑰[編輯 | 編輯原始碼]

For instructions on how to use kwallet to store your SSH keys, see KDE Wallet#Using the KDE Wallet to store ssh key passphrases.

KeePass2 搭配 KeeAgent 插件[編輯 | 編輯原始碼]

KeeAgent is a plugin for KeePass that allows SSH keys stored in a KeePass database to be used for SSH authentication by other programs.

  • Supports both PuTTY and OpenSSH private key formats.
  • Works with native SSH agent on Linux/Mac and with PuTTY on Windows.

See KeePass#Plugin installation in KeePass or install the keepass-plugin-keeagent package.

This agent can be used directly, by matching KeeAgent socket: KeePass -> Tools -> Options -> KeeAgent -> Agent mode socket file -> %XDG_RUNTIME_DIR%/keeagent.socket- and environment variable: export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR"'/keeagent.socket'.

KeePassXC[編輯 | 編輯原始碼]

The KeePassXC fork of KeePass can act as a client for an existing SSH agent. SSH keys stored in its database can be automatically (or manually) added to the agent. It is also compatible with KeeAgent's database format.

疑難排解[編輯 | 編輯原始碼]

密鑰被伺服器忽略[編輯 | 編輯原始碼]

如果您的 SSH 伺服器忽略了您的 SSH 密鑰對,您需要檢查一下相關文件的權限是否正確。

本地機器上:
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/key
伺服器上:
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

如果這樣還不能解決您的問題,您可以試試將 /etc/ssh/sshd_config 中的 StrictModes 設為 no。如果使用 StrictModes off 就能夠順利認證的話,說明相關文件的權限還沒有改對。

  • 確保 ~/.ssh/authorized_keys 中的密鑰正確並只有一行。
  • 確保遠程設備支持使用的密鑰類型:有些伺服器不支持 ECDSA 密鑰,可以試試 RSA 密鑰,具體請參考 #生成密鑰對
  • 你可能會想在連接時啟用調試模式並監控輸出:
# /usr/bin/sshd -d
  • 如果你的密鑰使用其它名字(如 id_rsa_server),需要使用 -i 選項進行連接:
$ ssh -i id_rsa_server user@server

代理拒絕操作[編輯 | 編輯原始碼]

If your private key requires a password (or, for instance, you have a hardware key with a PIN) but ssh-agent is not provided with one, ssh will fail:

sign_and_send_pubkey: signing failed for ECDSA-SK user@host from agent: agent refused operation

One potential cause for this is ssh-agent being unable to prompt for a password. Ensure that ssh-agent has access to either a display server (via the DISPLAY environment variable) or a TTY.

Another cause, if using a hardware authenticator, could be the key malfunctioning or being unplugged.

There is currently an open bug that triggers with the "agent refused operation" error when using authenticator keys like ED25519-sk and ECDSA-SK that were created with the option -O verify-required. To avoid this issue, use the -o IdentityAgent=none -o IdentitiesOnly=yes option for the ssh command or add it to your ssh_config file for the relevant hosts:

Host myserver.tld
    IdentityAgent none
    IdentitiesOnly yes

參考[編輯 | 編輯原始碼]