2017-05-22 58 views
1

我想代表另一个用户访问HDFS。我可以与下列应用尝试模拟用户访问HDFS时发生错误

import org.apache.hadoop.conf.Configuration; 
import org.apache.hadoop.fs.FileSystem; 
import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.security.UserGroupInformation; 
import org.apache.log4j.Logger; 
import org.apache.hadoop.fs.FSDataOutputStream; 
import java.security.PrivilegedExceptionAction; 

public class HDFSProxyTest { 

    public static void main (String[] args) throws Exception { 
     String hadoopConfigurationPath = "/etc/hadoop/conf/"; 
     final Configuration hdfsConfiguration = new Configuration(); 
     FileSystem localFileSystem = FileSystem.getLocal(hdfsConfiguration); 
     Path coreSitePath = new Path(hadoopConfigurationPath+"core-site.xml"); 
     hdfsConfiguration.addResource(coreSitePath); 
     Path hdfsSitePath = new Path(hadoopConfigurationPath+"hdfs-site.xml"); 
     hdfsConfiguration.addResource(hdfsSitePath); 
     UserGroupInformation.setConfiguration(hdfsConfiguration); 
     UserGroupInformation.loginUserFromKeytab("[email protected]", "/home/striim/striim1_client.keytab"); 
     UserGroupInformation ugi = 
      UserGroupInformation.createProxyUser("joy", UserGroupInformation.getLoginUser()); 
     FileSystem hadoopFileSystem =ugi.doAs(new PrivilegedExceptionAction<FileSystem>() { 
      public FileSystem run() throws Exception { 
       return FileSystem.get(hdfsConfiguration); 
      } 
     }); 

     FSDataOutputStream fsDataOutputStream = hadoopFileSystem.create(new Path("/user/striim1/hdfsproxy.csv")); 
     fsDataOutputStream.write("This is niranjan!!! testing this\n".getBytes()); 
     fsDataOutputStream.close(); 
     hadoopFileSystem.close(); 
     } 
} 

下面这个程序执行用户striim,我试图仿效超级用户striim1谁拥有Kerberos认证和喜悦想这是用户我正试图访问HDFS。

我最终遇到了这个例外。

2017-05-19 02:45:34,843 - WARN main org.apache.hadoop.util.NativeCodeLoader.<clinit> (NativeCodeLoader.java:62) Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 
Exception in thread "main" org.apache.hadoop.security.AccessControlException: Permission denied: user=joy, access=WRITE, inode="/user/striim1":striim1:striim1:drwxr-xr-x 
    at org.apache.hadoop.hdfs.server.namenode.DefaultAuthorizationProvider.checkFsPermission(DefaultAuthorizationProvider.java:281) 
    at org.apache.hadoop.hdfs.server.namenode.DefaultAuthorizationProvider.check(DefaultAuthorizationProvider.java:262) 
    at org.apache.hadoop.hdfs.server.namenode.DefaultAuthorizationProvider.check(DefaultAuthorizationProvider.java:242) 
    at org.apache.hadoop.hdfs.server.namenode.DefaultAuthorizationProvider.checkPermission(DefaultAuthorizationProvider.java:169) 
    at org.apache.sentry.hdfs.SentryAuthorizationProvider.checkPermission(SentryAuthorizationProvider.java:178) 
    at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:152) 
    at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:3560) 
    at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:3543) 
    at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkAncestorAccess(FSDirectory.java:3525) 
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkAncestorAccess(FSNamesystem.java:6592) 
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInternal(FSNamesystem.java:2821) 
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInt(FSNamesystem.java:2739) 
    at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFile(FSNamesystem.java:2624) 
    at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.create(NameNodeRpcServer.java:599) 
    at org.apache.hadoop.hdfs.server.namenode.AuthorizationProviderProxyClientProtocol.create(AuthorizationProviderProxyClientProtocol.java:112) 
    at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.create(ClientNamenodeProtocolServerSideTranslatorPB.java:401) 
    at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java) 
    at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:617) 
    at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1073) 
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2141) 
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2137) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at javax.security.auth.Subject.doAs(Subject.java:422) 
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1714) 
    at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2135) 

这是我的核心-site.xml中配置

<property> 
    <name>hadoop.proxyuser.striim1.hosts</name> 
    <value>*</value> 
    </property> 
    <property> 
    <name>hadoop.proxyuser.striim1.groups</name> 
    <value>*</value> 
    </property> 

这是文件夹的权限设置,我试图访问

drwxr-xr-x - striim1  striim1    0 2017-05-19 02:50 /user/striim1 

此异常导致我的以下问题

1)即使我将超级用户的UGI传递给代理用户喜悦。为什么客户端试图在用户喜悦的背景下创建文件?

2)在我的集群部署中,“striim1”只是具有Kerberos凭据的用户,并不是根据此definition确实是超级用户。仅当“striim1”是超级用户还是添加到超级用户组时,模拟才会起作用?

3)我试图模仿的用户的名字应该是一个有效的操作系统用户?如果不是会发生什么,在这方面做了什么验证?

4)我试图用这个模拟用户编写的目录的权限设置应该是什么?应该是它拥有的某个位置还是超级用户组的一部分?

