上一篇讲了序列化与压缩。本篇讲 Hadoop 的安全机制——Kerberos 认证、Delegation Token、Proxy User。

Hadoop 安全常被介绍成"Kerberos 配置"。这个描述对应了最显眼的部分但漏了完整设计。准确的说法是:Hadoop 安全是一个分层模型——底层用 Kerberos 做初始强认证,中间层用 Delegation Token 减轻 KDC 压力,资源访问层用 Block Token / Container Token 做时间受限授权,最上层用 ACL 做细粒度权限控制。Proxy User 让超级用户代表真实用户访问 Hadoop,是 HiveServer2 / Oozie / Hue 这类网关服务的核心机制。

本篇只抓一个问题:Kerberos 在 Hadoop 里到底起什么作用、Delegation Token 怎么减少 KDC 压力、Proxy User 与 doAs 模型怎么让网关服务代用户访问。

为什么 Hadoop 需要 Kerberos

Hadoop 默认是 SIMPLE 认证——客户端声称自己是哪个用户,Hadoop 就当作用户名。这种"自报家门"在内部开发环境够用,但在多租户生产集群里完全不安全——任何用户都能伪造身份。

Kerberos 是 MIT 1980 年代设计的网络认证协议,用对称加密 + 可信第三方(KDC)保证身份不可伪造。Kerberos 的核心是票据(ticket)——客户端拿到某个服务的票据后,向服务证明自己身份,不需要每次都查 KDC。

Hadoop 在 Hadoop 1.x 时代(2010 年左右)才集成 Kerberos,原因是早期 Hadoop 假设集群部署在受信任的内部网络。随着 Hadoop 在企业级生产环境普及,多租户集群的安全需求让 SIMPLE 认证不可接受,Kerberos 成为生产部署的标配。

Hadoop 通过 RPC 层的 SASL 抽象接入 Kerberos。Secure Mode 要求所有相关服务使用一致的安全配置,并为每个服务实例配置 principal 与 keytab;这不是可以任意逐节点混开的普通滚动开关,切换认证模式需要按集群升级方案协调重启和验证。

Kerberos 的认证流程

Kerberos 认证的标准流程涉及三方:Client、KDC(Key Distribution Center)、Service。

1
2
3
4
5
6
7
8
9
10
11
12
13
1. Client 向 KDC 的 AS(Authentication Server)申请 TGT
- 用 Client 长期密码加密
- KDC 返回 TGT(Ticket Granting Ticket,包含 Client 身份和会话密钥)

2. Client 用 TGT 向 KDC 的 TGS(Ticket Granting Server)申请 Service Ticket
- TGT 在 KDC 内部交换,不需要 Client 长期密码
- TGS 返回某个具体服务的 Service Ticket

3. Client 向 Service 出示 Service Ticket
- Service 用自己的密码(与 KDC 共享)解密 Ticket 验证身份
- 后续 Client-Service 通信用 Ticket 里的会话密钥加密

4. Service 接受 Client

Hadoop 集群的 Kerberos 配置:

1
2
3
4
5
6
7
8
hadoop.security.authentication = kerberos
hadoop.security.authorization = true

dfs.namenode.kerberos.principal = nn/_HOST@REALM
dfs.namenode.keytab.file = /etc/security/keytabs/nn.service.keytab

yarn.resourcemanager.kerberos.principal = rm/_HOST@REALM
yarn.resourcemanager.keytab.file = /etc/security/keytabs/rm.service.keytab

每个 Hadoop 服务(NameNode、ResourceManager、NodeManager、DataNode)有自己的 principal(服务身份)和 keytab(密码文件,可以本地读取不需要人工输入)。_HOST 是占位符,运行时替换为实际 hostname。

用户侧 Kerberos 认证通过 kinit 命令:

1
2
3
4
kinit alice@REALM        # 输入密码,获取 TGT 缓存在本地
klist # 查看当前 TGT

hadoop fs -ls / # hadoop 命令使用 TGT 向 NN 申请 Service Ticket,NN 验证

