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

时间:2017-05-22 06:11:38

标签: java hadoop hdfs kerberos impersonation

我正在尝试代表其他用户访问HDFS。我正在尝试使用以下应用程序

$cache->delete('customer' . $id);

此应用执行用户 striim ,我尝试模拟的超级用户是 striim1 谁拥有Kerberos凭据且欢乐是代表我试图访问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();
         }
}

这是我在core-site.xml中的配置

 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)

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

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

这个例外让我想到以下问题

1)即使我将超级用户的UGI传递给代理用户欢乐。为什么客户端尝试在用户欢乐的上下文中创建文件?

2)在我的群集部署中,“striim1”只是具有Kerberos凭据的用户,而不是真正的超级用户definition。只有当“striim1”是超级用户或添加到超级用户组时,模拟才会起作用吗?

3)我试图冒充的用户名是否应该是有效的OS用户?如果不是会发生什么以及在这方面做了哪些验证?

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

5)应该在我的应用程序中显式调用UGI.createProxyUser吗?假设我使用超级用户从我想要模仿的用户执行我的应用程序,并且我将代理用户配置(基本上将core-site.xm传递)传递给我的应用程序?这样就够了吗? (我希望通过将当前应用程序执行用户作为用户进行模拟来内部调用createProxyUser之类的东西)。

提前致谢。

此致

NIRANJAN

1 个答案:

答案 0 :(得分:1)

  

1)即使我将超级用户的UGI传递给代理用户欢乐。为什么客户端尝试在用户欢乐的上下文中创建文件?

使用代理用户功能调用NameNode等HDFS服务时,您可以作为&#34;真实用户&#34;进行身份验证。然后调用执行就好像它是由代理用户或有效用户&#34;完成的。在您的代码示例中,striim1是真正的用户,而joy是有效的用户。这意味着此客户端代码使用striim1的Kerberos凭据对NameNode进行身份验证,然后切换到表现得好像joy真正进行了调用。它会像欢乐一样创建文件,这对于您已经看过的文件权限检查非常重要。

您可能也想知道为什么即使您在FileSystem#create之外拨打doAs,它也会充满喜悦。这是因为FileSystem实例在创建时永久绑定到特定UserGroupInformation。由于您在作为代理用户欢乐运行的doAs内创建了实例,因此FileSystem上的后续操作将继续作为快乐执行。

  

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

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

  

3)我试图冒充的用户名是否应该是有效的OS用户?如果不是会发生什么以及在这方面做了哪些验证?

用户不必严格要求存在于服务器上的操作系统级别。这样做的结果是,当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