之前在論壇看到一個關于HDFS權限的問題,當時無法回答該問題。無法回答并不意味著對HDFS權限一無所知,而是不能準確完整的闡述HDFS權限,因此決定系統地學習HDFS文件權限。HDFS的文件和目錄權限模型共享了POSIX(Portable Operating System Interface,可移植操作系統接口)模型的很多部分,比如每個文件和目錄與一個擁有者和組相關聯,文件或者目錄對于擁有者、組內的其它用戶和組外的其它用戶有不同的權限等。與POSIX模型不同的是,HDFS中的文件沒有可執行文件的概念,因而也沒有setuid和setgid,雖然目錄依然保留著可執行目錄的概念(x),但對于目錄也沒有setuid和setgid。粘貼位(sticky bit)可以用在目錄上,用于阻止除超級用戶,目錄或文件的擁有者外的任何刪除或移動目錄中的文件,文件上的粘貼位不起作用。
當創建文件或目錄時,擁有者為運行客戶端進程的用戶,組為父目錄所屬的組。每個訪問HDFS的客戶端進程有一個由用戶姓名和組列表兩部分組的成標識,無論何時HDFS必須對由客戶端進程訪問的文件或目錄進行權限檢查,規則如下:
- 如果進程的用戶名匹配文件或目錄的擁有者,那么測試擁有者權限
- 否則如果文件或目錄所屬的組匹配組列表中任何組,那么測試組權限
- 否則測試其它權限
如果權限檢查失敗,則客戶端操作失敗。
從hadoop-0.22開始,hadoop支持兩種不同的操作模式以確定用戶,分別為simple和kerberos具體使用哪個方式由參數hadoop.security.authentication設置,該參數位于core-site.xml文件中,默認值為simple。在simple模式下,客戶端進程的身份由主機的操作系統確定,比如在類Unix系統中,用戶名為命令whoami的輸出。在kerberos模式下,客戶端進程的身份由Kerberos憑證確定,比如在一個Kerberized環境中,用戶可能使用kinit工具得到了一個Kerberos ticket-granting-ticket(TGT)且使用klist確定當前的principal。當映射一個Kerberosprincipal到HDFS的用戶名時,除了最主要的部分外其余部分都被丟棄,比如一個principal為todd/foobar@CORP.COMPANY.COM,將映射為HDFS上的todd。無論哪種操作模式,對于HDFS來說用戶標識機制都是外部的,HDFS本身沒有創建用戶標,建立組或者處理用戶憑證的規定。
上面討論了確定用戶的兩種模式,即simple和kerberos,下面學習如何確定用戶組。用戶組是通過由參數hadoop.security.group.mapping設置的組映射服務確定的,默認實現是org.apache.hadoop.security.JniBasedUnixGroupsMappingWithFallback,該實現首先確定Java本地接口(JNI)是否可用,如果JNI可用,該實現將使用hadoop中的API為用戶解析用戶組列表。如果JNI不可用,那么使用ShellBasedUnixGroupsMapping,該實現將使用Linux/Unix中的bash –cgroups命令為用戶解析用戶組列表。其它實現還有LdapGroupsMapping,通過直接連接LDAP服務器來解析用戶組列表。對HDFS來說,用戶到組的映射是在NameNode上執行的,因而NameNode的主機系統配置決定了用戶的組映射。HDFS將文件或目錄的用戶和組存儲為字符串,并且不像Linux/Unix那樣可以將用戶和組轉換為數字。
每個針對文件或者目錄的操作都將全路徑名稱傳遞到NameNode,然后對該路徑的每次操作都將應用權限檢查。客戶端隱含地關聯用戶身份到NameNode的連接,減少改變現存客戶端API的需要。總是存在這么一種情景,當在一個文件上的操作成功后,當重復該操作時可能失敗,因為該文件或者路徑中的某些目錄已經不再存在。例如,當客戶端第一次開始讀取一個文件時,它向NameNode發出的第一個請求來發現該文件第一個塊的位置,第二個尋找其他塊的請求可能失敗。另一方面,對于已經知道文件塊的客戶端來說,刪除文件不會取消訪問。通過添加權限,客戶端對文件的訪問在請求之間可能撤回,對于已經知道文件塊的客戶端來說,改變權限不會取消客戶端的訪問。
HDFS中超級用戶與通常熟悉的Linux或Unix中的root用戶不同,HDFS的超級用戶是與NameNode進程有相同標示的用戶,更簡單易懂些,啟動NameNode的用戶就為超級用戶。對于誰是超級用戶沒有固定的定義,當NameNode啟動后,該進程的標示決定了誰是超級用戶。HDFS的超級用戶不必是NameNode主機的超級用戶,也需用所有的集群使用相同的超級用戶,出于實驗目的在個人工作站上運行HDFS的人自然而然的稱為超級用戶而不需要任何配置。另外參數dfs.permissions.superusergroup設置了超級用戶,該組中的所有用戶也為超級用戶。超級用戶在HDFS中可以執行任何操作而針對超級用戶的權限檢查永遠不會失敗。
HDFS也提供了對POSIX ACL(訪問控制列表)支持來為特定的用戶或者用戶組提供更加細粒度的文件權限。ACL是不同于用戶和組的自然組織層次的有用的權限控制方式,ACL可以為特定的用戶和組設置不同的權限,而不僅僅是文件的擁有者和文件所屬的組。默認情況下,HDFS禁用ACL,因此NameNode禁止ACL的創建,為了啟用ACL,需要在hdfs-site.xml中將參數dfs.namenode.acls.enabled設置為true。
訪問控制列表由一組ACL項組成,每個ACL項命名了特定的用戶或組,并為其授予或拒絕讀,寫和執行的權限,例如:
user::rw- user:bruce:rwx #effective:r-- group::r-x #effective:r-- group:sales:rwx #effective:r-- mask::r-- other::r--
每個ACL項由類型,可選的名稱和權限字符串組成,它們之間使用冒號(:)。在上面的例子中文件的擁有者具有讀寫權限,文件所屬的組具有讀和執行的權限,其他用戶具有讀權限,這些設置與將文件設置為654等價(6表示擁有者的讀寫權限,5表示組的讀和執行權限,4表示其他用戶的讀權限)。除此之外,還有兩個擴展的ACL項,分別為用戶bruce和組sales,并都授予了讀寫和執行的權限。mask項是一個特殊的項,用于過濾授予所有命名用戶,命名組及未命名組的權限,即過濾除文件擁有者和其他用戶(other)之外的任何ACL項。在該例子中,mask值有讀權限,則bruce用戶、sales組和文件所屬的組只具有讀權限。每個ACL必須有mask項,如果用戶在設置ACL時沒有使用mask項,一個mask項被自動加入到ACL中,該mask項是通過計算所有被mask過濾項的權限與(&運算)得出的。對擁有ACL的文件執行chmod實際改變的是mask項的權限,因為mask項扮演的是過濾器的角色,這將有效地約束所有擴展項的權限,而不是僅改變組的權限而可能漏掉其它擴展項的權限。
訪問控制列表和默認訪問控制列表存在著不同,前者定義了在執行權限檢查實施的規則,后者定義了新文件或者子目錄創建時自動接收的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中,準確的權限由模式參數過濾。默認的umask為022,通常新目錄權限為755,新文件權限為644。模式參數為未命名用戶(文件的擁有者),mask及其他用戶過濾拷貝的權限值。在上面的例子中,創建權限為755的子目錄時,模式對最終結果沒有影響,但是如果創建權限為644的文件時,模式過濾器導致新文件的ACL中文件擁有者的權限為讀寫,mask的權限為讀以及其他用戶權限為讀。mask的權限意味著用戶bruce和組sales只有讀權限。拷貝ACL發生在文件或子目錄的創建時,后面如果修改父輩的默認ACL將不再影響已存在子類的ACL。
默認ACL必須包含所有最小要求的ACL項,包括文件擁有者項,文件所屬的組項和其它用戶項。如果用戶沒有在默認ACL中配置上述三項中的任何一個,那么該項將通過從訪問ACL拷貝對應的權限來自動插入,或者如果沒有訪問ACL則自動插入權限位。默認ACL也必須擁有mask,如果mask沒有被指定,通過計算所有被mask過濾項的權限與(&運算)自動插入mask。當一個文件擁有ACL時,權限檢查的算法變為:
- 如果用戶名匹配文件的擁有者,則測試擁有者權限
- 否則,如果用戶名匹配命名用戶項中的用戶名,則測試由mask權限過濾后的該項的權限
- 否則,如果文件所屬的組匹配組列表中的任何組,并且如果這些被mask過濾的權限具有訪問權限,那么使用這么權限
- 否則,如果存在命名組項匹配組列表中的成員,并且如果這些被mask過濾的權限具有訪問權限,那么使用這么權限
- 否則,如果文件所屬的組或者任何命名組項匹配組列表中的成員,但不具備訪問權限,那么訪問被拒絕
- 否則測試文件的其他用戶權限
最佳實踐時基于傳統的權限位設置大部分權限要求,然后定義少量帶有特殊規則的ACL增加權限位。相比較只是用權限位的文件,使用ACL的文件會在NameNode中產生額外的內存消耗。
上面學習了HDFS中的文件權限和訪問控制列表,最后學習一下如何針對權限和ACL進行配置,下表列出了其中的重要參數:
參數名 | 位置 | 用途 |
dfs.permissions.enabled | hdfs-site.xml | 默認值為true,即啟用權限檢查。如果為 false,則禁用權限檢查。 |
hadoop.http.staticuser.user | core-site.xml | 默認值為dr.who,查看web UI的用戶 |
dfs.permissions.superusergroup | hdfs-site.xml | 超級用戶的組名稱,默認為supergroup |
<fs.permissions.umask-mode | core-site.xml | 創建文件和目錄時使用的umask,默認值為八進制022,每位數字對應了擁有者,組和其他用戶。該值既可以使用八進制數字,如022,也可以使用符號,如u=rwx,g=r-x,o=r-x(對應022) |
dfs.cluster.administrators | hdfs-site.xml | 被指定為ACL的集群管理員 |
dfs.namenode.acls.enabled | hdfs-site.xml | 默認值為false,禁用ACL,設置為true則啟用ACL。當ACL被禁用時,NameNode拒絕設置或者獲取ACL的請求 |