HDFS 權限指南

概觀

Hadoop 分散式檔案系統 (HDFS) 為檔案和目錄實作權限模型,與 POSIX 模型有許多相似之處。每個檔案和目錄都與一個擁有者和一個群組相關聯。檔案或目錄具有針對擁有者使用者的個別權限、針對群組成員的其他使用者,以及針對所有其他使用者的權限。對於檔案,需要 r 權限才能讀取檔案,需要 w 權限才能寫入或附加到檔案。對於目錄,需要 r 權限才能列出目錄的內容,需要 w 權限才能建立或刪除檔案或目錄,需要 x 權限才能存取目錄的子目錄。

與 POSIX 模型相反,由於沒有可執行檔的概念,因此檔案沒有 setuid 或 setgid 位元。為了簡化,目錄沒有 setuid 或 setgid 位元目錄。sticky 位元可以設定在目錄上,防止除了超級使用者、目錄擁有者或檔案擁有者以外的任何人刪除或移動目錄內的檔案。設定檔案的 sticky 位元沒有作用。檔案或目錄的權限統稱為其模式。一般來說,Unix 表示和顯示模式的習慣會被使用,包括此說明中八進位數字的使用。當建立檔案或目錄時,其擁有者為用戶端程序的使用者身分,其群組為父目錄的群組(BSD 規則)。

HDFS 也提供 POSIX ACL(存取控制清單)的選用支援,以使用針對特定命名使用者或命名群組的更細緻規則來擴充檔案權限。ACL 會在本文稍後更詳細地討論。

每個存取 HDFS 的用戶端程序都有由使用者名稱和群組清單組成的兩部分身分。每當 HDFS 必須對用戶端程序存取的檔案或目錄 foo 進行權限檢查時,

  • 如果使用者名稱與 foo 的擁有者相符,則會測試擁有者權限;
  • 否則,如果 foo 的群組與群組清單的任何成員相符,則會測試群組權限;
  • 否則,會測試 foo 的其他權限。

如果權限檢查失敗,則用戶端操作會失敗。

使用者身分

從 Hadoop 0.22 開始,Hadoop 支援兩種不同的操作模式來判斷使用者的身分,由 hadoop.security.authentication 屬性指定

  • simple

    在此操作模式中,用戶端程序的身分由主機作業系統決定。在類 Unix 系統上,使用者名稱等同於 `whoami`。

  • kerberos

    在 Kerberized 操作中,用戶端程序的身分由其 Kerberos 憑證決定。例如,在 Kerberized 環境中,使用者可以使用 kinit 程式取得 Kerberos 授予憑證的憑證 (TGT),並使用 klist 來判斷其目前的原則。在將 Kerberos 原則對應到 HDFS 使用者名稱時,會捨棄所有組成部分,只保留主要組成部分。例如,原則 todd/foobar@CORP.COMPANY.COM 會在 HDFS 上作為簡單使用者名稱 todd 執行。

不論操作模式為何,使用者身分機制都與 HDFS 本身無關。HDFS 內沒有建立使用者身分、建立群組或處理使用者憑證的規定。

群組對應

一旦使用者名稱已如上所述確定,群組清單將由群組對應服務決定,此服務由 hadoop.security.group.mapping 屬性設定。詳情請參閱 Hadoop 群組對應

權限檢查

每個 HDFS 作業都要求使用者具有特定權限(READ、WRITE 和 EXECUTE 的某種組合),這些權限是透過檔案擁有權、群組成員資格或其他權限授予的。作業可能在路徑的多個組成部分(不只最後一個組成部分)執行權限檢查。此外,有些作業會依賴於路徑擁有者的檢查。

所有作業都需要穿越存取權。穿越存取權要求對路徑的所有現有組成部分(最後一個路徑組成部分除外)具有 EXECUTE 權限。例如,對於存取 /foo/bar/baz 的任何作業,呼叫者必須對 //foo/foo/bar 具有 EXECUTE 權限。

