跳轉到內容

OpenSSH/Cookbook/基於主機的身份驗證

100% developed
來自華夏公益教科書

 

基於主機的身份驗證允許主機代表該特定主機的所有或部分使用者進行身份驗證。這些帳戶可以是系統上的所有帳戶,也可以是 Match 指令指定的子集。這種型別的身份驗證對於管理計算叢集和其他相當同質的機器池很有用。

總共,伺服器上必須準備三個檔案才能進行基於主機的身份驗證。在客戶端上,只需要修改兩個檔案,但主機本身必須分配 SSH 主機金鑰。以下內容設定了從一個系統到另一個系統的一個方向的基於主機的身份驗證。為了雙向身份驗證,請重複執行此過程兩次,但顛倒系統的角色。

基於主機的身份驗證的客戶端配置

[編輯 | 編輯原始碼]

在客戶端或源主機上,必須配置兩個檔案,此外還需要至少存在一個主機金鑰

/etc/ssh/ssh_known_hosts - 已知主機的公鑰的全域性檔案
/etc/ssh/ssh_config - 允許客戶端請求基於主機的身份驗證

然後,如果客戶端的主機金鑰不存在,則必須建立它們

/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key

這三個步驟需要在每個將連線到指定主機的客戶端系統上完成。設定完成後,登入到一個系統上的帳戶將能夠連線到另一個系統,而無需進一步的互動式身份驗證。

請注意,在某些環境中,基於主機的身份驗證可能不被認為足以防止未經授權的訪問,因為它主要基於主機之間進行。

1. 使用伺服器的公鑰填充客戶端

[編輯 | 編輯原始碼]

遠端伺服器的公鑰必須儲存在客戶端系統上的全域性客戶端配置檔案 /etc/ssh/ssh_known_hosts 中。一種從伺服器獲取公鑰的方法是使用 ssh-keyscan(1) 獲取並儲存它們。

$ ssh-keyscan server.example.com | tee -a /etc/ssh/ssh_known_hosts

在嘗試任何操作之前,請務必備份 /etc/ssh/ssh_known_hosts(如果存在)。另一種方法是將伺服器的公鑰新增到相關帳戶中的 ~/.ssh/known_hosts 檔案。但這更麻煩。

無論以何種方式獲取和驗證,那裡列出的公鑰顯然必須與伺服器上的私有主機金鑰相對應。可以使用三種類型中的任何一種或全部三種類型:RSA、ECDSA 或 Ed25519。DSA 不應再使用。有關公鑰驗證,請參閱關於 如何透過指紋驗證主機金鑰 的部分,以瞭解一些相關方法。

2. 系統範圍的客戶端配置

[編輯 | 編輯原始碼]

必須進行兩個更改。首先,客戶端的配置必須在連線到指定系統時請求基於主機的身份驗證。其次,客戶端配置檔案必須設定為啟用 ssh-keysign(8)。它是一個輔助應用程式,用於訪問本地主機金鑰並生成基於主機的身份驗證所需的數字簽名。這兩個更改都可以在 /etc/ssh/ssh_config 中全域性完成。

以下是在客戶端上嘗試對所有機器進行基於主機的身份驗證的 /etc/ssh/ssh_config 的摘錄。 ssh_config(5) 中的 Host 指令可用於進一步限制對特定伺服器或伺服器組的訪問。

Host *.pool.example.org
	HostbasedAuthentication yes
	EnableSSHKeysign yes

在某些發行版中,例如 Red Hat Enterprise Linux 8,EnableSSHKeysign 指令可能需要放在通用部分中才能生效。在這種情況下,請執行以下操作

Host *.pool.example.org
	HostbasedAuthentication yes

Host *
	EnableSSHKeysign yes

可以根據需要新增其他配置指令。例如,以下是應用於同一池的兩個附加設定

Host *.pool.example.org
	HostbasedAuthentication yes
	EnableSSHKeysign yes
	ServerAliveCountMax 3
	ServerAliveInterval 60