TGT 默认有效期 10 小时(KDC 配置),到期前可以 renew(最长 7 天)。renew 不需要重新输入密码。

Kerberos 认证的关键好处是身份不可伪造——Client 必须知道对应 principal 的密码才能拿到有效票据。密码不通过网络传输(只本地使用),KDC 是唯一可信第三方。

Delegation Token:减轻 KDC 压力

Kerberos 的缺陷是每次访问服务都需要 Service Ticket。如果每个 Hadoop RPC 都走 Kerberos,KDC 会成为瓶颈——NameNode 一个集群每秒几万次 RPC,每次都查 KDC 不现实。

Delegation Token 是 Hadoop 自己设计的 token 机制(不是 Kerberos 标准)。Client 第一次用 Kerberos 认证 NameNode 时,可以申请一个 Delegation Token。后续 Client 与 NameNode 的所有 RPC 都用这个 Token 而不是 Kerberos。

1
2
3
4
5
6
7
1. Client kinit 拿到 TGT
2. Client → NN (Kerberos): getDelegationToken()
3. NN 用自己的密钥签发 Token,返回给 Client
4. Client 后续 RPC 用 Token (SASL DIGEST-MD5 机制)
5. Token 在 NN 内部维护状态(签发时间、续期时间、所有者)
6. Token 到期前 Client 调用 renewDelegationToken() 续期
7. 作业完成后 Client 调用 cancelDelegationToken() 主动撤销

Delegation Token 的关键设计:

Token 由 NameNode 用 HMAC(基于自己密钥的消息认证码)签发,Client 不需要每次都查 KDC——NameNode 自己能验证 Token 真伪。

Token 有生命周期(默认 24 小时,最长 7 天,dfs.namenode.delegation.token.max-lifetime)。Token 到期前可以 renew(默认 renew 间隔 24 小时)。

Token 可以在 Client 之间传递(例如作业提交时 Client 把 Token 拷贝给 ApplicationMaster,让 AM 代表自己访问 HDFS)。这是 MapReduce 长作业访问 HDFS 的核心机制——作业持续几小时甚至几天,不可能让 AM 每小时重新 Kerberos 认证。

ResourceManager 也有自己的 Delegation Token(RMDelegationToken),用于 AM 与 RM 的 RPC 认证。机制类似 NN 的 Delegation Token。

Block Token 与 Container Token:资源级授权

Hadoop 还有两类细粒度 token:

Block Token:HDFS 文件块的访问凭证。NameNode 在 Client 打开文件时签发该文件每个 block 的 Block Token。Client 直连 DataNode 读 block 时出示 Block Token,DataNode 验证后允许读。

1
2
3
4
5
6
1. Client → NN: open("/path/to/file")
2. NN 检查 Client ACL 权限
3. NN 签发该文件每个 block 的 Block Token 返回给 Client
4. Client → DN: read block-123, here is Block Token
5. DN 验证 Block Token (用与 NN 共享的密钥)
6. DN 允许 Client 读取 block 数据

Block Token 解决的问题是 DataNode 不知道用户的 ACL——DataNode 只存 block 字节,不知道哪些用户能读。如果不验证,任何 Client 都可以伪造 block ID 直接读 DataNode 拿到数据。Block Token 让 NameNode 在签发 token 时一次性做 ACL 检查,DataNode 只需要验证 token 真伪。

Container Token:YARN Container 的启动凭证。ResourceManager 在分配 Container 给 AM 时签发 Container Token,AM 拿这个 Token 向对应 NodeManager 启动 Container。

1
2
3
4
5
6
1. AM → RM: allocate() 申请 container
2. RM 调度,分配 container-1 在 node-A 上
3. RM 签发 Container Token 给 AM
4. AM → NM (node-A): startContainer(container-1, here is Container Token)
5. NM 验证 Container Token (用与 RM 共享的密钥)
6. NM 启动 container 进程