下表說明 HDFS 對路徑的每個組成部分執行的權限檢查。

  • 擁有權:是否檢查呼叫者是否為路徑的擁有者。通常,變更擁有權或權限中繼資料的作業要求呼叫者為擁有者。
  • 父代:請求路徑的父目錄。例如,對於路徑 /foo/bar/baz,父代為 /foo/bar
  • 祖先:請求路徑的最後一個現有組成部分。例如,對於路徑 /foo/bar/baz,如果 /foo/bar 存在,則祖先路徑為 /foo/bar。如果 /foo 存在,但 /foo/bar 不存在,則祖先路徑為 /foo
  • 最後:請求路徑的最後一個組成部分。例如,對於路徑 /foo/bar/baz,最後一個路徑組成部分為 /foo/bar/baz
  • 子樹:對於目錄路徑,目錄本身及其所有子目錄,遞迴。例如,對於路徑 /foo/bar/baz,它有 2 個子目錄,分別稱為 buzboo,則子樹為 /foo/bar/baz/foo/bar/baz/buz/foo/bar/baz/boo
作業 擁有權 父代 祖先 最後 子樹
追加 不適用 不適用 寫入 不適用
串接 否 [2] 寫入(來源) 不適用 讀取(來源)、寫入(目的地) 不適用
建立 不適用 寫入 寫入 [1] 不適用
建立快照 不適用 不適用 不適用 不適用
刪除 否 [2] 寫入 不適用 不適用 讀取、寫入、執行
刪除快照 不適用 不適用 不適用 不適用
取得 ACL 狀態 不適用 不適用 不適用 不適用
取得區塊位置 不適用 不適用 讀取 不適用
取得內容摘要 不適用 不適用 不適用 讀取、執行
取得檔案資訊 不適用 不適用 不適用 不適用
取得檔案連結資訊 不適用 不適用 不適用 不適用
取得連結目標 不適用 不適用 不適用 不適用
取得清單 不適用 不適用 讀取、執行 不適用
取得快照差異報告 不適用 不適用 讀取 讀取
取得儲存政策 不適用 不適用 讀取 不適用
取得 XAttrs 不適用 不適用 讀取 不適用
列出 XAttrs 執行 不適用 不適用 不適用
建立多層目錄 不適用 寫入 不適用 不適用
修改 ACL 項目 不適用 不適用 不適用 不適用
移除 ACL 不適用 不適用 不適用 不適用
移除 ACL 項目 不適用 不適用 不適用 不適用
移除預設 ACL 不適用 不適用 不適用 不適用
移除 XAttr 否 [2] 不適用 不適用 寫入 不適用
重新命名 否 [2] 寫入 (來源) 寫入 (目的地) 不適用 不適用
重新命名快照 不適用 不適用 不適用 不適用
設定 ACL 不適用 不適用 不適用 不適用
設定擁有者 是 [3] 不適用 不適用 不適用 不適用
設定權限 不適用 不適用 不適用 不適用
設定複製 不適用 不適用 寫入 不適用
設定儲存政策 不適用 不適用 寫入 不適用
設定時間 不適用 不適用 寫入 不適用
設定 XAttr 否 [2] 不適用 不適用 寫入 不適用
截斷 不適用 不適用 寫入 不適用

[1] 在 建立 期間,只有在呼叫使用覆寫選項且路徑中存在檔案時,才需要對最終路徑組件有寫入存取權。

[2] 任何檢查父目錄寫入權限的作業,如果設定了 黏著位元,也會檢查擁有權。

[3] 呼叫 setOwner 來變更擁有檔案的使用者,需要 HDFS 超級使用者 存取權。變更群組不需要 HDFS 超級使用者存取權,但呼叫者必須是檔案的擁有者,而且是指定群組的成員。

了解實作

