Kerberos认证CDH集群调用HDFS API时出现GSSException缺陷令牌错误
问题分析与解决方案
你碰到的这个问题,核心原因是没有走通SPNEGO认证的完整握手流程。curl能成功是因为它会自动处理整个交互:先发送不带认证的请求,拿到服务端返回的401和Negotiate挑战,再用这个挑战生成有效的认证token重新请求。而你的Python代码直接跳过了第一步,上来就发了自己生成的token,服务端根本认不出这个token,所以才会抛出GSS异常和403错误。
具体修正步骤
1. 先触发服务端的认证挑战
首先得发送一个不带Authorization头的请求,让服务端返回401响应,这样才能拿到它抛出的Negotiate挑战内容。
2. 用挑战内容完成Kerberos认证
把拿到的挑战内容传给kerberos.authGSSClientStep,而不是传空字符串,这样生成的token才是服务端能识别的有效凭证。
修正后的完整代码
import requests import kerberos baseurl = "http://<host_name>:50070/webhdfs/v1/prod/?op=LISTSTATUS" # 第一步:发送无认证请求,获取服务端的Negotiate挑战 initial_response = requests.get(baseurl) if initial_response.status_code != 401: raise Exception(f"预期返回401,但实际收到{initial_response.status_code}") # 从响应头中提取Negotiate挑战内容 negotiate_challenge = None for auth_header_part in initial_response.headers.get("WWW-Authenticate", "").split(","): stripped_part = auth_header_part.strip() if stripped_part.startswith("Negotiate"): negotiate_challenge = stripped_part.split(" ", 1)[1] break if not negotiate_challenge: raise Exception("响应头中未找到Negotiate挑战内容") # 第二步:使用挑战内容完成Kerberos认证流程 _, krb_context = kerberos.authGSSClientInit("HTTP/<host_name>") kerberos.authGSSClientStep(krb_context, negotiate_challenge) valid_negotiate_token = kerberos.authGSSClientResponse(krb_context) # 第三步:携带有效认证token发送请求 auth_headers = {"Authorization": f"Negotiate {valid_negotiate_token}"} final_response = requests.get(baseurl, headers=auth_headers) print(final_response.status_code) # 如果需要查看返回的目录内容,可以打印json # print(final_response.json())
额外需要注意的点
- 确保你的Python环境已经正确安装了Kerberos相关库:可以用
pip install pykerberos(大部分系统推荐这个)或者pip install kerberos。 - 运行代码的机器必须配置好Kerberos客户端:
krb5.conf文件配置正确,并且已经通过kinit命令获取了有效的Kerberos票据。 - 确认
HTTP/<host_name>这个服务主体名称(SPN)已经在Kerberos KDC中注册,且你的票据拥有访问该SPN的权限。
内容的提问来源于stack exchange,提问作者Vishant
相关产品推荐
相关产品推荐

