跳轉到內容

OpenSSH/Cookbook/基於證書的身份驗證

100% developed
來自華夏公益教科書,為開放世界提供開放書籍

 

證書是經過另一個金鑰簽名的金鑰[1]。 用於此類簽名的金鑰稱為證書頒發機構。 它是在預先建立並預留的,專門用於簽名。 其他方使用簽名金鑰的公鑰部分來驗證用於伺服器身份驗證的已簽名金鑰的真實性,在主機證書的情況下[2],或用於登入,在使用者證書的情況下[3]

為了實現特權分離,如果要使用主機證書和使用者證書,請為它們建立單獨的證書頒發機構。 在撰寫本文時,橢圓曲線演算法中的任何一種都是不錯的選擇。

SSH 證書概述

[編輯 | 編輯原始碼]
X.509 是 ITU 電信標準化部門的一個標準,它定義了公鑰證書的格式。

使用證書時,客戶端或伺服器預先配置為接受由另一個金鑰簽名的金鑰,該金鑰專門指定並預留,僅用於對實際用於工作的金鑰進行簽名。 該另一個金鑰稱為證書頒發機構,簡稱 CA。 與普通金鑰一樣,證書用於生成用於身份驗證的簽名。 但是,不是在檔案中查詢匹配的公鑰,而是將公鑰與簽名一起存檔,並且使用簽名驗證公鑰,然後使用公鑰確保協商正在與擁有匹配私鑰的客戶端進行。 因此,使用證書的先決條件至少是對普通 SSH 有基本的瞭解。 請參閱有關 公鑰身份驗證 的章節。 普通基於金鑰的身份驗證機制在引言中簡要描述。 SSH 使用其自己的更簡單的證書格式,而不是 X.509 證書格式。

證書相對於金鑰的兩個主要優勢是,它們可以使用過期日期,甚至有效期範圍,以及它們消除了對首次使用信任或複雜金鑰驗證方法的需要。 大多數情況下,它們透過簡化金鑰審批和分發過程來促進大規模部署,並提供比 將相同的主機金鑰複製到多個目標 更好的選擇。

使用者證書將使用者身份驗證到伺服器或其他遠端裝置上的帳戶。 主機證書將伺服器身份驗證到客戶端,證明客戶端正在連線到正確的系統。 使用 principals 欄位來指定使用者與主機之間的區別是主機證書和使用者證書之間的主要區別。 在主機證書中,principals 欄位指的是證書表示的伺服器名稱。 在使用者證書中,該欄位指的是允許使用證書登入的帳戶。 使用者證書還可以新增其他限制,例如特定源地址和強制命令。 有效日期和時間對於兩者都是可能的。 主機證書和使用者證書應使用單獨的證書頒發機構。 有關更權威的資源,請參閱 ssh-keygen(1) 中的“證書”部分。

SSH 使用者證書

[編輯 | 編輯原始碼]

使用者證書將使用者身份驗證到伺服器或其他遠端裝置,換句話說,它們允許使用者和指令碼登入。 透過使用者證書將客戶端身份驗證到伺服器意味著伺服器上的 authorized_keys 檔案不再需要。 相反,使用者證書(實際上是已簽名的金鑰)會根據證書頒發機構進行檢查,以驗證簽名是否有效。 如果有效,則可以繼續登入過程。 另一個優勢是,可以將簽名指定為僅在一定日期範圍內有效。 因此,在實踐中,可以設定過期日期。 使用者證書也與特定帳戶繫結,稱為“主體”。 允許使用已簽名金鑰的主體必須指定,否則即使證書已正確簽名,伺服器也不會接受使用身份驗證金鑰。

甚至可以使用類似於普通 SSH 公鑰的 force-commandsource-address 選項,來限制傳入連線的來源或強制執行特定命令。 這些限制是在簽名時設定的。 如果需要更改這些選項,則必須重新簽名金鑰,否則它將變得無效。

與 SSH 使用者證書相關的檔案

[編輯 | 編輯原始碼]

與使用者證書相關的檔案有五個。 證書頒發機構必須妥善保管並進行離線儲存。 如果丟失,則無法將新使用者帳戶新增到池中,並且必須建立新的證書頒發機構。 如果落入壞人之手,攻擊者可以使用它將其帳戶冒充為合法使用者。

  • 證書頒發機構 - 用於簽名其他金鑰的專用 SSH 金鑰

下一個儲存在伺服器本身

  • 證書公鑰 - 證書頒發機構的公鑰部分