如果客戶端主機的 home 目錄是與其他機器共享的目錄,例如使用 NFS 或 AFS,那麼檢視 NoHostAuthenticationForLocalhost 指令可能也很有用。

作為一些瑣事,程式 ssh-keysign(8) 本身必須是 SUID root。但 SUID 可能是安裝時設定的,不需要在那裡進行任何更改。

3. 設定客戶端系統自己的主機金鑰

[編輯 | 編輯原始碼]

程式 ssh-keysign(8) 需要讀取客戶端系統在 /etc/ssh/ 中的私有主機金鑰。安裝 OpenSSH 伺服器將建立這些金鑰,但如果客戶端系統上尚未安裝 OpenSSH 伺服器,則不需要安裝。僅擁有金鑰就足夠了。如果客戶端系統上的私有主機金鑰不存在,則需要使用 ssh-keygen(1) 手動新增它們,然後基於主機的身份驗證才能正常工作。

$ ssh-keygen -A

使用 -A 選項時,預設路徑為 /etc/ssh/

請注意,儘管客戶端系統不需要實際執行 SSH 伺服器才能使用基於主機的身份驗證來連線到另一個系統,但完全可以安裝 SSH 伺服器,然後停用或解除安裝客戶端伺服器上的 SSH 伺服器,以此來獲取主機金鑰。

基於主機的身份驗證的伺服器端配置

[編輯 | 編輯原始碼]

必須修改伺服器或目標主機上的三個檔案才能啟用和允許基於主機的身份驗證

/etc/shosts.equiv 與舊的 rhosts.equiv 語法相同
/etc/ssh/ssh_known_hosts 儲存來自客戶端的主機公鑰
/etc/ssh/sshd_config 開啟基於主機的身份驗證

shosts.equiv 的確切位置可能因作業系統和發行版而異。

1. 在伺服器上註冊允許的客戶端系統

[編輯 | 編輯原始碼]

shosts.equiv 檔案必須包含允許嘗試基於主機的身份驗證的客戶端系統的列表。該檔案可以包含主機名、IP 地址或網路組。最好保持此檔案簡單,並僅面向主機列表,無論是透過名稱還是 IP 號碼。它只提供第一個切入點。對於微調,請改用 sshd_config(5) 來為特定使用者和組設定或撤銷訪問許可權。

重要的是要注意,如果您使用的是 shosts.equiv 檔案,則客戶端和伺服器系統上的使用者名稱必須匹配。例如,要連線到 bob@server1.example.org,客戶端上的使用者名稱也必須是 bob。如果您需要使用者 'alice' 連線到 bob@server1.example.org,您需要在 'bob' 的 .shosts 檔案中指定這一點,而不是在全域性 shosts.equiv 檔案中。

client1.example.org
192.0.2.102
client8.example.org -bull
@statcluster

此檔案位於 OpenBSD 中的 /etc/ 目錄中,本手冊儘可能地使用該目錄作為參考系統。在其他系統上,該檔案可能位於 /etc/ssh/ 目錄中。無論哪種方式,shosts.equiv 檔案都會標識允許嘗試身份驗證的地址。請檢視您正在使用的實際系統的 sshd(1) 手冊頁,以確保您知道正確的位置。

尋找 hosts.equiv(5) 手冊頁,以瞭解更多關於 .shosts.equiv(以及 .shosts.)的資訊,但請注意,它的使用早已過時,大多數系統甚至沒有該手冊頁。

舊時代的遺留物

[edit | edit source]

非常舊的系統上可能存在兩個遺留檔案。 如果從shosts.equiv中引用,則可以對其進行可選修改。netgroup檔案中的每一行都包含一個網路組名稱,後跟網路組成員的列表,具體來說是主機、使用者和域。

/etc/netgroup - 預設網路組列表
/etc/netgroup.db - 網路組資料庫,從網路組構建

