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

本文介绍了在Windows上使用Java客户端操作Hadoop集群时遇到的权限问题,并提供了三种解决方案:通过环境变量指定用户、修改系统账号名称及调整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目录,后面的这个是为根目录调整权限。

我喜欢第一个方法。

以上的方法可参考,本人尝试另外一种方法可以解决这个问题。

Run on Hadoop编译程序时,出现如下错误:
        org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=xxx, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x
        因为Eclipse使用Hadoop插件提交作业时,会默认以xxx身份去将作业写入hdfs文件系统中,对应的也就是HDFS上的/user/xxx,我的为/user/root,由于xxx用户对hadoop目录并没有写入权限,所以导致异常的发生。解决方法为:放开 hadoop目录的权限 , 方法有二:
        (1)执行如下命令
        $ hadoop fs -chmod 777 /user/root
        (2)修改Hadoop配置
        修改hadoop的配置文件:conf/hdfs-core.xml,找到dfs.permissions的配置项,将value值改为false,具体如下:
        
            dfs.permissions
            false
            
                If "true", enable permission checking in HDFS.
                If "false", permission checking is turned off, but all other behavior is unchanged.
                Switching from one parameter value to the other does not change the mode, owner or group of files or directories.
            
        
        修改完后重启下hadoop的进程使之生效即可。


转载地址: http://www.huqiwen.com/2013/07/18/hdfs-permission-denied/
<think>嗯,用户遇到了Hadoop集群启动时出现“Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)”的问题。根据提供的引用内容,这通常与SSH公钥配置有关。我需要一步步分析可能的原因和解决办法。 首先,用户的问题是在启动DataNode和SecondaryNameNode时出现的权限拒绝错误。Hadoop的节点间通信依赖于SSH无密码登录,所以问题可能出在SSH配置上。参考引用[1]和[2],常见原因是目标主机的公钥没有正确添加到authorized_keys文件中,或者文件权限设置不正确。 接下来,我需要检查几个方面:SSH密钥生成是否正确,公钥是否复制到目标主机,authorized_keys文件的权限是否正确,以及是否配置了本机到自身的免密登录。例如,引用[3]提到需要设置~/.ssh目录的权限为700,authorized_keys为600。此外,用户可能需要执行ssh-copy-id命令将公钥添加到目标主机,尤其是当涉及到本机登录时,比如hadoop103需要自己的公钥。 可能的解决步骤应包括生成密钥对,分发公钥,设置正确的文件权限,并验证SSH连接。另外,用户需要确保所有集群节点的主机名配置正确,并且在/etc/hosts文件中正确映射IP地址和主机名,避免因主机名解析问题导致的连接失败。 最后,需要提醒用户检查防火墙设置和SELinux状态,因为这些也可能影响SSH连接。如果所有步骤都正确执行,应该能解决权限被拒绝的问题,顺利启动Hadoop服务。</think>### Hadoop集群SSH免密登录配置与权限问题解决方案 当Hadoop集群启动DataNode或SecondaryNameNode时出现`Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)`错误,本质是**SSH免密登录未正确配置**,导致节点间无法通过密钥认证通信。以下是详细解决步骤: --- #### 一、核心问题分析 1. **SSH认证机制** Hadoop主节点需要通过SSH协议远程启动从节点的服务(如DataNode)。若未配置免密登录,系统会尝试密码登录,但Hadoop默认不支持交互式密码输入,因此触发权限错误[^1][^2]。 2. **典型错误原因** - 目标主机的公钥未存入`~/.ssh/authorized_keys` - SSH目录或文件权限过大(Linux要求严格权限) - 未配置本机到自身的免密登录(如`hadoop103`无法SSH到自身) --- #### 二、具体解决步骤 1. **生成SSH密钥对(所有节点执行)** 在**所有Hadoop节点**上执行: ```bash ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa ``` 生成无密码的RSA密钥对,输出路径为`~/.ssh/id_rsa`和`~/.ssh/id_rsa.pub`。 2. **分发公钥到目标节点** - **跨节点分发**(如主节点到DataNode): ```bash ssh-copy-id hadoop103 # 将公钥复制到hadoop103 ``` - **本机自分发**(关键步骤): ```bash ssh-copy-id localhost # 允许本机免密登录 ssh-copy-id hadoop103 # 主机名需与/etc/hosts一致 ``` 3. **验证SSH连接** ```bash ssh hadoop103 date # 测试是否无需密码输出日期 ``` 4. **修正文件权限(关键)** ```bash chmod 700 ~/.ssh # 目录权限必须为700 chmod 600 ~/.ssh/* # 密钥文件权限必须为600 chmod 644 ~/.ssh/*.pub # 公钥文件权限可放宽 ``` --- #### 三、补充验证与调试 - **检查`authorized_keys`内容** 确认文件包含所有节点的公钥(如`hadoop102`, `hadoop103`, `hadoop104`等)。 - **主机名解析验证** 在`/etc/hosts`中确保所有节点IP与主机名正确映射: ```text 192.168.1.102 hadoop102 192.168.1.103 hadoop103 192.168.1.104 hadoop104 ``` - **防火墙与SELinux** 临时关闭防火墙和SELinux测试: ```bash systemctl stop firewalld # 关闭防火墙 setenforce 0 # 临时禁用SELinux ``` --- #### 四、成功验证 完成上述步骤后,重新执行集群启动命令: ```bash sbin/start-dfs.sh # 启动HDFS sbin/start-yarn.sh # 启动YARN ``` 观察日志中是否仍存在`Permission denied`错误[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值