最後三個檔案儲存在客戶端系統上

  • 專用 SSH 金鑰 - 用於向伺服器或遠端裝置進行身份驗證的私鑰
  • 公鑰 SSH 金鑰 - 已被證書頒發機構簽名的匹配公鑰
  • 使用者證書 - 使用證書頒發機構對使用者公鑰生成的簽名

可選地,可以使用 | ssh_config 檔案將使用者證書及其金鑰永久地與遠端伺服器或裝置關聯,可以全域性關聯,也可以透過 CertificateFileIdentityFile 指令逐帳戶關聯。

使用 SSH 使用者證書的步驟

[編輯 | 編輯原始碼]

使用使用者證書有四個步驟。 第一步,建立證書頒發機構,每個使用者或指令碼池只執行一次。 第二步,調整伺服器配置,可以根據需要針對任意數量的伺服器系統或遠端裝置重複執行。 第三個步驟,簽名使用者金鑰,每個使用者帳戶只執行一次。 第四步,部署使用者證書,可以針對 principals 和任何可能包含的 source-address 限制允許的任意數量的客戶端執行。

1. 建立證書頒發機構

[編輯 | 編輯原始碼]

為主機和使用者保留單獨的證書頒發機構是一個非常好的主意。 因此,為了實現特權分離,即使您已經為主機證書建立了一個證書頒發機構,也請為使用者證書建立一個單獨的證書頒發機構。

$ ssh-keygen -t ed25519 -f ~/.ssh/user_ca_key \
        -C 'User Certificate Authority for *.example.com'

此處生成的私鑰應儲存在伺服器以外的地方。但是,伺服器將能夠訪問公鑰元件,以便能夠驗證客戶端提供的簽名。

2. 在伺服器上儲存證書頒發機構的公鑰元件

[編輯 | 編輯原始碼]

伺服器需要能夠查詢匹配的證書,以驗證使用者金鑰上的簽名。這在 SSH 守護程式的配置中設定。將主機證書複製到主機金鑰儲存的相同位置。然後使用 |sshd_config(5) 中的 TrustedUserCAKeys 指令將 OpenSSH 伺服器指向證書頒發機構的公鑰元件。

TrustedUserCAKeys /etc/ssh/user_ca_key.pub

仔細檢查以確保檔案許可權正確。

$ ls -lhn /etc/ssh/user_ca_key.pub
-rw-r--r--  1 0  0   114B May  4 16:38 /etc/ssh/user_ca_key.pub

然後可以使用任意數量的帳戶使用該證書頒發機構。

3. 處理現有的公鑰

[編輯 | 編輯原始碼]

使用者必須已經建立了金鑰對,然後提交金鑰對的公鑰元件進行簽名。簽署它並將簽署的副本傳回正確的人員。立即刪除此過程的任何工件,因為多餘的公鑰散佈在周圍只會造成混亂。這裡一個名為 server01.ed25519.pub 的公鑰已被接受,並使用它製作了一個證書。

$ ssh-keygen -s user_ca_key -I 'edcba' -z '0002' -n fred \
        server01.ed25519.pub

生成的證書將被命名為 server01.ed25519-cert.pub,並將具有內部 ID "edcba" 和內部序列號 "2"。ID 和序列號必須在外部計算。對於成功的登入,證書的 idserial 欄位將包含在日誌中。有關該主題的更多詳細資訊,請參見部分 日誌記錄和故障排除。為證書列出主體是一個非常好的主意,即使是使用者證書也是如此。證書中列出的主體需要與它將登入的帳戶匹配。

即使在客戶端側登入後不再嚴格需要公鑰本身,但最好讓客戶端保留它。但是,如果公鑰丟失,可以從私鑰重新生成一個新的公鑰,但反之則不行。私鑰一旦丟失,就無法找回。因此,請保持適當的備份計劃。如果存在一個與公鑰應具有的名稱相同的檔案,那麼它最好是公鑰本身,否則登入嘗試將失敗。

獲取公鑰和交付證書的物流超出了本書的範圍。但在這一點上,生成的證書應傳回使用提交的金鑰的人員。

4. 使用 SSH 使用者證書登入

[編輯 | 編輯原始碼]

在客戶端側,登入需要使用者證書及其對應的私鑰。

$ ssh -o CertificateFile=server01.ed25519-cert.pub -i server01.ed25519 \
        fred@server01.example.org

一旦事情手動運作起來,就可以使用客戶端上的 ssh_config(5) 建立一個快捷方式。如果使用代理並且代理中有多個金鑰,則可能還需要使用 IdentitiesOnly

Host server01 server01.example.org
        Hostname server01.example.org
        User fred
        IdentitiesOnly yes
        IdentityFile /home/fred/.ssh/server01.ed25519
        CertificateFile /home/fred/.ssh/server01.ed25519-cert.pub