但是,這些大多數是舊的rhosts的遺留問題,應該避免。

另一個遺留問題是在每個帳戶的主目錄中使用.shosts。 這將是.shosts.equiv的本地等效項。 透過這種方式,單個使用者可以擁有包含受信任的遠端機器列表或使用者-機器對的本地.shosts,這些機器或使用者-機器對被允許嘗試基於主機的身份驗證。

.shosts 不得被任何組或任何其他使用者寫入。 許可權設定為 0644 應該就可以了。.shosts的使用和格式與.rhosts完全相同,但允許基於主機的身份驗證,而不允許透過不安全的遺留工具rloginrsh登入。 該列表每主機一行。 第一列是強制性的,包含允許嘗試基於主機的身份驗證的主機名稱或地址。

但是,全域性.shosts.equiv比在每個主目錄中都有.shosts更可取。

2. 在伺服器上填充客戶端的公鑰

[edit | edit source]

伺服器的shosts.equiv中列出的客戶端系統還必須在其伺服器上的/etc/ssh/ssh_known_hosts中包含其公鑰,才能被確認。 每行需要三個資料欄位。 第一個是主機名或 IP 地址或它們的逗號分隔列表,對應於shosts.equiv中的那些。 接下來是金鑰型別,對於 RSA 金鑰為 ssh-rsa,對於 Ed25519 金鑰為 ssh-ed25519,對於 ECDSA 金鑰為 ecdsa-sha2-nistp256。 第三個欄位是公鑰本身。 最後,可選地,可以是對金鑰的註釋。

desktop,192.0.2.102 ssh-rsa AAAAB3NzaC1yc2EAAAABIw ... qqU24CcgzmM=

就像客戶端的第一步一樣,從客戶端收集公鑰資訊並將其傳送到伺服器有很多方法。 它可以使用 sftp(1) 複製,從~/.ssh/known_hosts 複製,或使用 ssh-keyscan(1) 獲取。 儘管後兩種方法只有在客戶端系統也執行 SSH 伺服器的情況下才有效。

$ ssh-keyscan -t rsa client.example.org | tee -a /etc/ssh/ssh_known_hosts

3. 全域性伺服器配置

[edit | edit source]

必須在伺服器上更改的第三個檔案是 sshd_config(5)。 它必須被告知透過設定HostbasedAuthentication指令允許基於主機的身份驗證,無論是針對所有使用者,還是僅針對某些使用者,還是僅針對某些組。

HostbasedAuthentication yes

基於主機的身份驗證可以限制為特定使用者或組。 以下是從 sshd_config(5) 中允許任何屬於 'cluster2' 組的使用者讓主機代表其進行身份驗證的示例摘錄

Match Group cluster2
        HostbasedAuthentication yes

可以使用HostbasedAcceptedAlgorithms(以前稱為HostbasedAcceptedKeyTypes)和逗號分隔的可接受金鑰演算法列表來允許某些主機金鑰型別。 必須列出所有要允許的金鑰演算法,因為未列出的演算法將不被允許。 在白名單中可以使用模式。 以下示例允許 Ed25519 和 ECDSA 金鑰,但不允許其他金鑰,例如 RSA 和 DSA。

HostbasedAuthentication yes
HostbasedAcceptedAlgorithms ssh-ed25519*,ecdsa-sha2*

主機名和其他 DNS 事項

[edit | edit source]

如果可能,為客戶端建立完整的 DNS 條目,包括允許反向查詢。 如果客戶端機器未在 DNS 中列出,則伺服器可能無法識別它。 在這種情況下,您可能需要告訴 sshd(8) 不要對連線的主機執行 DNS 反向查詢。 這在非正式的 LAN 上可能是一個問題,其中主機有地址但沒有註冊主機名。 以下是從/etc/ssh/sshd_config 中的示例,使用HostbasedUsesNameFromPacketOnly指令來解決客戶端缺少 DNS 記錄的問題。

