上一篇讲了序列化与压缩。本篇讲 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 的 Kerberos 集成不修改 Hadoop 核心代码——通过 RPC 层的 SASL 抽象插入。RPC Server 在 ConnectionHeader 协商时声明认证机制(SIMPLE / KERBEROS / TOKEN),客户端按服务端要求做认证。这让 Kerberos 启用可以滚动升级——不需要重启整个集群,逐节点启用即可。

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 = hive            ← 实际发起 RPC 的用户(超级用户)
realUser = alice ← 被代表的真实用户

NameNode 收到这种 RPC 时:

  1. 验证 effectiveUser(hive)的 Kerberos 票据。
  2. 检查 hive 是否允许 proxy 给 alice(hadoop.proxyuser.hive.hosts + hadoop.proxyuser.hive.groups 配置)。
  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 超级用户密钥泄露的影响范围——攻击者即使拿到 hive 密钥,也只能从特定主机 proxy 特定组的用户,不能任意伪造身份。

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 安全状态

如果集群启用了 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=hive/hive-server-host@EXAMPLE.COM (auth:PROXY) via hive@EXAMPLE.COM (auth:KERBEROS) \
ip=/10.0.0.10 cmd=open src=/user/alice/query.result

这条日志同时记录了 effective user(hive)、real user(alice)、认证机制(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 + Service Account + TokenRequest API。K8s 的 Service Account Token 与 Hadoop Delegation Token 概念几乎相同——服务签发、有生命周期、可以 renew、客户端用 Token 而不是密钥认证。

工程迁移表

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 客户端证书替代 Kerberos——同样是基于公私钥的强认证,但证书管理比 Kerberos 简单(不需要 KDC)。K8s 的 ServiceAccount Token 与 Hadoop Delegation Token 概念几乎一致——服务签发、有 TTL、客户端不需要每次重新认证。K8s 的 impersonate-users 字段与 Hadoop Proxy User 的 doAs 机制完全对应——超级用户代表真实用户访问。

常见误解

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

误解二:“Proxy User 等于普通用户切换”。Proxy User 是受控的——超级用户只能 proxy 配置允许的组和主机。普通用户不能用 su / sudo 切换身份(Kerberos 防止)。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 申请一个 Delegation Token,保存到本地文件。然后用 kdestroy 删除 TGT,再 hadoop fs -D hadoop.security.authentication=token -ls /,观察 Token 是否仍然能认证(在 token 有效期内)。

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

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

系列导航

序号 主题 状态
00-06 HDFS 存储层 第一阶段(已完成)
07-12 YARN 资源管理层 第二阶段(已完成)
13-15 MapReduce 计算模型 第三阶段(已完成)
16 Hadoop RPC 协议栈
17 序列化与压缩:Writable、Avro 与 Codec 上一篇
18 Hadoop 安全:Kerberos、Delegation Token、Proxy User 本篇
19 监控与运维:Metrics V2、JMX、日志聚合 下一篇
20-22 演进、生态与对比 第五阶段,待开始

参考资料