Container Token 让 NodeManager 只接受 RM 授权的 container 启动请求,AM 不能凭空在自己想要的节点启动任意 container。

ACL:操作级权限控制

Kerberos 解决"你是谁",ACL 解决"你能做什么"。Hadoop 的 ACL 在多个层面:

HDFS ACL:文件 / 目录的权限。每个文件有 owner、group、permission(类似 POSIX rwx)。Hadoop 2.x+ 扩展支持细粒度 ACL(user:alice:rwx、group:dev:r-x)。

1
2
3
hadoop fs -chmod 750 /user/alice
hadoop fs -setfacl -m user:bob:rwx /user/alice/share
hadoop fs -getfacl /user/alice/share

YARN ACL:队列的访问控制。Capacity Scheduler 配置每个队列的 submit-applications 和 administer-queue ACL。

1
2
3
4
5
6
7
8
<property>
<name>yarn.scheduler.capacity.root.dev.acl_submit_applications</name>
<value>alice,bob</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.acl_administer_queue</name>
<value>alice</value>
</property>

MapReduce ACL:作业的查看和修改权限。mapreduce.job.acl-view-jobmapreduce.job.acl-modify-job 配置作业的访问控制。

Service Level Authorization:服务级开关。hadoop.security.authorization=true 启用后,每个 Hadoop 服务可以配置允许访问的用户 / 主机列表。

ACL 是 Hadoop 多租户集群的核心控制机制。Kerberos 保证身份真实,ACL 决定身份能做什么。两层组合让 Hadoop 可以在企业级生产环境安全运行。

Proxy User:网关服务代用户访问

很多 Hadoop 生态服务是"网关"——用户不直接用 hadoop 命令访问集群,而是通过 HiveServer2、Oozie、Hue、Presto 等中间服务。这些服务代用户访问 Hadoop(HDFS / YARN)。

最简单的实现是网关服务用一个超级用户身份访问所有数据,但这破坏了 Hadoop 的审计——NameNode 日志只看到 “hive” 用户访问,不知道真实用户是谁。

Proxy User 机制解决这个问题。超级用户(例如 hive)可以"代表"另一个用户访问 Hadoop,Hadoop 在审计日志里同时记录超级用户和被代表的真实用户。

Proxy User 的 RPC 调用在 ConnectionHeader 里带两个信息:

1
2
effectiveUser = alice           ← 被代理、实际执行操作的用户
realUser = hive ← 持有 Kerberos 凭据的超级用户

NameNode 收到这种 RPC 时:

  1. 验证 realUser(hive)的 Kerberos 票据。
  2. 检查 hive 是否允许 proxy 给 alice(hadoop.proxyuser.hive.hosts,再配 groups 和/或 users)。
  3. 如果允许,用 alice 身份做 ACL 检查、写审计日志。

Proxy User 配置:

1
2
3
4
5
6
7
8
<property>
<name>hadoop.proxyuser.hive.hosts</name>
<value>hive-server-host</value> <!-- hive 只能从这个 host 做 proxy -->
</property>
<property>
<name>hadoop.proxyuser.hive.groups</name>
<value>dev,business-team</value> <!-- hive 只能 proxy 这些组的用户 -->
</property>

这种“主机 + 组和/或用户”限制收窄 hive 超级用户密钥泄露的影响范围:请求来源必须命中 hosts,目标用户还必须命中允许的 groupsusers

Proxy User 的常见场景:

HiveServer2:业务用户通过 JDBC 连 HiveServer2,HiveServer2 用 hive 身份认证后用 doAs=真实用户身份提交 MapReduce/Tez/Spark 作业。

Oozie:工作流引擎,工作流定义里指定 user,Oozie 用 oozie 身份提交作业但 doAs=工作流所有者。

Hue:Web UI,用户登录 Hue 后所有 Hadoop 操作通过 Hue 的 hue 身份 doAs=登录用户。

实验:观察 Hadoop 安全状态

