HDFS客户端的权限错误:Permission denied

本文记录了解决Hadoop HDFS文件上传时出现的权限问题的过程。通过修改系统环境变量HADOOP_USER_NAME,成功地让Windows上的Java客户端能够以指定用户身份操作HDFS文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误,被折磨了几天,问题终得以解决。以此文记录问题的解决过程。

如果想看最终解决问题的方法拉到最后,如果想看我的问题解决思路请从上向下看

问题描述

上传文件的代码:

private static void uploadToHdfs() throws FileNotFoundException,IOException {
        //我的文件地址
        String localSrc = "E:\\快盘\\技术文档\\hadoop\\HDFS初步研究.pdf";
        //存放在云端的目的地址
        String dest = "hdfs://192.168.2.156:9000/user/HDFS初步研究.pdf";
        InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
        //得到配置对象
        Configuration conf = new Configuration();
//        conf.set("fs.default.name","hdfs://192.168.2.156:9000");
        //文件系统
        FileSystem fs = FileSystem.get(URI.create(dest), conf);
        //输出流
        OutputStream out = fs.create(new Path(dest), new Progressable() {
            @Override
            public void progress() {
                System.out.println("上传完一个设定缓存区大小容量的文件!");
            }
        });
        //连接两个流,形成通道,使输入流向输出流传输数据
        IOUtils.copyBytes(in, out, 4096, true);
    }

 

错误的详细描述如下:

org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=Administrator, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x

其实这个错误的原因很容易看出来,用户Administator在hadoop上执行写操作时被权限系统拒绝.

解决问题的过程

看到这个错误的,第一步就是将这个错误直接入放到百度google里面进行搜索。找到了N多篇文章,但是主要的思路就如此篇文章所写的两个解决办法:http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html

1、在hdfs的配置文件中,将dfs.permissions修改为False

2、执行这样的操作 hadoop fs -chmod 777 /user/hadoop

对于上面的第一个方法,我试了行不通,不知道是自己设置错误还是其他原因,对我此法不可行,第二个方法可行。第二个方法是让我们来修改HDFS中相 应文件夹的权限,后面的/user/hadoop这个路径为HDFS中的文件路径,这样修改之后就让我们的administrator有在HDFS的相应 目录下有写文件的权限(所有的用户都是写权限)。

虽然上面的第二步可以解决问题了,上传之后的文件所有者为Administrator,但是总感觉这样的方法不够优雅,而且这样修改权限会有一定的安全问题,总之就是看着不爽,就在想有没有其他的办法?

问题分析

开始仔细的观察了这个错误的详细信息,看到user=Administrator, access=WRITE。这里的user其实是我当前系统(运行客户端的计算机的操作系统)的用户名,实际期望这里的 user=hadoop(hadoop是我的HADOOP上面的用户名),但是它取的是当前的系统的用户名,很明显,如果我将当前系统的用户名改为 hadoop,这个肯定也是可以行得通的,但是如果后期将开发的代码部署到服务器上之后,就不能方便的修改用户,此方法明显也不够方便。

现在就想着Configuration这个是一个配置类,有没有一个参数是可以在某个地方设置以哪个用户运行呢?搜索了半天,无果。没有找到相关的配置参数。

最终只有继续分析代码, FileSystem fs = FileSystem.get(URI.create(dest), conf);代码是在此处开始对HDFS进行调用,所以就想着将HADOOP的源码下下来,debug整个调用过程,这个 user=Administator是在什么时间赋予的值。理解了调用过程,还怕找不到解决问题的办法么?

跟踪代码进入 FileSystem.get-->CACHE.get()-->Key key = new Key(uri, conf);到这里的时候发现key值里面已经有Administrator了,所以关键肯定是在new key的过程。继续跟踪 UserGroupInformation.getCurrentUser()-->getLoginUser()-->login.login() 到这一步的时候发现用户名已经确定了,但是这个方法是Java的核心源码,是一个通用的安全认证,但对这一块不熟悉,但是debug时看到subject 里面有NTUserPrincipal:Administator,所以就想着搜索一下这个东西是啥,结果就找到了下面这一篇关键的文章:

http://www.udpwork.com/item/7047.html

在此篇文章里面作者分析了hadoop的整个登录过程,对于我有用的是其中的这一段:

2.login.login();
这个会调用HadoopLoginModule的login()和commit()方法。
HadoopLoginModule的login()方法是一个空函数,只打印了一行调试日志 LOG.debug("hadoop login");
commit()方法负责把Principal添加到Subject中。
此时一个首要问题是username是什么?
在使用了kerberos的情况下,从javax.security.auth.kerberos.KerberosPrincipal的实例获取username。
在未使用kerberos的情况下,优先读取HADOOP_USER_NAME这个系统环境变量,如果不为空,那么拿它作username。否则,读取HADOOP_USER_NAME这个java环境变量。否则,从com.sun.security.auth.NTUserPrincipal或者com.sun.security.auth.UnixPrincipal的实例获取username。
如果以上尝试都失败,那么抛出异常LoginException("Can’t find user name")。
最终拿username构造org.apache.hadoop.security.User的实例添加到Subject中。

 

看完这一段,我明白了执行login.login的时候调用了hadoop里面的HadoopLoginModule方法,而关键是在commit方法里 面,在这里优先读取HADOOP_USER_NAME系统环境变量,然后是java环境变量,如果再没有就从NTUserPrincipal等里面取。关 键代码为:

    if (!isSecurityEnabled() && (user == null)) {
      String envUser = System.getenv(HADOOP_USER_NAME);
      if (envUser == null) {
        envUser = System.getProperty(HADOOP_USER_NAME);
      }
      user = envUser == null ? null : new User(envUser);
    }

 

OK,看到这里我的需求也就解决了,只要在系统的环境变量里面添加HADOOP_USER_NAME=hadoop(HDFS上的有权限的用户,具 体看自己的情况),或者在当前JDK的变量参数里面添加HADOOP_USER_NAME这个Java变量即可。我的情况添加系统环境变量更方法。

如果是在Eclipse里面运行,修改完环境变量后,记得重启一下eclipse,不然可能不会生效。

解决办法

最终,总结下来解决办法大概有三种:

1、在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)

2、将当前系统的帐号修改为hadoop

3、使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user /xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。

我喜欢第一个方法。

 

 

 

 