使用這些設定,在該客戶端上執行 ssh server01 將嘗試應用指定的金鑰及其對應的使用者證書和指定的主體。

SSH 主機證書

[編輯 | 編輯原始碼]

OpenSSH 使用金鑰的主要用途之一是將遠端主機認證到客戶端,以便客戶端可以驗證它是否直接連線到正確的系統,而不是透過中間的入侵者進行模仿。為此,一旦確認,known_hosts 檔案通常會在主機金鑰登錄檔中保留公鑰的副本,與主機名或 IP 地址配對。

主機金鑰通常的難點在於,為大量客戶端機器填充客戶端上的 known_hosts 檔案,或者在首次連線到新系統時填充它。在資料中心、實驗室或物聯網部署中,機器始終處於不斷加入和離開的狀態。這意味著每次都會有新的 SSH 主機金鑰。如果涉及大量主機,那麼這就會加起來,在登錄檔中會有很多金鑰。相反使用主機證書,使用相同證書頒發機構的大量任意主機池只需要在 known_hosts 登錄檔中進行一次條目,即使向池中添加了新主機也是如此。透過簽署新伺服器或裝置用來標識自身的那些主機金鑰,仍然可以在首次嘗試時使用唯一的金鑰推出新系統,但可以確保客戶端能正確且安全地識別它們,而不會冒中間人攻擊的風險。

透過使用主機證書,這些識別主機金鑰被簽署,並且簽名可以根據商定的證書頒發機構進行驗證,從而極大地簡化了在建立第一個連線時收集和驗證主機公鑰的本來繁瑣的過程。

與 SSH 主機證書關聯的檔案

[編輯 | 編輯原始碼]

使用主機證書涉及五個檔案。與使用者證書一樣,證書頒發機構必須保密。與使用者證書相同,但針對主機而不是主機上的帳戶。

  • 證書頒發機構 - 為簽署其他金鑰而生成的私鑰

接下來的三個檔案儲存在伺服器本身。

  • 證書公鑰 - 證書頒發機構的公鑰元件
  • 主機公鑰 - SSH 守護程式用來標識自己到客戶端的實際金鑰
  • 主機證書 - 使用證書頒發機構為主機公鑰生成的簽名

然後在客戶端,要麼在客戶端的登錄檔中,要麼在系統範圍內的已識別主機登錄檔中

  • known_hosts - 包含對主機證書及其主體的引用

當客戶端找到並使用有效的主機證書時,不會為單個主機在 known_hosts 登錄檔中新增任何條目。

使用 SSH 主機證書的步驟

[編輯 | 編輯原始碼]

使用主機證書通常有四個階段。步驟一,建立證書頒發機構,每臺伺服器或伺服器池或裝置僅執行一次。步驟二,簽署主機金鑰,每臺伺服器裝置僅執行一次,步驟三也是如此。步驟四,配置客戶端,可以根據需要為任意數量的客戶端機器或單個登入帳戶重複執行。

在每一步中,都要注意路徑。沒有萬能的解決方案,因此需要決定檔案應該放在哪裡。

1. 建立證書頒發機構

[編輯 | 編輯原始碼]

再說一次,證書頒發機構或 CA 只是另一個 SSH 金鑰。但是,它不是直接用於對伺服器或客戶端進行身份驗證,而是用於簽署然後驗證其他金鑰,這些金鑰實際上用於身份驗證。

$ ssh-keygen -t ecdsa -f ~/.ssh/ca_key \
        -C 'Host Certficate Authority for *.example.com'

此處生成的私鑰應儲存在將使用它們的伺服器以外的地方。

此步驟中的公鑰必須透過帶外方式分發到客戶端,然後客戶端將在首次連線時使用它來驗證主機身份。

2. 獲取和簽署主機金鑰

[編輯 | 編輯原始碼]

只有公鑰被簽署。透過可靠的方法獲取遠端主機的公鑰主機金鑰,簽署它,然後將生成的證書上傳到伺服器。-h 選項表示這將是主機證書,-s 選項指向用於簽署的金鑰。這裡,主機金鑰 ssh_host_ecdsa_key.pub 的副本已從其伺服器獲取,並將本地處理

$ ssh-keygen -h -s ~/.ssh/ca_key -V '+1d' -I abcd -z 00001 \
         -n server.example.com ./ssh_host_ecdsa_key.pub
Enter passphrase: 
Signed host key /etc/ssh/ssh_host_ecdsa_key-cert.pub: id "abcd" serial 1 for server.example.com valid from 2020-05-05T09:51:00 to 2020-05-06T09:52:01