HostbasedAuthentication yes
HostbasedUsesNameFromPacketOnly yes

除非正常方法失敗,否則不要新增此指令。 否則它會干擾並阻止身份驗證。

有時,嘗試連線的主機被識別為目標主機上的其他東西,而不是預期的東西。 這也會阻止身份驗證。 因此,請確保配置檔案與主機實際呼叫的內容相匹配。

除錯

[edit | edit source]

配置應該非常直觀,只需在伺服器上的三個檔案和客戶端上的兩個檔案上進行少量更改即可管理。 如果遇到困難,請準備以除錯級別 1 (-d) 到 3 (-ddd) 執行 sshd(8) 獨立程式,並在除錯級別 3 (-vvv) 執行 ssh(1) 幾次,看看您錯過了什麼。 錯誤必須按正確的順序清除,因此請一次一步進行。

如果伺服器生成訊息“debug3: auth_rhosts2_raw: no hosts access file exists”,則shosts.equiv檔案可能位於錯誤的位置或丟失,並且該帳戶中沒有備用的~/.shosts檔案。

如果伺服器無法找到客戶端的金鑰,儘管它在known_hosts中,並且如果客戶端的主機名不在常規 DNS 中,則可能需要新增指令HostbasedUsesNameFromPacketOnly。 這將使用客戶端本身提供的名稱,而不是執行 DNS 查詢。

以下是從主機 192.0.2.102(也稱為 desktop1)上的使用者 'fred' 使用 Ed25519 金鑰成功進行基於主機的身份驗證的示例摘錄。 伺服器首先嚐試查詢 ECDSA 金鑰,但沒有找到它。

