NFSv4 客戶端識別符號¶
本文件解釋了 NFSv4 協議如何標識客戶端例項,以便在系統重啟期間維護檔案開啟和鎖定狀態。每個客戶端上都維護一個特殊的識別符號和主體。這些可以由管理員、站點管理員提供的指令碼或 Linux 發行商提供的工具設定。
如果客戶端的 NFSv4 識別符號及其主體沒有仔細選擇,則存在風險。
簡介¶
NFSv4 協議使用“基於租約的檔案鎖定”。租約幫助 NFSv4 伺服器提供檔案鎖定保證並管理其資源。
簡單來說,NFSv4 伺服器為每個 NFSv4 客戶端建立一個租約。伺服器將每個客戶端的檔案開啟和鎖定狀態收集在該客戶端的租約下。
客戶端負責定期續訂其租約。在租約保持有效時,持有該租約的伺服器保證客戶端已建立的檔案鎖定保持不變。
如果客戶端停止續訂其租約(例如,如果它崩潰),NFSv4 協議允許伺服器在一定時間後刪除客戶端的開啟和鎖定狀態。當客戶端重新啟動時,它會向伺服器指示與其先前租約關聯的開啟和鎖定狀態不再有效,可以立即銷燬。
此外,每個 NFSv4 伺服器管理一個客戶端租約的持久列表。當伺服器重新啟動並且客戶端嘗試恢復其狀態時,伺服器使用此列表來區分伺服器重新啟動之前持有狀態的客戶端和傳送新的 OPEN 和 LOCK 請求的客戶端。這使得檔案鎖定能夠在伺服器重啟後安全地持續存在。
NFSv4 客戶端識別符號¶
每個 NFSv4 客戶端都向 NFSv4 伺服器提供一個識別符號,以便它們可以將客戶端與其租約相關聯。每個客戶端的識別符號由兩個元素組成
co_ownerid: 一個任意但固定的字串。
啟動驗證器:一個 64 位例項驗證器,使伺服器能夠區分同一客戶端的連續啟動時期。
NFSv4.0 規範將這兩個專案稱為“nfs_client_id4”。NFSv4.1 規範將這兩個專案稱為“client_owner4”。
NFSv4 伺服器將此識別符號繫結到客戶端呈現它時使用的主體和安全風格。伺服器使用此主體來授權客戶端傳送的後續租約修改操作。實際上,此主體是識別符號的第三個元素。
作為呈現給伺服器的身份的一部分,一個好的“co_ownerid”字串具有幾個重要的屬性
“co_ownerid”字串在重新啟動恢復期間標識客戶端,因此該字串在客戶端重新啟動後保持不變。
“co_ownerid”字串幫助伺服器區分客戶端與其他客戶端,因此該字串是全域性唯一的。請注意,沒有中央機構分配“co_ownerid”字串。
由於它經常在網路上以明文形式出現,“co_ownerid”字串不會洩露有關客戶端本身的私有資訊。
“co_ownerid”字串的內容在客戶端在重新啟動後嘗試 NFSv4 掛載之前設定並且不會更改。
NFSv4 協議對“co_ownerid”字串的大小設定了 1024 位元組的限制。
保護 NFSv4 租約狀態¶
NFSv4 伺服器利用如上所述的“client_owner4”為每個客戶端分配唯一的租約。在此方案下,在某些情況下,客戶端可能會相互干擾。這被稱為“租約竊取”。
如果不同的客戶端呈現相同的“co_ownerid”字串並使用相同的主體(例如,AUTH_SYS 和 UID 0),則伺服器無法判斷客戶端是否相同。每個不同的客戶端呈現不同的啟動驗證器,因此對於伺服器來說,它看起來像是一個經常重新啟動的客戶端。在這種情況下,沒有一個客戶端可以維護開啟或鎖定狀態。
如果不同的客戶端呈現相同的“co_ownerid”字串並使用不同的主體,則伺服器可能會允許第一個客戶端正常執行,但拒絕隨後具有相同“co_ownerid”字串的客戶端。
如果客戶端的“co_ownerid”字串或主體不穩定,則無法保證伺服器或客戶端重新啟動後的狀態恢復。如果客戶端意外重新啟動,但向伺服器呈現不同的“co_ownerid”字串或主體,則伺服器會孤立客戶端之前的開啟和鎖定狀態。這會阻止訪問鎖定的檔案,直到伺服器刪除孤立狀態。
如果伺服器重新啟動並且客戶端向伺服器呈現更改的“co_ownerid”字串或主體,則伺服器將不允許客戶端收回其開啟和鎖定狀態,並且可能會在此期間將這些鎖定授予其他客戶端。這被稱為“鎖定竊取”。
租約竊取和鎖定竊取增加了拒絕服務的可能性,在極少數情況下甚至會導致資料損壞。
選擇合適的客戶端識別符號¶
預設情況下,Linux NFSv4 客戶端實現構造其“co_ownerid”字串,首先是“Linux NFS”字樣,然後是客戶端的 UTS 節點名稱(順便說一句,與 AUTH_SYS 憑據中用作“機器名稱”的節點名稱相同)。在小型部署中,這種構造通常足夠。但是,通常情況下,節點名稱本身不夠唯一,並且可能會意外更改。有問題的情況包括
NFS-root(無盤)客戶端,其中本地 DHCP 伺服器(或等效伺服器)不提供唯一的主機名。
單個 Linux 主機中的“容器”。如果每個容器都有一個單獨的網路名稱空間,但不使用 UTS 名稱空間來提供唯一的主機名,則可能存在多個具有相同主機名的 NFS 客戶端例項。
跨多個管理域訪問公共 NFS 伺服器的客戶端。如果未集中分配主機名,則除非主機名中包含域名,否則無法保證唯一性。
Linux 提供了兩種機制來為其“co_ownerid”字串新增唯一性
- nfs.nfs4_unique_id
此模組引數可以透過核心命令列設定任意唯一識別符號字串,或者在載入“nfs”模組時設定。
- /sys/fs/nfs/net/nfs_client/identifier
此虛擬檔案自 Linux 5.3 起可用,它對於訪問它的網路名稱空間是本地的,因此當主機名保持統一時,它可以提供網路名稱空間(容器)之間的區分。
請注意,此檔案在名稱空間建立時為空。如果容器系統可以訪問某種型別的每個容器身份,則可以使用該唯一識別符號。例如,可以在啟動時使用容器的內部識別符號形成唯一識別符號
- sha256sum /etc/machine-id | awk ‘{print $1}’ \
> /sys/fs/nfs/net/nfs_client/identifier
安全注意事項¶
強烈建議對租約管理操作使用加密安全。
如果未配置帶有 Kerberos 的 NFS,則 Linux NFSv4 客戶端使用 AUTH_SYS 和 UID 0 作為其客戶端身份的主體部分。此配置不僅不安全,而且會增加租約和鎖定竊取的風險。但是,它可能是沒有本地持久儲存的客戶端配置的唯一選擇。在這種情況下,“co_ownerid”字串的唯一性和永續性至關重要。
當 Kerberos 金鑰表存在於 Linux NFS 客戶端上時,客戶端會嘗試使用該金鑰表中的一個主體來標識自己到伺服器。“sec=”掛載選項不控制此行為。或者,具有 Kerberos 主體的單使用者客戶端可以使用該主體代替客戶端的主機主體。
為此目的使用 Kerberos 允許客戶端和伺服器對所有“sec=”設定覆蓋的操作使用相同的租約。此外,Linux NFS 客戶端使用帶有 Kerberos 的 RPCSEC_GSS 安全風格和完整性 QOS 來防止傳輸中租約修改請求的修改。
補充說明¶
Linux NFSv4 客戶端在其訪問的每個 NFSv4 伺服器上建立一個租約。來自特定伺服器的 Linux NFSv4 客戶端的 NFSv4 掛載然後共享該租約。
一旦客戶端建立開啟和鎖定狀態,NFSv4 協議允許租約狀態轉換到其他伺服器,跟隨已遷移的資料。這完全向正在執行的應用程式隱藏了資料遷移。Linux NFSv4 客戶端透過向其遇到的所有伺服器呈現相同的“client_owner4”來促進狀態遷移。
另請參閱¶
nfs(5)
kerberos(7)
NFSv4.0 規範的 RFC 7530
NFSv4.1 規範的 RFC 8881。