當前Apache Hadoop認證(authentication)支持simple和kerberos,simple是默認的,其實是信任操作系統的認證結果(也就是直接使用操作系統的用戶)。kerberos是一套第三方的認證系統,我們沒有使用。
以下基於hadoop 2.6.0版本。
hadoop權限相關的問題,涉及四個方面:HDFS權限、YARN資源使用權限、Container使用主機資源權限、主機(hadoop節點)之間的權限;
0. hadoop獲取user/group方式:(hadoop-common組件的,公用,參見
UserGroupInformation類
)
user獲取:優先從kerberos獲取(kerberos模式);從系統HADOOP_USER_NAME變量獲取;從java屬性HADOOP_USER_NAME獲取;獲取操作系統當前用戶
group獲取:從定義的group映射關系獲取hadoop.user.group.static.mapping.overrides;從配置的group映射 類獲取(
hadoop.security.group.mapping
);從系統groups user獲取
(注意:user的獲取是在client上進行的,但是yarn執行task時,需要根據user獲取group,這個操作是在NodeManager的節點上進行的)
這是hadoop-common里面的代碼,所以hdfs、yarn的用戶名相關都使用了這套代碼。(參見代碼UserGroupInformation$HadoopConfiguration類)
HADOOP_USER_NAME屬性是一個很重要的屬性。
static final String HADOOP_USER_NAME = "HADOOP_USER_NAME";
static final String HADOOP_PROXY_USER = "HADOOP_PROXY_USER";
1. hdfs文件系統的權限
HDFS Permissions Guide
默認
POSIX模式:
文件: r->讀;w-
>
寫;x-
>
執行;
目錄: r-
>
list; w-
>
創建或刪除;x-
>
查看子目錄; T/t->不能刪除別人的文件或目錄
不同於POSIX,沒有可執行標志位,所以沒有setuid和setgid;
權限繼承方式:創建文件或目錄,owner是當前用戶,group是上級目錄的group(
When a file or directory is created, its owner is the user identity of the client process, and its group is the group of the parent directory (the BSD rule))
權限驗證方式:任何客戶端有user和group兩個認證信息,訪問任何hdfs上的文件要盡心下面的認證(這個操作僅在NameNode進行):
1. 是否owner; or
2. 文件的group是否包含在用戶的group中; or
3. 其他認證(hdfs的acl等授權功能)。
用戶標識:
如果使用hdfs命令行,
默認,simple模式,取決於os,在類unix系統,等同於`whoami`的輸出
如果使用hadoop服務,參見:
hadoop獲取user/group方式
注:用戶標識和group不是hdfs的內在特性。hdfs沒有任何創建、刪除用戶的相關操作。
Group Mapping組映射
根據用戶獲取組的操作時可配置的(hadoop.security.group.mapping property),默認情況,在linux上相當於執行`groups user`。
這個映射在NN進行,所以要在NN配置。
僅與字符串形式進行。這點與Linux稍有不同(linux有group id)。
實現:
全路徑檢查,且檢查每個子路徑的權限。
一旦客戶端知道文件塊,修改文件權限也不能阻止其訪問。
Super-User
NN程序啟動的用戶即為超級用戶。權限檢測不會失敗;hdfs里沒有標記誰是固定的超級用戶,也就是,誰啟動誰就是超級用戶。它不必是NN/DN的root用戶。
管理員可指定某個組是超級用戶組,改組的所有用戶都是超級用戶(
In addition, the administrator my identify a distinguished group using a configuration parameter. If set, members of this group are also super-users)。超級用戶可以“扮演”其他用戶,行使他們的權限,但是沒看到具體有什么用,參見:
http://hadoop.apache.org/docs/r1.2.1/Secure_Impersonation.html
Web Server
網頁訪問的用戶和組是可配置的,NN上沒有對應的用戶標識。但NN會像有這個用戶那樣操作hdfs
配置
dfs.permissions.enabled = true
dfs.web.ugi = webuser,webgroup
dfs.permissions.superusergroup = supergroup
fs.permissions.umask-mode = 0022
dfs.cluster.administrators = ACL-for-admins
dfs.namenode.acls.enabled = true 默認關閉
2. yarn資源使用的權限
用戶名的獲取和認證使用了hadoop通用的那套,參見:
hadoop獲取user/group方式
3. 操作系統相關權限(Container權限)
YARN Secure Containers :
LinuxContainerExecutor
雖然是NM啟動的container,但是不能訪問NM的私有資源。在程序中使用setuid切換用戶到 YARN application user,使用cgroup
LinuxContainerExecutor::
launchContainer->
verifyUsernamePattern:
linux-container-executor.nonsecure-mode.user-pattern : container的用戶名要滿足的正則表達式表達式;默認"^[_.A-Za-z0-9][-@_.A-Za-z0-9]{0,255}?[$]?$"都滿足
String getRunAsUser(String user) :
user: 使能安全功能(不是simple模式) || !
NM_PREFIX +
"linux-container-executor.nonsecure-mode.limit-users"
NM_PREFIX +
"linux-container-executor.nonsecure-mode.local-user" 配置值(默認nobody)。
執行container命令行:
containerExecutorExe,
//
@{container-executor} 可執行程序路徑(C語言程序),這個程序中會使用setuid/cgroup操作。
runAsUser,
//
getRunAsUser return
user,
//來自hadoop的獲取的用戶名
Integer
.toString(Commands.LAUNCH_CONTAINER.getValue()),
//
container-executor
命令操作碼
appId,
//應用名字
containerIdStr, containerWorkDir.toString(),
nmPrivateCotainerScriptPath.toUri().getPath().toString(),
// task的腳本,一般是
org.apache.hadoop.mapred.MapReduceChildJVM#getVMCommand得到
nmPrivateTokensPath.toUri().getPath().toString(), //認證使用的token
pidFilePath.toString(),
StringUtils.join(",", localDirs),
StringUtils.join(",", logDirs),
resourcesOptions
//cgroup相關信息:組名
defaultContainer
:
org.apache.hadoop.mapreduce.v2.app.job.impl.TaskAttemptImpl#createContainerLaunchContext
org.apache.hadoop.mapred.MapReduceChildJVM#getVMCommand --task的jvm命令行拼接
sb.writeLocalWrapperScript(launchDst, pidFile);
注意: defaultContainer使用的是與NM相同的用戶啟動container,所以本地資源是不隔離的
4. hadoop節點間的權限
kerberos: 解決服務器到服務器的認證;防止了用戶偽裝成Datanode,Tasktracker,去接受JobTracker,Namenode的任務指派。
解決client到服務器的認證
對用戶級別上的認證並沒有實現
默認是沒有限制。
附錄:
1. No such user問題。 hadoop本身沒有檢查用戶合法性的功能(除非配置了第三方插件,如kerberos),但是它要獲取一個用戶的group。默認情況下,調用操作系統的`groups`命令檢查。這就表面上看起來要求NM節點上要有這個用戶,但事實是只要能找到用戶對應的group(作為一個字符串)即可。參見
hadoop獲取user/group方式,可以知道配置
hadoop.user.group.static.mapping.overrides即可指定用戶對應的組,輕松解決這個問題。
15/07/29 14:11:57 INFO ParseDriver: Parse Completed
15/07/29 14:11:57 INFO HiveContext: Initializing HiveMetastoreConnection version 0.13.1 using Spark classes.
15/07/29 14:11:58 INFO metastore: Trying to connect to metastore with URI thrift://heju:9083
15/07/29 14:11:58 WARN ShellBasedUnixGroupsMapping: got exception trying to get groups for user bi_etl
org.apache.hadoop.util.Shell$ExitCodeException: id: bi_etl: No such user
at org.apache.hadoop.util.Shell.runCommand(Shell.java:505)
at org.apache.hadoop.util.Shell.run(Shell.java:418)
at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:650)
at org.apache.hadoop.util.Shell.execCommand(Shell.java:739)
at org.apache.hadoop.util.Shell.execCommand(Shell.java:722)