Hadoop分布式文件系統實現了一個和POSIX系統類似的文件和目錄的權限模型。每個文件和目錄有一個所有者(owner)和一個組(group)。文件或目錄對其所有者、同組的其他用戶以及所有其他用戶分別有着不同的權限。對文件而言,當讀取這個文件時需要有r權限,當寫入或者追加到文件時需要有w權限。對目錄而言,當列出目錄內容時需要具有r權限,當新建或刪除子文件或子目錄時需要有w權限,當訪問目錄的子節點時需要有x權限。每個訪問HDFS的用戶進程的標識分為兩個部分,分別是用戶名和組名列表。每次用戶進程訪問一個文件或目錄foo,HDFS都要對其進行權限檢查:
1、如果用戶即foo的所有者,則檢查所有者的訪問權限;
2、如果foo關聯的組在組名列表中出現,則檢查組用戶的訪問權限;
3、否則檢查foo其他用戶的訪問權限。
如果權限檢查失敗,則客戶的操作會失敗。所以如果我們以某個用戶ls HDFS上某個文件夾時可能會出現以下的錯誤信息:
Caused by: org.apache.hadoop.ipc.RemoteException (org.apache.hadoop.security.AccessControlException): Permission denied: user=iteblog, access=EXECUTE, inode="/user/hadoop":iteblog:iteblog:drwx------
上面的iteblog用戶試圖訪問HDFS上/user/hadoop目錄下的文件,但是iteblog是屬於iteblog組的,而/user/hadoop目錄的權限是drwx------,也就是只有該文件夾所有者才能訪問這個目錄。仔細研究,我們可以找到這個用戶獲取模塊是在UserGroupInformation類中獲取的,部分代碼如下:
Principal user = null; // if we are using kerberos, try it out if (isAuthenticationMethodEnabled(AuthenticationMethod.KERBEROS)) { user = getCanonicalUser(KerberosPrincipal.class); if (LOG.isDebugEnabled()) { LOG.debug("using kerberos user:"+user); } } //If we don't have a kerberos user and security is disabled, check //if user is specified in the environment or properties if (!isSecurityEnabled() && (user == null)) { String envUser = System.getenv(HADOOP_USER_NAME); if (envUser == null) { envUser = System.getProperty(HADOOP_USER_NAME); } user = envUser == null ? null : new User(envUser); } // use the OS user if (user == null) { user = getCanonicalUser(OS_PRINCIPAL_CLASS); if (LOG.isDebugEnabled()) { LOG.debug("using local user:"+user); } } // if we found the user, add our principal if (user != null) { subject.getPrincipals().add(new User(user.getName())); return true; } LOG.error("Can't find user in " + subject); throw new LoginException("Can't find user name");
從上面代碼片段可以知道,Hadoop先判斷集群是否啟用了Kerberos授權,如果是,則直接從配置中獲取用戶(可以為空);如果不是,則往下走。然后判斷是否啟用了安全認證,安全認證是通過下面參數配置的:
<property>
<name>hadoop.security.authentication</name>
<value>simple</value>
</property>
默認是不啟用的。所以如果沒有啟用安全認證或者從Kerberos獲取的用戶為null,那么獲取HADOOP_USER_NAME環境變量,並將它的值作為Hadoop執行用戶。如果我們沒有設置HADOOP_USER_NAME環境變量,那么程序將調用whoami來獲取當前用戶,並用groups來獲取用戶所在組。
根據上面的分析,我們有兩個辦法來解決用戶訪問HDFS失敗的問題(這兩個方法能夠使用的前提都是沒有啟用安全認證):
1、我們可以在啟動程序之前設置HADOOP_USER_NAME環境變量,比如:
[blog@node1 ~]$ export HADOOP_USER_NAME=node1
2、我們可以自定義whoami和groups命令,返回咱們需要的用戶或者組。
只要Hadoop沒有啟用安全認證,我們想咋修改用戶和用戶所在組就咋修改,這樣對存在HDFS上的文件來說是非常不利的。