5)应该在我的应用程序中明确调用UGI.createProxyUser?假设我从要使用超级用户模拟的用户执行我的应用程序,并将代理用户配置(基本上是通过core-site.xm)传递给我的应用程序?这足够吗? (我期待像createProxyUser这样的内容,通过将当前应用程序执行用户作为用户作为模拟来调用)。

在此先感谢。

问候,

NIRANJAN

回答

1

1)即使我通过超级用户的UGI代理用户的喜悦。为什么客户端试图在用户喜悦的背景下创建文件?

当使用代理用户的功能调用HDFS服务,如在NameNode的,你的“真实用户”,然后调用执行,就好像它是由代理用户或“有效用户”进行验证。在你的代码示例中,striim1是真正的用户,喜悦是有效的用户。这意味着此客户端代码使用striim1的Kerberos凭证向NameNode进行身份验证,然后切换为充当欢乐真正进行呼叫的行为。它将充当欢乐创建文件,这对于文件权限检查非常重要,正如您所见。

您可能还想知道,为什么它尽管在doAs之外调用FileSystem#create,却充当了喜悦。这是因为FileSystem实例在创建时会永久绑定到特定的UserGroupInformation。由于您在作为代理用户欢乐运行的doAs内创建实例,因此该后续操作将继续作为欢乐执行。

2)在我的群集部署中,“striim1”只是具有Kerberos凭据的用户,并不是根据此定义的超级用户。仅当“striim1”是超级用户还是添加到超级用户组时,模拟才会起作用?

没有要求真实用户必须是HDFS超级用户。您的设置与striim1似乎工作正常,因为它认证为striim1(真实用户),然后作为快乐(有效用户)执行。

3)我试图模仿的用户的名字应该是一个有效的操作系统用户?如果不是会发生什么,在这方面做了什么验证?

对于用户来说,存在于服务器的操作系统级别不是一个严格的要求。这样做的结果是当NameNode执行调用时,它将执行,就好像用户不是任何组的成员一样。 (组成员身份由操作系统集成确定,例如本地定义的组或pam_ldap。)如果用户不需要具有组成员身份以访问某些文件,则这不会成为问题。

4)什么应该是我试图用这个模拟用户写的目录的权限设置?应该是它拥有的某个位置还是超级用户组的一部分?

在你的例子中,这个调用就像用户很高兴一样执行。您可以自由选择任何文件权限设置,以满足您授予或拒绝访问喜悦的要求。要在目录中创建新文件,用户必须对路径祖先的所有子组件(在您的示例中为/,/ user和/ user/striim1)具有执行许可权,并将权限写入直接祖先(/ user/striim1在你的例子中)。

有关该主题的更详细讨论,请参阅HDFS Permissions Guide

5)应该在我的应用程序中明确调用UGI.createProxyUser?假设我从要使用超级用户模拟的用户执行我的应用程序,并将代理用户配置(基本上是通过core-site.xm)传递给我的应用程序?这足够吗? (我期待像createProxyUser这样的内容,通过将当前应用程序执行用户作为用户作为模拟来调用)。

听起来好像您正在寻找一种解决方案,您无需专门为代理用户处理编写应用程序,而是可以在执行程序时从外部控制代理用户的使用情况。如果是这样,那么您可以通过将HADOOP_PROXY_USER环境变量设置为您要模拟的用户来控制此项。例如,您可以运行kinit -kt以striim1登录,然后登录set HADOOP_PROXY_USER=joy,然后执行您的程序。

请参阅HADOOP-8561讨论此功能的实施。下面是在UserGroupInformation代码实现这一点:

https://github.com/apache/hadoop/blob/release-2.7.0/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java#L803

+0

这是一个很好的解释。我只是有这些后续问题 1)在一个不安全的环境中,除了具有模仿权限以外,真实用户还有什么作用? 5)在我想从一个应用程序代理多个用户的情况下,我必须明确调用UGI.createProxyUser()。 –

+0

在5)我试着设置这个环境变量设置HADOOP_PROXY_USER =欢乐跑我的程序(注释掉这些行 /* UGI UGI = UGI.createProxyUser( “欢乐”,UGI.getLoginUser()); 文件系统HFS = UGI .doAs(新的PrivilegedExceptionAction (){ 公共文件系统的run(){ 回报FileSystem.get(CONF);} }); */ 但文件是使用用户创建striim1 -RW-R - R-- 3 striim1 striim1 33 2017-05-30 02:29 /user/striim1/hdfsproxynew.csv而不是快乐我在这里错过了什么吗? –

+1

@NiranjanSubramanian,1)在一个不安全的环境中,真正的用户仍然被认为是成为认证用户。只是认证方法很薄弱,基本上只是通过纯文本识别用户名。 5)是的,这是正确的。只有当整个过程需要代理一个用户时,使用'HADOOP_PROXY_USER'才有用。尝试删除'UserGroupInformation#loginUserFromKeytab'调用,而不是在启动应用程序之前使用'kinit -kt'。如果仍然无法正常工作,请考虑跟踪我刚刚在解决问题答案底部关联的代码。 –

相关问题