尝试模拟用户访问hdfs时出错

2ic8powd  于 2021-06-01  发布在  Hadoop
关注(0)|答案(1)|浏览(542)

我正试图代表另一个用户访问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("striim1@FCE.CLOUDERA.COM", "/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凭据,joy是我尝试代表他访问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)

这是我在core-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传递给代理用户joy。为什么客户机要在用户joy的上下文中创建文件?
2) 在我的集群部署中,“striim1”只是一个拥有kerberos凭据的用户,而不是这个定义中的超级用户。只有当“striim1”是超级用户或添加到超级用户组时,模拟才能工作吗?
3) 我试图模拟的用户的名称是否应该是有效的os用户?如果没有,会发生什么,在这方面做了什么验证?
4) 我试图使用这个模拟用户编写的目录的权限设置应该是什么?是属于超级用户组还是属于超级用户组?
5) 是否应在我的应用程序中显式调用ugi.createproxyuser?假设我从我想使用超级用户模拟的用户那里执行我的应用程序,然后我将代理用户配置(基本上是传递core site.xm)传递给我的应用程序?这就够了吗(我期望像createproxyuser这样的东西在内部被调用(通过将当前应用程序执行用户作为要模拟的用户)。
提前谢谢。
当做,
尼兰詹

vatpfxk5

vatpfxk51#

1) 即使我将超级用户的ugi传递给代理用户joy。为什么客户机要在用户joy的上下文中创建文件?
当使用代理用户功能来调用hdfs服务(如namenode)时,您将作为“真实用户”进行身份验证,然后调用的执行就好像是由代理用户或“有效用户”完成的一样。在您的代码示例中,striim1是真正的用户,joy是有效的用户。这意味着此客户机代码使用striim1的kerberos凭据对namenode进行身份验证,然后它切换到充当joy真正调用的角色。就像joy正在创建文件一样,这对于文件权限检查非常重要。
你可能还想知道,即使你打电话来,为什么它也会起到快乐的作用 FileSystem#create 外面的 doAs . 那是因为 FileSystem 示例永久绑定到特定 UserGroupInformation 当它被创建时。因为您在 doAs 以代理用户joy的身份运行时,该服务器上的后续操作 FileSystem 继续快乐地执行。
2) 在我的集群部署中,“striim1”只是一个拥有kerberos凭据的用户,而不是这个定义中的超级用户。只有当“striim1”是超级用户或添加到超级用户组时,模拟才能工作吗?
没有要求真正的用户必须是hdfs超级用户。使用striim1的设置似乎运行良好,因为它作为striim1(真实用户)进行身份验证,然后作为joy(有效用户)执行。
3) 我试图模拟的用户的名称是否应该是有效的os用户?如果没有,会发生什么,在这方面做了什么验证?
对于用户来说,服务器上的操作系统级别并不是一个严格的要求。这样做的结果是,当namenode执行调用时,它将像用户不是任何组的成员一样执行(组成员身份是通过操作系统集成来确定的,例如本地定义的组或pamëldap。)如果用户不需要具有组成员身份来访问某些文件,那么这不会是一个问题。
4) 我试图使用这个模拟用户编写的目录的权限设置应该是什么?是属于超级用户组还是属于超级用户组?
在您的示例中,调用的执行就像用户是joy一样。您可以自由选择满足您授予或拒绝访问joy的要求的任何文件权限设置。要在目录中创建新文件,用户必须对路径祖先的所有子组件具有执行权限(示例中为/user和/user/striim1),并对直接祖先具有写入权限(示例中为/user/striim1)。
有关此主题的详细讨论,请参阅《hdfs权限指南》。
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

相关问题