<think>嗯,用户这次遇到了一个明确的Hive/Hawq权限错误:SQL状态42501,表示对bi_external_data模式没有操作权限。从用户提供的引用材料看,ta应该是在操作分布式数据库(Hive/Hawq),并且可能正在尝试创建或访问外部表。用户可能是数据工程师或分析师,正在搭建数据仓库。这个错误很典型,通常发生在跨模式操作时权限配置不完整。考虑到用户引用了Hawq的配置和用户创建命令,ta的操作环境可能是Greenplum或Hawq数据库(基于PostgreSQL内核)。我注意到用户贴出的参考引用很有价值:[1]展示了Hive的ALTERDATABASE用法,[2]是Hawq用户创建范例,[3]涉及集群节点状态检查。这说明用户需要的是分布式数据库场景下的解决方案,而不仅是普通PostgreSQL的权限处理。权限问题的核心在于三个层面:对象权限、用户权限、安全机制。针对这个错误,应该分四步解决:确认模式归属>检查用户权限>授予缺失权限>验证集群状态。特别是Hawq的分布式特性,需要确保所有Segment节点同步权限。特别要提醒用户注意安全机制问题。Hawq的模式USAGE权限需要额外注意,且外部表可能涉及跨存储系统的访问权限(如HDFS),这容易遗漏。用户贴出的引用[3]提到资源管理参数,如果集群节点异常也可能导致权限验证失败,所以需要确认集群健康状态。用户应该会需要具体的授权命令模板,特别是GRANT和外部表关联的HDFS权限处理。同时要提醒ta在Hawq中使用数据库所有者(gpadmin)操作更可靠,普通用户授权可能存在继承关系问题。</think> 针对 SQL 权限错误 `42501: permission denied for schema bi_external_data`,以下是系统性的解决方案: --- ### 一、问题根源分析 此错误表明 **当前用户缺少对 `bi_external_data` 模式(schema)的操作权限**。常见原因包括: 1. **用户未被授权**:用户未获得该模式的 `USAGE` 权限。 2. **所有权问题**:用户非模式所有者,且未继承所有者权限。 3. **外部数据限制**:`bi_external_data` 可能关联外部存储系统(如 HDFS),需同步检查存储层权限[^1][^2]。 --- ### 二、解决方案步骤 #### 📌 步骤 1:检查当前用户权限 ```sql -- 查看当前用户权限 (示例语法,以 HAWQ/Greenplum 为例) SELECT grantee, privilege_type FROM information_schema.usage_privileges WHERE schema_name = 'bi_external_data'; ``` - 若结果为空,说明用户无权限。 #### 📌 步骤 2:授予模式访问权限 使用模式所有者或超级用户执行: ```sql -- 授予 USAGE 权限(允许进入模式) GRANT USAGE ON SCHEMA bi_external_data TO <用户名>; -- 授予表操作权限(按需选做) GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA bi_external_data TO <用户名>; -- 若需永久生效,添加默认权限 ALTER DEFAULT PRIVILEGES IN SCHEMA bi_external_data GRANT SELECT, INSERT, UPDATE ON TABLES TO <用户名>; ``` > ✅ **关键提示**: > - `<用户名>` 替换为实际用户名(如 `dwtest`[^2]) > - 外部表需额外检查存储系统权限(如 HDFS 目录的读写权限) #### 📌 步骤 3:验证权限继承 - 检查用户是否属于拥有权限的角色组: ```sql \dg <用户名> -- 查看用户角色关系 ``` - 通过角色授权更高效: ```sql GRANT USAGE ON SCHEMA bi_external_data TO role_data_engineer; GRANT role_data_engineer TO dwtest; ``` #### 📌 步骤 4:检查外部存储权限 若模式包含**外部表**: 1. 确认关联的 HDFS 路径权限: ```bash hadoop fs -ls /path/to/bi_external_data ``` 2. 授予 HDFS 目录权限(需 Hadoop 管理员操作): ```bash hadoop fs -chmod -R 755 /path/to/bi_external_data hadoop fs -chown -R <hadoop_user>:<group> /path/to/bi_external_data ``` #### 📌 步骤 5:确认集群健康状态 权限错误可能由节点宕机引起(资源管理器拒绝请求)[^3]: ```bash # 检查 HAWQ 节点状态 hawq state -v ``` - 确保所有节点状态为 `status='u'`(启动状态) --- ### 三、预防性措施 1. **统一授权模板**: ```sql -- 创建用户时直接授权 CREATE ROLE dwtest WITH PASSWORD '123456' LOGIN; GRANT USAGE ON SCHEMA bi_external_data TO dwtest; ``` 2. **定期审计权限**: ```sql -- 列出模式的所有权限分配 SELECT grantee, privilege_type FROM information_schema.schema_privileges WHERE schema_name = 'bi_external_data'; ``` 3. **使用安全组策略**:通过角色间接授权,避免直接操作用户权限。 --- > ⚠️ **重要说明**: > 1. 需使用 **超级用户或模式所有者** 执行授权命令 > 2. HAWQ/Greenplum 中授予 `USAGE` 后仍需单独授予表级权限 > 3. 外部表需同步处理存储层权限(如 Kerberos 认证或 HDFS ACL) > 4. 集群异常会导致权限验证失败(参考 `hawq_rm_rejectrequest_nseg_limit` 参数[^3]) --- ### 相关问题 1. 如何批量授权用户访问数据库中的多个模式? 2. HAWQ/Greenplum 中普通用户如何安全地创建外部表? 3. Hadoop HDFS 目录权限如何与 HAWQ 外部表权限联动配置? 4. 如何监控 HAWQ 集群节点状态以防止权限错误? [^1]: 需同时处理数据库元数据权限和底层存储权限,尤其是外部表场景。 [^2]: 用户创建时未绑定模式权限导致后续操作受阻。 [^3]: 资源管理器因节点宕机可能直接拒绝请求,产生类权限错误现象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值