实验状态:UNVERIFIED_RUNTIME。下面是验证步骤,本轮没有连接真实 Kerberos + Hadoop 集群执行。

如果集群启用了 Kerberos,hadoop fs -ls / 在 kinit 之前会失败:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 没有 TGT
hadoop fs -ls /
# 报错: Failed to specify server's Kerberos principal name

# kinit
kinit alice@EXAMPLE.COM
# 输入密码

hadoop fs -ls /
# 成功列出根目录

# 查看 TGT
klist
# Ticket cache: FILE:/tmp/krb5cc_1000
# Default principal: alice@EXAMPLE.COM
# Valid starting Expires Service principal
# 07/26/2026 10:00:00 07/26/2026 20:00:00 krbtgt/EXAMPLE.COM@EXAMPLE.COM

观察 NameNode 的审计日志(hdfs.audit.logger,默认 INFO 级别):

1
2
3
2026-07-26 10:00:01,234 INFO FSNamesystem.audit: allowed=true \
ugi=alice@EXAMPLE.COM (auth:KERBEROS) \
ip=/10.0.0.5 cmd=open src=/user/alice/data.txt dst=null perm=null

每条审计日志记录:是否允许(allowed)、用户身份(ugi,含认证机制)、来源 IP、操作类型、目标文件、权限。

观察 Delegation Token:

1
2
3
4
5
6
# 申请 token
hadoop fs -put /etc/hosts /tmp/test
hdfs fetchdt --webservice "http://namenode:9870" /tmp/token.bin

# 查看 token
hdfs dtutil print /tmp/token.bin

输出 token 的所有者、renewer、签发时间、过期时间。

Proxy User 的审计日志:

1
2
3
2026-07-26 11:00:00,000 INFO FSNamesystem.audit: allowed=true \
ugi=alice (auth:PROXY) via hive/hive-server-host@EXAMPLE.COM (auth:KERBEROS) \
ip=/10.0.0.10 cmd=open src=/user/alice/query.result

这条日志同时记录了 effective user(alice)、real user(hive)和认证机制(PROXY 表示通过 proxy user 机制)。审计完整性比 SIMPLE 模式强得多。

模式提炼

Hadoop 安全体现的设计模式:

1
2
3
4
5
6
7
8
模式:分层认证 + Token 减压 + 资源级授权 + 网关代理

- 初始强认证用 Kerberos(不可伪造身份)
- 服务自己签发 token 减轻 KDC 压力(Delegation Token)
- 每个资源访问用一次性 token(Block Token / Container Token)
- 操作级权限用 ACL(细粒度控制)
- 网关服务用 Proxy User 代用户访问(保留审计)
- 主机 + 组和/或用户限制防止超级用户密钥泄露影响扩散

这个模式不只是 Hadoop。Kafka 的安全栈(SASL + ACL + quotas)与 Hadoop 类似。Spark on YARN 复用 Hadoop 的 Kerberos + Token 机制。HBase 的安全直接用 Hadoop 的 UserGroupInformation,安全机制与 HDFS 完全一致。

云原生时代的对应是 Kubernetes RBAC + ServiceAccount + TokenRequest API。二者都使用有生命周期的 bearer token,但 Kubernetes 投影 token 由 kubelet 自动轮换,没有 Hadoop Delegation Token 那套服务端 renew/cancel 同构语义。

工程迁移表

Hadoop 安全概念 Kafka HBase Kubernetes AWS IAM
Kerberos 认证 SASL/GSSAPI 复用 Hadoop UGI x509 证书 access key + secret
Delegation Token SCRAM Token HBase AuthToken Service Account Token STS Session Token
Block Token - - - S3 Pre-signed URL
Container Token - - Service Account Token ECS Task Role
Proxy User - - impersonate-users STS AssumeRole
ACL topic ACL table ACL RBAC IAM policy