-V選項設定的有效期區間是相對於金鑰簽發日期和時間的相對時間跨度。因此,可以使用公式-V '+1d2h:+1d3h'使證書在明天的某個時間段內有效。如果未設定開始時間,則該值將被解釋為結束時間。如果需要特定的結束時間或日期,最好使用指令碼計算該時間,然後呼叫ssh_key-gen(1)。如果根本沒有提供時間,則證書將被視為無限期有效。

-I選項為證書分配一個標籤,以便於識別。

-z選項手動為證書分配一個序列號。該序列號必須從舊證書中提取,然後在需要保持順序的情況下遞增。預設情況下不使用序列號。-n選項分配一組主體,即哪些主機可以在主機證書的上下文中使用該證書。

可以使用-L選項檢視證書的內容。

$ ssh-keygen -L -f ssh_host_ecdsa_key-cert.pub                   
ssh_host_ecdsa_key-cert.pub:
        Type: ecdsa-sha2-nistp256-cert-v01@openssh.com host certificate
        Public key: ECDSA-CERT SHA256:kVSFLH5MP/3uJWU57JxD8xVFs7ia8Pww8/ro+pq4S50
        Signing CA: ECDSA SHA256:INewUSvbnfVbgUhtLBhh+XKL0uN99qbXjsi0jvD/IGI (using ecdsa-sha2-nistp256)
        Key ID: "abcd"
        Serial: 1
        Valid: from 2020-05-05T09:51:00 to 2020-05-06T09:52:01
        Principals: 
                server.example.com
        Critical Options: (none)
        Extensions: (none)

公鑰主機證書必須傳輸到伺服器可以使用的目錄。這通常意味著與常規公鑰主機證書相同的目錄,預設情況下為/etc/ssh/。將證書複製到適當位置後,請確保其具有正確的許可權。

$ ls /etc/ssh/ssh_host_ecdsa_key*.pub
ls -nlh /etc/ssh/ssh_host_ecdsa_key*.pub
-rw-r--r--  1 0  0   653 May  4 16:49 /etc/ssh/ssh_host_ecdsa_key-cert.pub
-rw-r--r--  1 0  0   172 Feb 21 16:09 /etc/ssh/ssh_host_ecdsa_key.pub

3. 釋出主機證書。

[編輯 | 編輯原始碼]

一旦主機證書就位,遠端主機上的SSH守護程序就必須指向該主機證書。有關更多資訊,請參見sshd_config(5)

HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub

然後必須指示SSH守護程序重新載入其配置檔案。確切的方法因系統而異,但最終守護程序將收到一個HUP訊號。

4. 更新客戶端以確認指定的證書頒發機構

[編輯 | 編輯原始碼]

最後,在客戶端的known_hosts檔案中新增對證書頒發機構的引用

@cert-authority *.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFJQHK0uoOpBfynyKrjF/SjsLMFewUAihosD6UL3/HkaFPI1n3XAg9D7xePyUWf8thR2e0QVl5TeGLdFiGyCgt0=

就是這樣。但是,重要的是要意識到,上述每個步驟都將或多或少地靜默失敗,並且客戶端將退回到通常的驗證主機身份的方法,而不會報告任何錯誤。任何有用的除錯資訊都將記錄在守護程序的日誌中,即使這樣也僅限於一定程度。有關示例,請參見關於日誌記錄和故障排除的章節。

證書部署的編排

[編輯 | 編輯原始碼]

自動部署證書(使用者證書或主機證書)超出了本書的範圍。有很多方法可以做到,並且涉及很多因素。具體細節不僅取決於使用哪種編排軟體,還取決於端點上使用的是哪個特定發行版或作業系統。簡而言之,弄清楚如何手動操作,然後弄清楚如何使用部署指令碼或軟體允許的工作流來自動化該過程。

但是,重要的是要注意,證書頒發機構可以儲存在代理中。調查有關簽署的-U選項。

限制使用者證書

[編輯 | 編輯原始碼]

可以在證書本身內部對使用者證書施加各種限制。這些限制主要是在簽署金鑰時使用-O選項指定的,包括有效期區間、強制命令、源地址範圍、停用偽終端分配等。有關權威列表,請參見ssh-keygen(1)的手冊頁。這些限制可以組合使用,也可以單獨使用。以下示例將為了清晰起見分別說明它們。

使用者證書的時間限制

[編輯 | 編輯原始碼]

證書可以設定為在計劃的時間段內有效,這裡稱為有效期區間。有效期區間可以有特定的開始日期和時間、結束日期和時間,或者兩者都有。但是,每個證書可能只有一個有效期區間。

