目前Hadoop的穩定版本為1.2.1,我們的實驗就在hadoop-1.2.1上進行
Hadoop 版本:1.2.1
OS 版本: Centos6.4
環境配置
機器名 |
Ip地址 |
功能 |
用戶 |
Hadoop1 |
192.168.124.135 |
namenode, datanode, secondNameNode jobtracker, tasktracer |
hadoop |
Hadoop2 |
192.168.124.136 |
Datanode, tasktracker |
hadoop |
Hadoop3 |
192.168.124.137 |
Datanode, tasktracker |
hadoop |
client |
192.168.124.141 |
client |
test |
簡單介紹一下hadoop安全需要哪些授權
先來看一下hdfs,當一個用戶需要讀寫hadoop集群上的一個文件時,他通常先跟namenode聯系,這就需要namenode的認證(org.apache.hadoop.hdfs.protocol.ClientProtocol定義了需要授權的接口),當namenode成功的認證client用戶時,會返回給用戶存儲文件的datanode,client需要讀寫datanode上的數據時,同樣也需要datanode的認證(org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol定義了需要授權的接口)。datanode和namenode之間也需要聯系,datanode需要定時向namenode發送heartbeat和數據塊的信息(org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol定義了需要授權的接口)。Datanode之間也要發生數據交換,比如負載均衡,數據失效(org.apache.hadoop.hdfs.server.protocol.InterDatanodeProtocol定義了需要授權的接口)。Hadoop通常還需要一個secondnamenode來備份數據,因為secondnamenode定期向namenode發送數據請求,這中間也需要namenode的認證(org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol定義了需要授權的接口)。還有兩個不常用的授權org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol和org.apache.hadoop.security.RefreshUserMappingsProtocol,這兩個授權時檢查是否有刷新授權和用戶的權限。
我們再來看一下mapred框架需要哪些授權
當一個client寫好map和reduce以及其他相關的程序后,他首先向jobtracker提交job,這就需要得到jobtracker的授權(org.apache.hadoop.mapred.JobSubmissionProtocol定義了需要授權的接口)。提交的job經過jobtracker調度后,會合理的分配到tasktracker節點上,hadoop采用的是tasktracker向jobtracker發送heartbeat或其他信息的返回值來得到task的信息,而不是jobttracker將task推送給tasktracker,也就是說tasktracker需要jobtracker的認證(org.apache.hadoop.mapred.InterTrackerProtocol定義了需要授權的接口)。還有一個必要重要的授權,tasktracker在得到task后,不是直接在自己的進程里執行,而是啟動一個叫做Child的子進程,tasktracker和這些Child子進程(通常最多只有兩個map和兩個reduce)需要交換數據。盡管linux存在很多種進程共享數據的方式,Child和tasktracker還是通過網絡的方式來的,這個交換過程主要都是由Child發起的。所以這些Child也需要得到tasktracer的認證(org.apache.hadoop.mapred.TaskUmbilicalProtocol定義了需要授權的接口)。跟hdfs一樣,mapredu中也有兩個不常用的授權org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol和org.apache.hadoop.security.RefreshUserMappingsProtocol,這兩個授權時檢查是否有刷新授權和用戶的權限。
這些授權都在org.apache.hadoop.hdfs.HDFSPolicyProvider和org.apache.hadoop.mapred.MapReducePolicyProvider中定義,有興趣的可能看看。
簡單方式配置
conf/core-site.xml加上
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
</property>
<property>
<name>hadoop.security.authentication</name>
<value>simple</value>
</property>
下面做一些簡單測試,來驗證一下配置
測試代碼1
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://hadoop1:9000");
FileSystem hdfs = FileSystem.get(conf);
Path path = new Path("/user/hadoop/input");
FileStatus[] files = hdfs.listStatus(path);
for(int i=0; i< files.length; i++ ){
System.out.println(files[i].getPath());
}
控制台打出的結果
Exception in thread "main" org.apache.hadoop.ipc.RemoteException: User test is not authorized for protocol interface org.apache.hadoop.hdfs.protocol.ClientProtocol, expected client Kerberos principal is null
at org.apache.hadoop.ipc.Client.call(Client.java:1113)
at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:229)
at com.sun.proxy.$Proxy1.getProtocolVersion(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:85)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:62)
at com.sun.proxy.$Proxy1.getProtocolVersion(Unknown Source)
at org.apache.hadoop.ipc.RPC.checkVersion(RPC.java:422)
at org.apache.hadoop.hdfs.DFSClient.createNamenode(DFSClient.java:183)
at org.apache.hadoop.hdfs.DFSClient.<init>(DFSClient.java:281)
at org.apache.hadoop.hdfs.DFSClient.<init>(DFSClient.java:245)
at org.apache.hadoop.hdfs.DistributedFileSystem.initialize(DistributedFileSystem.java:100)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:1446)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:67)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:1464)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:263)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:124)
at test.TestHdfs.main(TestHdfs.java:18)
從上面的結果可以看出,client機器上的test用戶沒有權限訪問hdfs系統。當我們將代碼稍作改變,見測試代碼2:
測試代碼2
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://hadoop1:9000");
//FileSystem hdfs = FileSystem.get(conf);
FileSystem hdfs = FileSystem.get(new URI("hdfs://hadoop1:9000"), conf, "hadoop");
Path path = new Path("/user/hadoop/input");
FileStatus[] files = hdfs.listStatus(path);
for(int i=0; i< files.length; i++ ){
System.out.println(files[i].getPath());
控制台打出的結果
hdfs://hadoop1:9000/user/hadoop/input/Balancer.java
hdfs://hadoop1:9000/user/hadoop/input/BalancerBandwidthCommand.java
hdfs://hadoop1:9000/user/hadoop/input/BlockAlreadyExistsException.java
hdfs://hadoop1:9000/user/hadoop/input/BlockCommand.java
很顯然,使用hadoop用戶來訪問hdfs就沒有任何問題。換一句話說,一旦客戶端知道hadoop集群的用戶,就可以執行hdfs的操作。這將會存在很大的安全隱患。至少應該有一個登錄系統來提供一個認證功能。
目前常用的認證的方式有如下幾種:
- 用戶名/密碼認證。這是一種常用方式,當用戶數量比較多時,可以采用sql/ldap方式。這種方式通常性能較能。
- 機器地址過濾。 這種方式通常有兩種方式實行,黑名單列表:機器不能訪問,白名單列表:機器能夠訪問。這種方式盡管配置簡單,但是部署比較麻煩,通常表現在:一次修改到處部署。Hadoop實現了此種方式:dfs.hosts,dfs.hosts.exclude。但默認不使用
Kerboros方式,hadoop1后面都實現了這種方式,而且推薦使用這種方式。