# /usr/sbin/sshd -ddd
debug2: load_server_config: filename /etc/ssh/sshd_config
...
debug3: /etc/ssh/sshd_config:111 setting HostbasedAuthentication yes
debug3: /etc/ssh/sshd_config:112 setting HostbasedUsesNameFromPacketOnly yes
...
debug1: sshd version OpenSSH_6.8, LibreSSL 2.1
...
debug1: userauth-request for user fred service ssh-connection method hostbased [preauth]
debug1: attempt 1 failures 0 [preauth]
debug2: input_userauth_request: try method hostbased [preauth]
debug1: userauth_hostbased: cuser fred chost desktop1. pkalg ecdsa-sha2-nistp256 slen 100 [preauth]
...
debug3: mm_answer_keyallowed: key_from_blob: 0x76eede00
debug2: hostbased_key_allowed: chost desktop1. resolvedname 192.0.2.102 ipaddr 192.0.2.102
debug2: stripping trailing dot from chost desktop1.
debug2: auth_rhosts2: clientuser fred hostname desktop1 ipaddr desktop1
debug1: temporarily_use_uid: 1000/1000 (e=0/0)
debug1: restore_uid: 0/0
debug1: fd 4 clearing O_NONBLOCK
debug2: hostbased_key_allowed: access allowed by auth_rhosts2
debug3: hostkeys_foreach: reading file "/etc/ssh/ssh_known_hosts"
debug3: record_hostkey: found key type ED25519 in file /etc/ssh/ssh_known_hosts:1
debug3: load_hostkeys: loaded 1 keys from desktop1
debug1: temporarily_use_uid: 1000/1000 (e=0/0)
debug3: hostkeys_foreach: reading file "/home/fred/.ssh/known_hosts"
debug1: restore_uid: 0/0
debug1: check_key_in_hostfiles: key for host desktop1 not found
Failed hostbased for fred from 192.0.2.102 port 10827 ssh2: ECDSA SHA256:CEXGTmrVgeY1qEiwFe2Yy3XqrWdjm98jKmX0LK5mlQg, client user "fred", client host "desktop1"
debug3: mm_answer_keyallowed: key 0x76eede00 is not allowed
debug3: mm_request_send entering: type 23
debug2: userauth_hostbased: authenticated 0 [preauth]
debug3: userauth_finish: failure partial=0 next methods="publickey,password,keyboard-interactive,hostbased" [preauth]
debug1: userauth-request for user fred service ssh-connection method hostbased [preauth]
debug1: attempt 2 failures 1 [preauth]
debug2: input_userauth_request: try method hostbased [preauth]
debug1: userauth_hostbased: cuser fred chost desktop1. pkalg ssh-ed25519 slen 83 [preauth]
debug3: mm_key_allowed entering [preauth]
debug3: mm_request_send entering: type 22 [preauth]
debug3: mm_key_allowed: waiting for MONITOR_ANS_KEYALLOWED [preauth]
debug3: mm_request_receive_expect entering: type 23 [preauth]
debug3: mm_request_receive entering [preauth]
debug3: mm_request_receive entering
debug3: monitor_read: checking request 22
debug3: mm_answer_keyallowed entering
debug3: mm_answer_keyallowed: key_from_blob: 0x7e499180
debug2: hostbased_key_allowed: chost desktop1. resolvedname 192.0.2.102 ipaddr 192.0.2.102
debug2: stripping trailing dot from chost desktop1.
debug2: auth_rhosts2: clientuser fred hostname desktop1 ipaddr desktop1
debug1: temporarily_use_uid: 1000/1000 (e=0/0)
debug1: restore_uid: 0/0
debug1: fd 4 clearing O_NONBLOCK
debug2: hostbased_key_allowed: access allowed by auth_rhosts2
debug3: hostkeys_foreach: reading file "/etc/ssh/ssh_known_hosts"
debug3: record_hostkey: found key type ED25519 in file /etc/ssh/ssh_known_hosts:1
debug3: load_hostkeys: loaded 1 keys from desktop1
debug1: temporarily_use_uid: 1000/1000 (e=0/0)
debug3: hostkeys_foreach: reading file "/home/fred/.ssh/known_hosts"
debug1: restore_uid: 0/0
debug1: check_key_in_hostfiles: key for desktop1 found at /etc/ssh/ssh_known_hosts:1
Accepted ED25519 public key SHA256:BDBRg/JZ36+PKYSQTJDsWNW9rAfmUQCgWcY7desk/+Q from fred@desktop1
debug3: mm_answer_keyallowed: key 0x7e499180 is allowed
debug3: mm_request_send entering: type 23
debug3: mm_key_verify entering [preauth]
debug3: mm_request_send entering: type 24 [preauth]
debug3: mm_key_verify: waiting for MONITOR_ANS_KEYVERIFY [preauth]
debug3: mm_request_receive_expect entering: type 25 [preauth]
debug3: mm_request_receive entering [preauth]
debug3: mm_request_receive entering
debug3: monitor_read: checking request 24
debug3: mm_answer_keyverify: key 0x7e49a700 signature verified
debug3: mm_request_send entering: type 25
Accepted hostbased for fred from 192.0.2.102 port 10827 ssh2: ED25519 SHA256:BDBRg/JZ36+PKYSQTJDsWNW9rAfmUQCgWcY7desk/+Q, client user "fred", client host "desktop1"
debug1: monitor_child_preauth: fred has been authenticated by privileged process
...

注意任何警告或錯誤訊息,並仔細閱讀它們。 如果輸出太多,請記住伺服器的-e選項,並使用它將除錯輸出儲存到單獨的檔案中,然後在以後讀取該檔案。

由於此方法依賴於客戶端和伺服器,因此以更高的詳細程度執行客戶端有時也有幫助。

$ ssh -v fred@server.example.org
$ ssh -vv fred@server.example.org
$ ssh -vvv fred@server.example.org

如果來自客戶端的輸出太多而無法處理,請記住-E選項,並將除錯日誌重定向到檔案,然後在空閒時讀取該檔案。

 

華夏公益教科書