有效期區間使用-V選項指定,可以使用絕對日期和時間範圍或相對時間範圍。使用上面使用者證書部分的金鑰示例,以下將限制證書的有效期。具體而言,它在2020年6月24日下午1:55至下午2點的五分鐘時間段內有效。

$ ssh-keygen -V '202006241355:202006241400' \
        -s user_ca_key -I 'edcba' -z '0003' -n fred \
        server01.ed25519.pub

請務必仔細檢視生成的輸出,以確保範圍符合預期。

也可以使用相對區間。以下是一個僅在五分鐘內有效的證書,立即開始

$ ssh-keygen -V ':+5m' \
        -s user_ca_key -I 'edcba' -z '0004' -n fred \
        server01.ed25519.pub

請注意,秒也被包含在內,並且從簽署開始時開始計算,而不是從最終輸入密碼並完成簽署時開始計算。因此,如果證書籤署在分鐘開始後的35秒開始,則到期時間也將是第五分鐘後的35秒。並且,再次強調,請仔細檢視生成的輸出。

使用使用者證書強制命令

[編輯 | 編輯原始碼]

透過在建立使用者證書時使用-O選項,可以將使用者證書與伺服器上的特定命令繫結。在本示例中,該證書僅在用於連線到SSH伺服器時顯示時間和日期

$ ssh-keygen -O force-command='/bin/date +"%T %F"' \
        -s user_ca_key -I 'edcba' -z '0005' -n fred \
        server01.ed25519.pub

如果證書和sshd_config(5)中都存在強制命令,則後者優先。任何作為執行時引數傳遞的命令都將被覆蓋,但可以在SSH_ORIGINAL_COMMAND環境變數中找到。來自證書內部的命令不會影響SSH_ORIGINAL_COMMAND變數,必須從證書本身解析,證書將儲存在SSH_USER_AUTH環境變數指向的臨時檔案中。

$ awk '/^publickey/ {print $2,$3}' ${SSH_USER_AUTH} \
        | ssh-keygen -Lf -

該檔案僅在會話仍處於開啟狀態時存在。SSH_USER_AUTH變數本身僅在SSH伺服器的配置將ExposeAuthInfo設定為'yes'時才設定,預設值為'no'。

使用者證書的源地址限制

[編輯 | 編輯原始碼]

證書可以限制為特定的CIDR範圍。

$ ssh-keygen -O source-address='198.51.100.0/24,203.0.113.0/26' \
        -s user_ca_key -I 'edcba' -z '0006' -n fred \
        server01.ed25519.pub

CIDR範圍必須有效。

檢視使用者證書上的限制

[編輯 | 編輯原始碼]

如果證書在手,則可以詳細檢視它,並檢視哪些限制適用(證書端)。以下是一個用於帳戶'fred'、兩個LAN範圍和僅一個多小時訪問許可權的證書示例。

$ ssh-keygen -Lf server01.ed25519-cert.pub

server01.ed25519-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:hSy7QrAApIU1LgDCUrtBK2F2TZxhvincnJ0djSDow7I
        Signing CA: ED25519 SHA256:dVgTW1INbhvHjHbeAe10R9Niu8BpejifO286RZ7/niU (using ssh-ed25519)
        Key ID: "edcba"
        Serial: 7
        Valid: from 2020-06-24T15:17:00 to 2020-06-24T16:23:47
        Principals: 
                fred
        Critical Options: 
                force-command /bin/date +"%T",source-address=192.168.0.0/16,10.11.9.0/26
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

顯然,證書本身無法顯示SSH伺服器配置中進行的任何其他伺服器端限制。

如果使用者證書不在手,但用於身份驗證,則可以使用sshd_config(5)中的ExposeAuthInfo選項提供的SSH_USER_AUTH變數從伺服器獲取證書,從而瞭解限制和所有其他嵌入式特性。證書本身將保留SSH_ORIGINAL_COMMAND變數,因此臨時檔案將是檢視證書中實際內容的唯一方法。再次強調,SSH_USER_AUTH變數指向的證書檔案僅在會話處於開啟狀態時存在。


參考文獻

[編輯 | 編輯原始碼]
  1. Stephen Harris (2016-10-30). "使用 SSH 證書". Retrieved 2020-05-07.
  2. Maggie Danger (2014-08-07). "如何使用身份和證書強化 SSH". Magnus Achim Deininger. Retrieved 2020-05-07.
  3. Mike Malone (2019-09-11). "如果你沒有使用 SSH 證書,你就沒有正確使用 SSH". Smallstep Labs, Inc. Retrieved 2020-05-07.

 

華夏公益教科書