每個檔案或目錄作業都會將完整路徑名稱傳遞給 NameNode,而且權限檢查會沿著路徑套用於每個作業。用戶端架構會將使用者身分隱含地與與 NameNode 的連線關聯,減少對現有用戶端 API 變更的需求。一直以來,當對檔案的某個作業成功時,如果重複執行,作業可能會失敗,因為檔案或路徑上的某個目錄不再存在。例如,當用戶端第一次開始讀取檔案時,它會對 NameNode 提出第一個要求,以找出檔案的第一個區塊的位置。找到其他區塊的第二個要求可能會失敗。另一方面,刪除檔案不會撤銷已知道檔案區塊的用戶端的存取權。加入權限後,用戶端對檔案的存取權可能會在要求之間被撤銷。同樣地,變更權限不會撤銷已知道檔案區塊的用戶端的存取權。

檔案系統 API 的變更

如果權限檢查失敗,所有使用路徑參數的方法都會擲回 AccessControlException

新方法

  • public FSDataOutputStream create(Path f, FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException;
  • public boolean mkdirs(Path f, FsPermission permission) throws IOException;
  • public void setPermission(Path p, FsPermission permission) throws IOException;
  • public void setOwner(Path p, String username, String groupname) throws IOException;
  • public FileStatus getFileStatus(Path f) throws IOException;將另外傳回與路徑相關聯的使用者、群組和模式。

新檔案或目錄的模式受到設定為組態參數的 umask 限制。當使用現有的 create(path, …) 方法(沒有權限參數)時,新檔案的模式為 0666 & ^umask。當使用新的 create(path, permission, …) 方法(有權限參數 P)時,新檔案的模式為 P & ^umask & 0666。當使用現有的 mkdirs(path) 方法(沒有權限參數)建立新目錄時,新目錄的模式為 0777 & ^umask。當使用新的 mkdirs(path, permission) 方法(有權限參數 P)時,新目錄的模式為 P & ^umask & 0777

應用程式 Shell 的變更

新操作

  • chmod [-R] mode file ...

    只有檔案擁有者或超級使用者才能變更檔案的模式。

  • chgrp [-R] group file ...

    呼叫 chgrp 的使用者必須屬於指定的群組,且為檔案擁有者,或為超級使用者。

  • chown [-R] [owner][:[group]] file ...

    檔案的擁有者只能由超級使用者變更。

  • ls file ...

  • lsr file ...

    輸出重新格式化,以顯示擁有者、群組和模式。

超級使用者

超級使用者與 NameNode 程序本身具有相同身分的使用者。簡單來說,如果您啟動 NameNode,那麼您就是超級使用者。超級使用者可以在其中執行任何操作,因為權限檢查永遠不會讓超級使用者失敗。沒有關於誰是超級使用者的持續概念;當 NameNode 啟動時,程序身分會決定誰是目前的超級使用者。HDFS 超級使用者不必是 NameNode 主機的超級使用者,所有叢集也不一定具有相同的超級使用者。此外,在個人工作站上執行 HDFS 的實驗者,會方便地成為該安裝的超級使用者,而無需任何組態。

此外,管理員可以使用組態參數識別一個特殊群組。如果設定,此群組的成員也是超級使用者。

網路伺服器

預設情況下,網路伺服器的識別碼是組態參數。也就是說,NameNode 沒有實際使用者的識別碼概念,但網路伺服器會表現得好像它有管理員選擇的使用者(使用者和群組)識別碼。除非所選的識別碼與超級使用者相符,否則網路伺服器可能無法存取名稱空間的部分內容。

ACL(存取控制清單)

除了傳統的 POSIX 權限模式,HDFS 也支援 POSIX ACL(存取控制清單)。ACL 可用於實作與使用者的自然組織階層不同的權限需求。ACL 提供一種方式,可以設定特定命名使用者或命名群組的不同權限,而不仅仅是檔案擁有者和檔案群組。

預設情況下,會啟用對 ACL 的支援,而且 NameNode 允許建立 ACL。若要停用對 ACL 的支援,請在 NameNode 組態中將 dfs.namenode.acls.enabled 設為 false。

ACL 包含一組 ACL 項目。每個 ACL 項目會命名特定的使用者或群組,並授予或拒絕該特定使用者或群組的讀取、寫入和執行權限。例如

   user::rw-
   user:bruce:rwx                  #effective:r--
   group::r-x                      #effective:r--
   group:sales:rwx                 #effective:r--
   mask::r--
   other::r--

ACL 項目包含類型、選用名稱和權限字串。為了顯示目的,':' 用作每個欄位之間的分隔符號。在此範例 ACL 中,檔案擁有者具有讀取寫入存取權、檔案群組具有讀取執行存取權,而其他人具有讀取存取權。到目前為止,這等於將檔案的權限位元組設定為 654。

此外,還有 2 個延伸 ACL 項目,分別是命名使用者 bruce 和命名群組 sales,兩個都授予完全存取權。遮罩是一個特殊的 ACL 項目,用於篩選授予所有命名使用者項目和命名群組項目的權限,以及未命名群組項目。在此範例中,遮罩僅具有讀取權限,而且我們可以看到,多個 ACL 項目的有效權限已過濾相應地。

每個 ACL 都必須有一個遮罩。如果使用者在設定 ACL 時未提供遮罩,則會自動插入遮罩,方法是計算會被遮罩篩選的所有項目的權限聯集。

對具有 ACL 的檔案執行 chmod 實際上會變更遮罩的權限。由於遮罩會作為篩選器,因此這會有效地限制所有延伸 ACL 項目的權限,而不是只變更群組項目,並可能遺漏其他延伸 ACL 項目。

此模式還會區分「存取 ACL」(定義在權限檢查期間要執行的規則)和「預設 ACL」(定義新的子檔案或子目錄在建立期間自動接收的 ACL 項目)。例如

   user::rwx
   group::r-x
   other::r-x
   default:user::rwx
   default:user:bruce:rwx          #effective:r-x
   default:group::r-x
   default:group:sales:rwx         #effective:r-x
   default:mask::r-x
   default:other::r-x

僅目錄可以有預設 ACL。當建立新檔案或子目錄時,它會自動將其父目錄的預設 ACL 複製到其自己的存取 ACL 中。新的子目錄也會將它複製到其自己的預設 ACL 中。這樣一來,當建立新的子目錄時,預設 ACL 會複製到檔案系統樹的任意深度層級。

新子目錄存取 ACL 中的確切權限值會受到模式參數的篩選。考量到 022 的預設 umask,這通常是新目錄的 755 和新檔案的 644。模式參數會篩選未命名使用者(檔案擁有者)、遮罩和其他權限值。使用這個特定範例 ACL,並建立一個模式為 755 的新子目錄,這個模式篩選不會影響最終結果。但是,如果我們考慮建立一個模式為 644 的檔案,則模式篩選會讓新檔案的 ACL 接收未命名使用者(檔案擁有者)的讀寫權限、遮罩的讀取權限和其他人的讀取權限。這個遮罩也表示,命名使用者 bruce 和命名群組 sales 的有效權限僅為讀取。

請注意,複製會在建立新檔案或子目錄時發生。隨後對父目錄預設 ACL 的變更不會變更現有的子目錄。

預設 ACL 必須具備所有最低要求的 ACL 項目,包括未命名使用者(檔案擁有者)、未命名群組(檔案群組)和其他項目。如果使用者在設定預設 ACL 時未提供其中一個項目,則會自動插入這些項目,方法是複製存取 ACL 中對應的權限,或是在沒有存取 ACL 時複製權限位元。預設 ACL 也必須有遮罩。如上所述,如果未指定遮罩,則會自動插入遮罩,方法是計算會被遮罩篩選的所有項目權限的聯集。

請注意,您無法為特定檔案或目錄擁有無限量的 ACL 項目。存取項目的最大數量為 32,預設項目的最大數量為 32,總計為 64。

在考量具有 ACL 的檔案時,權限檢查演算法會變更為

  • 如果使用者名稱與檔案擁有者相符,則會測試擁有者權限;

  • 否則,如果使用者名稱與其中一個命名使用者項目中的名稱相符,則會測試這些權限,並由遮罩權限篩選;

  • 否則,如果檔案群組與群組清單中的任何成員相符,而且這些權限由遮罩篩選後授予存取權,則會使用這些權限;

  • 否則,如果有一個命名群組項目與群組清單中的成員相符,而且這些由遮罩篩選的權限授予存取權,則使用這些權限;

  • 否則,如果檔案群組或任何命名群組項目與群組清單中的成員相符,但這些權限並未授予存取權,則拒絕存取;

  • 否則,會測試檔案的其他權限。

最佳做法是依賴傳統權限位元來實作大部分的權限需求,並定義較少數量的 ACL 來使用少數例外規則來擴充權限位元。與僅有權限位元的檔案相比,具有 ACL 的檔案會在 NameNode 中產生額外的記憶體成本。

ACLs 檔案系統 API

新方法

  • public void modifyAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
  • public void removeAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
  • public void public void removeDefaultAcl(Path path) throws IOException;
  • public void removeAcl(Path path) throws IOException;
  • public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException;
  • public AclStatus getAclStatus(Path path) throws IOException;

ACLs Shell 指令

  • hdfs dfs -getfacl [-R] <path>

    顯示檔案和目錄的存取控制清單 (ACL)。如果目錄具有預設 ACL,則 getfacl 也會顯示預設 ACL。

  • hdfs dfs -setfacl [-R] [-b |-k -m |-x <acl_spec> <path>] |[--set <acl_spec> <path>]

    設定檔案和目錄的存取控制清單 (ACL)。

  • hdfs dfs -ls <args>

    ls 的輸出會將「+」字元附加到具有 ACL 的任何檔案或目錄的權限字串。

    請參閱 檔案系統 Shell 文件,以完整了解這些指令。

設定參數

  • dfs.permissions.enabled = true

    如果為是,請使用此處所述的權限系統。如果為否,則會關閉權限檢查,但所有其他行為保持不變。從一個參數值切換到另一個參數值不會變更檔案或目錄的模式、擁有者或群組。無論權限是否開啟或關閉,chmod、chgrp、chown 和 setfacl 始終會檢查權限。這些功能僅在權限內容中才有用,因此不存在向後相容性問題。此外,這允許管理員在開啟常規權限檢查之前可靠地設定擁有者和權限。

  • dfs.web.ugi = webuser,webgroup

    網頁伺服器要使用的使用者名稱。將其設定為超級使用者的名稱,允許任何網頁用戶端查看所有內容。將其變更為其他未使用的身分,允許網頁用戶端僅查看使用「其他」權限可見的內容。其他群組可以新增到以逗號分隔的清單中。

  • dfs.permissions.superusergroup = supergroup

    超級使用者群組的名稱。

  • fs.permissions.umask-mode = 0022

    建立檔案和目錄時使用的 umask。對於設定檔,可以使用十進位數值 18。

  • dfs.cluster.administrators = ACL-for-admins

    群集的管理員,指定為 ACL。這會控制誰可以存取 HDFS 中的預設 servlet 等。

  • dfs.namenode.acls.enabled = true

    設定為 true 以啟用對 HDFS ACL(存取控制清單)的支援。預設情況下,會啟用 ACL。當 ACL 停用時,NameNode 會拒絕所有設定 ACL 的嘗試。

  • dfs.namenode.posix.acl.inheritance.enabled

    設定為 true 以啟用 POSIX 風格的 ACL 繼承。預設為啟用。當啟用且建立要求來自相容用戶端時,NameNode 會將父目錄的預設 ACL 套用至建立模式,並忽略用戶端 umask。如果找不到預設 ACL,則會套用用戶端 umask。