注意 Kubernetes 这一列。K8s 支持 x509 客户端证书等认证方式,也用短期 ServiceAccount Token 给 Pod 访问 API;投影 token 由 kubelet 轮换,不等同于 Hadoop Delegation Token 的 renew/cancel。K8s impersonation 与 Hadoop doAs 都表达代用户操作,但授权模型不同。

常见误解

误解一:“Kerberos 启用后所有 RPC 都查 KDC”。Kerberos 的 Service Ticket 有生命周期(默认 10 小时),Client 拿到后缓存复用,不每次查 KDC。Delegation Token 进一步减少 KDC 压力——长作业只需要一次 Kerberos,后续都用 Token。

误解二:“Proxy User 等于普通用户切换”。Proxy User 是受控的——超级用户只能从配置允许的主机代理命中的组和/或用户。普通用户不能借此任意切换身份;它是 HiveServer2、Oozie 等网关服务的特权。

误解三:“Kerberos 启用很复杂所以可以不开”。Hadoop 1.x 时代确实复杂(需要手工配置 keytab、principal、防火墙),但 Hadoop 2.x+ 之后配置标准化,配合自动化部署工具(Cloudera Manager、Ambari)一键启用。生产集群不开 Kerberos 等于完全无安全,必须开。

误解四:“Token 泄露无所谓,反正会过期”。Token 泄露在过期前仍然有效——攻击者拿到 token 可以冒充用户访问。生产环境通过加密传输(TLS)、keytab 文件严格权限(仅服务用户可读)降低泄露风险。

误解五:“SIMPLE 认证就是不开认证”。SIMPLE 认证仍然有认证机制——Client 通过 whoami 报告用户名,Hadoop 用这个用户名做 ACL 检查。攻击者可以伪造 whoami 输出(修改用户名环境变量),但需要在能跑 hadoop 命令的机器上。SIMPLE 不安全在多租户集群,但在单租户开发环境可以接受。

练习

  1. 在 Kerberos 启用的集群上跑 kinit alice@REALM 获取 TGT,然后 hadoop fs -ls / 验证认证成功。kdestroy 后再试 hadoop fs -ls /,观察错误信息。

  2. hdfs fetchdt /tmp/token.bin 申请 Delegation Token,执行 kdestroy 删除 TGT,再运行 HADOOP_TOKEN_FILE_LOCATION=/tmp/token.bin hadoop fs -ls /,观察 Token 是否仍能认证。hadoop.security.authentication 只接受 simplekerberos,没有 token 这个配置值。

  3. apache/hadoop 源码里找到 UserGroupInformation.javaKerberosInfo.javaSecretManager.javaDelegationTokenIdentifier.java(hadoop-common-project 模块),观察 Kerberos 认证和 Token 签发的核心实现。

  4. 思考题:如果让 Hadoop 用 OAuth 2.0 替代 Kerberos(像现代云原生系统),需要改造哪些组件?这种改造对 Hadoop 多租户隔离有什么影响?

系列导航

序号 主题 状态
00 导读:节点总会失败
01 HDFS 架构与三层切分
02 文件写入路径与流水线
03 文件读取路径与副本选择
04 NameNode 内存模型与启动恢复
05 HDFS HA 与脑裂防御
06 HDFS 3.x 演进与纠删码
07 YARN 架构与三方契约
08 YARN 资源模型、Container 与 NodeLabel
09 YARN 调度器对比:FIFO、Capacity、Fair
10 YARN 应用程序生命周期
11 YARN HA 与 Federation
12 YARN Timeline Service v2
13 MapReduce 编程模型与分而治之
14 MapReduce Shuffle 全流程
15 MRv2 on YARN ApplicationMaster 与 Task Attempt
16 Hadoop RPC 协议栈
17 序列化与压缩 上一篇
18 Hadoop 安全 Kerberos Token ProxyUser 本篇
19 监控与运维 Metrics JMX 日志聚合 下一篇
20 Hadoop 生态 Hive HBase Pig
21 Hadoop 与对象存储 Kubernetes 演进对比
22 Hadoop 设计遗产从 GFS MapReduce 到云原生

参考资料