☰
大数据集群Kerberos认证实战:从KDC搭建到五大组件完整配置
2026/10/1 4:44:13 网站建设 项目流程

给大数据集群加 Kerberos,应该是很多团队从测试环境走向生产环境要过的第一道坎。内容本身不难理解,就是给每个组件发一张“身份证”,难的是涉及的组件太多:Zookeeper 要认、Hadoop 要认、Hive 要认、Spark 要认、Presto 还要认,任何一个环节 principal 写错一个字母,整个链条就断给你看。这篇文章我用一套三节点环境把这些组件完整走一遍,从 KDC 搭建到每个组件的 keytab 化,再到启动顺序和踩坑记录,给正在做同样事情的你一个可以直接抄的模板。先说明前提:下面这套操作假设你的组件已经以无认证模式跑通了,集群本身没问题的前提下再来配认证,否则你会把组件本身的故障误判成 Kerberos 的问题,排查起来非常痛苦。

1. 认证整体规划:为什么从 ZooKeeper 开始

给一套 Hadoop 生态配 Kerberos,最忌讳的就是零散地按组件一个个配,配完 HDFS 发现 ZooKeeper 没开认证,又回头补,补完 ZooKeeper 又发现 Hive 连不上 HDFS 了。我建议先画一张认证链路图,理清楚谁依赖谁、谁要验证谁的票据,然后再动手。

1.1 认证链路拆解

在这个集群里,所有组件最终都要落到 HDFS 上读写数据,而 HDFS 的 NameNode 元数据协调又依赖 ZooKeeper,Hive 的 Metastore 和 Presto 的 Hive Connector 都要通过 ZooKeeper 维护会话,Spark 任务跑在 YARN 上,YARN 的 ResourceManager 又依赖 ZooKeeper 做 HA。所以认证开启顺序基本就是启动顺序的反向:先 ZooKeeper,再 HDFS/YARN,再 Hive,再 Spark,最后 Presto。

ZooKeeper 不开认证的情况下,HDFS 开了认证是没意义的,因为客户端可以绕过 NameNode 直连 ZooKeeper 干扰分布式锁和 leader 选举。Hadoop 侧开启 Kerberos 后,所有 RPC 通道默认都要求票据,而 Hive 的 Metastore 要连 HDFS,Server2 要接收客户端的令牌,这两条通道必须同时打开,否则 beeline 能连上却查不了数据。Spark 本身不持有长期凭证,它依赖 YARN 的 ResourceManager 去获取 HDFS 访问权限,所以 Spark 的配置反而很简单。Presto 是最后一个接入的,它既要验证客户端身份,又要在服务端以指定 principal 去访问 Hive Metastore 和 HDFS,双端都要配。

1.2 principal 与 keytab 规划表

Kerberos 里表达身份的单位叫 principal,格式类似服务名/主机名@域。配置前先把所有需要的主体列出来,我给这套三节点环境(bigdata101、bigdata102、bigdata103,域统一用 EXAMPLE.COM)做的规划如下,你可以直接套用:

服务组件principalkeytab 路径部署节点
ZooKeeperzookeeper/bigdata101@EXAMPLE.COM等/etc/security/keytab/zk.service.keytab每个 ZK 节点各一份
HDFS NameNodehdfs/bigdata101@EXAMPLE.COM/etc/security/keytab/hdfs.service.keytabNameNode
HDFS DataNodehdfs/bigdata102@EXAMPLE.COM等/etc/security/keytab/hdfs.service.keytab每个 DataNode
Web UI(SPNEGO)HTTP/bigdata101@EXAMPLE.COM等/etc/security/keytab/http.service.keytabNameNode / RM / HistoryServer
YARN ResourceManageryarn/bigdata101@EXAMPLE.COM/etc/security/keytab/yarn.service.keytabResourceManager
YARN NodeManageryarn/bigdata102@EXAMPLE.COM等/etc/security/keytab/yarn.service.keytab每个 NodeManager
Hive Metastore / HiveServer2hive/bigdata101@EXAMPLE.COM/etc/security/keytab/hive.service.keytabHive 所在节点
Spark HistoryServerspark/bigdata101@EXAMPLE.COM/etc/security/keytab/spark.service.keytabSpark HistoryServer
PrestoServerpresto-server/bigdata101@EXAMPLE.COM/etc/security/keytab/presto.service.keytabPresto 所在节点

这里有个常见误区:每个节点要导出的 keytab 只包含该节点自己的 principal,不要把三台节点的 keytab 全部合成一个大文件再分发。虽然技术上也能用,但一旦某台机器被攻破,所有节点的凭证都暴露了,违背了最小权限原则。

2. KDC 环境搭建:Kerberos 的地基

大数据生态下的 Kerberos 实现基本就是 MIT Kerberos,虽然还有 Heimdal 和 Windows AD,但社区和 Hadoop 官方默认支持的都是 MIT。原因很简单,Apache 各项目的文档、参数和报错信息都围绕 MIT 的配置格式来写,其他实现容易遇到兼容性怪问题。

2.1 安装与 krb5.conf 配置

我用 CentOS 7.9 环境来演示,安装命令三条:

yum install -y krb5-server krb5-libs krb5-workstation

KDC 服务端我放在 bigdata101 上,客户端三台都装。装完之后先改/etc/krb5.conf,这个文件是所有客户端认证行为的核心配置,三台节点必须内容一致:

[libdefaults] default_realm = EXAMPLE.COM dns_lookup_kdc = false dns_lookup_realm = false ticket_lifetime = 24h renew_lifetime = 7d forwardable = true rdns = false udp_preference_limit = 1 default_ccache_name = FILE:/tmp/krb5cc_%{uid} [realms] EXAMPLE.COM = { kdc = bigdata101.example.com admin_server = bigdata101.example.com } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COM

几个关键参数我解释一下。rdns = false必须加,否则 Java 进程在认证时会尝试对客户端 IP 做反向 DNS 解析,解析出的主机名如果跟 principal 里的主机名对不上,认证直接失败。udp_preference_limit = 1的意思是 KRB5 尽量走 TCP,UDP 容易遇到大票据被截断的问题,尤其是票据里带的 PAC 信息多的时候。forwardable = true允许票据被转发,HiveServer2 做代理认证时要用到。

2.2 KDC 数据库初始化与启动

接着配置/var/lib/krb5kdc/kdc.conf,这是 KDC 服务端自己的配置:

[kdcdefaults] kdc_ports = 88 kdc_tcp_ports = 88 [realms] EXAMPLE.COM = { database_name = /var/lib/krb5kdc/principal admin_keytab = /var/lib/krb5kdc/kadm5.keytab acl_file = /var/lib/krb5kdc/kadm5.acl key_stash_file = /var/lib/krb5kdc/.k5.EXAMPLE.COM max_life = 24h 0m 0s max_renewable_life = 7d 0h 0m 0s supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal }

初始化数据库并启动服务:

kdb5_util create -s -r EXAMPLE.COM systemctl start krb5kdc systemctl start kadmin

这里-s参数会在当前目录生成 stash 文件,stash 文件里保存了 KDC 的 master key,没有它 KDC 启动后无法自动打开数据库。另外注意防火墙要放行 88 端口(Kerberos 认证)和 749 端口(kadmin 管理),否则集群其他节点连不上。

2.3 创建主体与导出 keytab

启动之后,我用kadmin.local在本机创建所有主体。kadmin.local是本地管理命令,不需要走网络认证,适合初始化阶段使用。创建命令可以批量执行,我先写一个脚本循环创建并导出 keytab:

for host in bigdata101 bigdata102 bigdata103; do kadmin.local -q "addprinc -randkey zookeeper/$host@EXAMPLE.COM" kadmin.local -q "addprinc -randkey hdfs/$host@EXAMPLE.COM" kadmin.local -q "addprinc -randkey HTTP/$host@EXAMPLE.COM" kadmin.local -q "addprinc -randkey yarn/$host@EXAMPLE.COM" done kadmin.local -q "addprinc -randkey hive/bigdata101@EXAMPLE.COM" kadmin.local -q "addprinc -randkey spark/bigdata101@EXAMPLE.COM" kadmin.local -q "addprinc -randkey presto-server/bigdata101@EXAMPLE.COM"

-randkey是让 KDC 随机生成密钥,而不是交互式输入密码,这样导出的 keytab 才能用于服务进程的免密登录。之后分别在各节点导出 keytab:

# 在 bigdata101 上执行 kadmin.local -q "ktadd -k /etc/security/keytab/zk.service.keytab zookeeper/bigdata101@EXAMPLE.COM" kadmin.local -q "ktadd -k /etc/security/keytab/hdfs.service.keytab hdfs/bigdata101@EXAMPLE.COM HTTP/bigdata101@EXAMPLE.COM" kadmin.local -q "ktadd -k /etc/security/keytab/yarn.service.keytab yarn/bigdata101@EXAMPLE.COM" kadmin.local -q "ktadd -k /etc/security/keytab/hive.service.keytab hive/bigdata101@EXAMPLE.COM" kadmin.local -q "ktadd -k /etc/security/keytab/spark.service.keytab spark/bigdata101@EXAMPLE.COM" kadmin.local -q "ktadd -k /etc/security/keytab/presto.service.keytab presto-server/bigdata101@EXAMPLE.COM"

提示:keytab 导出的节点必须与 principal 里的主机名对应,否则服务启动时会报Server not found in Kerberos database。每台 DataNode 上要导出hdfs/本机名@EXAMPLE.COM和HTTP/本机名@EXAMPLE.COM。

导出之后立刻检查一下:

klist -ket /etc/security/keytab/hdfs.service.keytab

这条命令会列出 keytab 里的 principal、时间戳和加密类型,如果导出的主体不对或者加密类型为空,基本就是 kdc.conf 里的 supported_enctypes 与客户端 JDK 不匹配,后面细说。

3. 五大组件逐个接入 Kerberos

KDC 是地基,接下来就是一层一层往上盖楼。每一层都遵循一个固定套路:准备 keytab → 修改配置文件 → 重启服务 → 用命令验证。我个人强烈建议每配完一个组件就立即验证,不要想着等全部配完再统一验证。

3.1 ZooKeeper 开启 SASL 认证

ZooKeeper 的认证机制走的是 JAAS,需要单独准备一个 jaas.conf 文件。我在每个 ZK 节点的 conf 目录下新建zk_server_jaas.conf:

Server { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/etc/security/keytab/zk.service.keytab" storeKey=true useTicketCache=false principal="zookeeper/bigdata101@EXAMPLE.COM"; };

注意principal要写带主机的完整格式,不能写zookeeper/_HOST@EXAMPLE.COM,因为 JAAS 不会自动替换_HOST,只有 Hadoop 的 UserGroupInformation 层才会做这个替换。ZooKeeper 这边必须写真实主机名。

在zoo.cfg中追加:

authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider requireClientAuthScheme=sasl jaasLoginRenew=3600000

最后一项jaasLoginRenew=3600000表示每小时自动续期一次 keytab 登录,这对长时间运行的 ZooKeeper 服务是必须的,否则运行一天后票据过期,整个服务就会变成“假活”状态。启动时用环境变量把 JAAS 配置指过去:

export ZK_SERVER_JVMFLAGS="-Djava.security.auth.login.config=$ZK_HOME/conf/zk_server_jaas.conf" zkServer.sh start

验证方法也很简单,客户端连接一次:

zkCli.sh -server bigdata101:2181

如果 ZooKeeper 日志里出现Client successfully logged in,并且 zkCli 能正常执行get /,说明 SASL 认证已经生效。假如没有任何日志输出又能连上,多半是requireClientAuthScheme=sasl没加上,客户端走的是无认证通道。

3.2 Hadoop HDFS 与 YARN 的 Kerberos 化

Hadoop 是所有组件里配置项最多的,也是最容易出问题的。修改 core-site.xml:

<property> <name>hadoop.security.authentication</name> <value>kerberos</value> </property> <property> <name>hadoop.security.authorization</name> <value>true</value> </property>

注意authorization这一项,它启用的是 Hadoop 自己的服务 ACL,比如哪些用户能访问某些服务端口。如果不开它,Kerberos 只能解决“你是谁”的问题,解决不了“你能干什么”的问题。生产环境建议打开,但第一次调试时可以先把 authorization 关掉,减少变量。

然后是 hdfs-site.xml,NameNode 和 DataNode 的配置都要写。Hadoop 支持_HOST宏,启动时会自动替换为本机 hostname,这就省去了每台机器改配置的麻烦:

<property> <name>dfs.namenode.kerberos.principal</name> <value>hdfs/_HOST@EXAMPLE.COM</value> </property> <property> <name>dfs.namenode.keytab.file</name> <value>/etc/security/keytab/hdfs.service.keytab</value> </property> <property> <name>dfs.datanode.kerberos.principal</name> <value>hdfs/_HOST@EXAMPLE.COM</value> </property> <property> <name>dfs.datanode.keytab.file</name> <value>/etc/security/keytab/hdfs.service.keytab</value> </property> <property> <name>dfs.web.authentication.kerberos.principal</name> <value>HTTP/_HOST@EXAMPLE.COM</value> </property> <property> <name>dfs.web.authentication.kerberos.keytab</name> <value>/etc/security/keytab/http.service.keytab</value> </property>

如果你只配了 RPC 认证,没有配 web 认证,会发现 HDFS Web UI 能打开但任何文件操作都提示匿名用户没权限。实际生产里这个 Web SPNEGO 经常让运维头疼,因为它要求浏览器客户端也处于 Kerberos 域里,否则打开网页会一直弹登录框。后面第 5 节我再细说。

HDFS 配完,YARN 也要跟着配,否则 ResourceManager 和 NodeManager 还是匿名状态,Spark 提交任务时会因为跨服务认证失败而崩掉:

<property> <name>yarn.resourcemanager.principal</name> <value>yarn/_HOST@EXAMPLE.COM</value> </property> <property> <name>yarn.resourcemanager.keytab</name> <value>/etc/security/keytab/yarn.service.keytab</value> </property> <property> <name>yarn.nodemanager.principal</name> <value>yarn/_HOST@EXAMPLE.COM</value> </property> <property> <name>yarn.nodemanager.keytab</name> <value>/etc/security/keytab/yarn.service.keytab</value> </property>

注意:开启 Hadoop 的 Kerberos 后,HDFS 会自动要求开启 block access token,就是dfs.block.access.token.enable=true,不用手动设。但如果你的集群是从无认证模式平滑切换,建议先格式化之前的临时数据目录,或者至少清理 NameNode 的 current 目录,否则容易碰到 token 校验的兼容问题。

验证 HDFS 是否认证成功,标准做法是:

sudo -u hdfs kinit -kt /etc/security/keytab/hdfs.service.keytab hdfs/bigdata101@EXAMPLE.COM sudo -u hdfs hdfs dfs -ls /

如果这条命令能正常列出目录,而klist显示为空或 keytab 未登录时会报JAASAuthenticationException,那就说明链路有问题。常见原因一个是/etc/security/keytab/hdfs.service.keytab的权限问题,NameNode 对 keytab 文件的权限非常敏感,要求属主正确且chmod 400,组和其他用户如果有读权限会直接拒绝启动。另一个是rdns=false没配置,导致反向 DNS 解析出错。

3.3 Hive Metastore 与 HiveServer2 双端认证

Hive 的认证分为两层:一层是 Metastore 与 HDFS、与其他服务之间的 RPC 认证,另一层是 HiveServer2 与客户端(beeline/JDBC)之间的认证。很多团队只配了 HiveServer2,以为 beeline 能登录就完事了,结果 Presto 连 Metastore 时一直报 SASL 错误,就是因为 Metastore 侧没开。

hive-site.xml 里这样配置:

<property> <name>hive.server2.authentication</name> <value>KERBEROS</value> </property> <property> <name>hive.server2.authentication.kerberos.principal</name> <value>hive/_HOST@EXAMPLE.COM</value> </property> <property> <name>hive.server2.authentication.kerberos.keytab</name> <value>/etc/security/keytab/hive.service.keytab</value> </property> <property> <name>hive.metastore.sasl.enabled</name> <value>true</value> </property> <property> <name>hive.metastore.kerberos.principal</name> <value>hive/_HOST@EXAMPLE.COM</value> </property> <property> <name>hive.metastore.kerberos.keytab.file</name> <value>/etc/security/keytab/hive.service.keytab</value> </property>

还有个隐藏参数hive.server2.enable.doAs,默认是 true,表示 HiveServer2 会模拟客户端身份去访问 HDFS,即 beeline 里登录的用户名决定最终文件操作权限。这个机制对权限管控很重要,但如果你想让所有客户端统一走 hive 用户(比如测试环境图省事),可以把 doAs 改为 false。生产环境按最小权限原则建议保持 true。

启动顺序也是坑:必须先启动 Metastore,等 Metastore 完全就绪再启动 HiveServer2。HiveServer2 启动时要连接 Metastore,如果 Metastore 还没起来,它会显示启动成功但后面所有查询都会挂在元数据连接上。验证方式用 beeline:

kinit -kt /etc/security/keytab/hive.service.keytab hive/bigdata101@EXAMPLE.COM beeline -u "jdbc:hive2://bigdata101:10000/default;principal=hive/_HOST@EXAMPLE.COM"

注意 JDBC URL 里的principal必须与 HiveServer2 配置的 principal 完全一致,大小写都不能错。如果kinit成功但 beeline 报GSSException: No valid credentials provided,优先检查 HiveServer2 的 keytab 路径和权限,再看看启动日志里有没有说明“加载 keytab 失败”。

3.4 Spark on YARN 的认证接入

Spark 相比前面几个组件简单不少,原因在于它自己不常驻服务进进程,而是作为客户端向 YARN 提交任务。任务被 YARN 拉起来后,Spark Executor 需要访问 HDFS,这个凭证链条是:提交用户的 Kerberos token 传给 ResourceManager,RM 再为 Spark ApplicationMaster 创建 delegation token 传递给 Executor。

我在 spark-defaults.conf 里加三项基础配置:

spark.yarn.principal=hive/bigdata101@EXAMPLE.COM spark.yarn.keytab=/etc/security/keytab/hive.service.keytab

如果你用 spark-submit 提交任务,也可以用命令行参数:

spark-submit --master yarn \ --deploy-mode cluster \ --principal hive/bigdata101@EXAMPLE.COM \ --keytab /etc/security/keytab/hive.service.keytab \ --class com.example.WordCount \ app.jar

执行这个操作前要确保本机已经 kinit 过,或者提交时自动从 keytab 登录。这里有个安全细节:spark-submit 带上--keytab时,Spark 会把 keytab 上传到 HDFS 临时目录,任务执行完再清理。这个机制虽然方便,但如果集群有严格的机密性要求,建议改成调度平台上先 kinit 再提交的方式,避免 keytab 在网络和 HDFS 上留下副本。

Spark HistoryServer 是唯一需要长期运行并持有主体身份的 Spark 服务,配置如下:

spark.history.kerberos.enabled=true spark.history.kerberos.principal=spark/bigdata101@EXAMPLE.COM spark.history.kerberos.keytab=/etc/security/keytab/spark.service.keytab spark.history.ui.port=18080

如果 Spark 任务要读写 Hive 表,本质上是 Spark 作为客户端用 HDFS delegation token 去访问数据文件,不需要通过 HiveServer2,所以 hive-site.xml 只需要让 Spark 节点能拿到 HDFS 的凭证即可,不需要额外配置 Spark 连接 Hive 的 Kerberos 参数。

3.5 Presto Server 认证与 Hive Connector 双链路

Presto 是接入链路的最后一环,它同时涉及两个方向的认证:客户端要验证 Presto 服务端,Presto 服务端要去访问 Hive Metastore 和 HDFS。这两个方向都是必需的,只配一个就会出现“客户端能连上但查询报错”的现象。

先改config.properties:

http-server.authentication.type=KERBEROS http-server.authentication.krb5.principal=presto-server/bigdata101@EXAMPLE.COM http-server.authentication.krb5.keytab=/etc/security/keytab/presto.service.keytab http-server.authentication.krb5.krb5-config=/etc/krb5.conf

然后准备jvm.config,在 JVM 参数里指定 JAAS 和 krb5 配置文件:

-Djava.security.auth.login.config=/etc/presto/jaas.conf -Djava.security.krb5.conf=/etc/krb5.conf -Dsun.security.krb5.rdns=false

/etc/presto/jaas.conf内容如下:

PrestoServer { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/etc/security/keytab/presto.service.keytab" storeKey=true useTicketCache=false principal="presto-server/bigdata101@EXAMPLE.COM"; };

再改 Hive Connector 的catalog/hive.properties,这里是最容易漏的地方。Presto 要连 Hive Metastore 就要以 Kerberos 身份去握手,走 HDFS 也要有身份:

connector.name=hive-hadoop2 hive.metastore.uri=thrift://bigdata101:9083 hive.metastore.authentication.type=KERBEROS hive.metastore.service.principal=hive/_HOST@EXAMPLE.COM hive.metastore.client.principal=presto-server/bigdata101@EXAMPLE.COM hive.metastore.client.keytab=/etc/security/keytab/presto.service.keytab hive.hdfs.authentication.type=KERBEROS hive.hdfs.impersonation.enabled=true hive.hdfs.presto.principal=presto-server/bigdata101@EXAMPLE.COM hive.hdfs.presto.keytab=/etc/security/keytab/presto.service.keytab

Presto 这一块的版本差异很大。老版本 Presto(0.x 系列)用的是com.facebook.presto.hive.authentication.HadoopAuthentication,参数名是hive.hdfs.authentication.type搭配hive.hdfs.presto.principal。后来 Trino 改了部分参数,如果你用的是 Trino 版本,要以官方文档为准。我上面的配置对 Presto 330 及后续版本、Trino 350+ 都能用。

Presto 的 HDFS 访问还有一个关键设置:hive.hdfs.impersonation.enabled=true表示 Presto 模拟客户端用户的身份去访问 HDFS。这个功能要生效,Preto 服务所在的 host 必须在 HDFS 的代理用户白名单里。core-site.xml 需要添加:

<property> <name>hadoop.proxyuser.presto-server.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.presto-server.groups</name> <value>*</value> </property>

很多人在这一步报错Presto is not allowed to impersonate hdfs,就是因为代理用户没配置。同样地,HiveServer2 和 Spark 如果也以代理用户工作,需要对应的hadoop.proxyuser.hive.hosts和hadoop.proxyuser.spark.hosts配置,这个在后面第 4 节会专门强调。

4. 踩坑实录:从时间偏差到 JCE 加密策略

Kerberos 的报错信息非常不友好,往往一个底层加密异常传到上层就变成了“无法连接到服务”。我把自己实际踩过的坑按出现频率整理出来,你遇到问题时可以逐条对照。

4.1 集群时间同步是第一个隐形杀手

Kerberos 要求客户端和服务端的时钟偏差在 5 分钟内,默认值max_clock_skew=300。这个 5 分钟其实很宽松,但我会告诉你:虚拟机集群非常容易超过这个值,尤其是宿主机休眠恢复后,虚拟机的时钟可能偏差到小时级别。

排查方法非常简单,KDC 节点上执行date,客户端节点上执行date,对比一下。如果偏差超过 5 分钟,立刻配置 NTP 同步。生产环境建议全集群统一用 chrony 指向内网 NTP 服务器,而不要各节点各自向公网同步,否则外网不稳定时节点间照样漂移。配置完 chrony 后用chronyc sources -v确认同步状态。

4.2 hostname 与 DNS 反向解析问题

这是第二个高频坑。Kerberos principal 里的主机名必须能被解析成 IP,IP 反向解析回去的主机名也必须一致。很多集群的/etc/hosts里只写了短主机名:

192.168.1.101 bigdata101

而 principal 用的却是bigdata101.example.com,KDC 对比时先正向解析再反向解析,解析出来是bigdata101或者完全报Server not found in Kerberos database。我建议/etc/hosts写成 FQDN 加短名的双重映射:

192.168.1.101 bigdata101.example.com bigdata101

同时保证/etc/sysconfig/network里的 HOSTNAME 也是 FQDN。Java 进程里再加-Dsun.security.krb5.rdns=false,这条命令能禁止 JVM 对 IP 做反向域名解析,HiveServer2、Presto、YARN 的启动脚本里都值得加。

4.3 keytab 文件权限的硬性校验

Apache Hadoop 对 keytab 文件有硬性权限检查,要求文件只对运行用户可读。比如 NameNode 以 hdfs 用户运行,那么hdfs.service.keytab必须属于 hdfs 用户,权限400或600。如果你复制 keytab 后没改属主,启动日志里会出现类似:

javax.security.auth.login.LoginException: Unable to obtain Princpal Name for authentication

或者直接报keytab file ... is not owned by the operating system user。处理命令:

chown hdfs:hadoop /etc/security/keytab/hdfs.service.keytab chmod 400 /etc/security/keytab/hdfs.service.keytab

每个服务有自己的运行用户,比如 ZooKeeper 常用 zookeeper 用户,Hive 常用 hive 用户,Presto 常用 presto-server 用户,逐一对应设置属主,不要偷懒统一成一个用户,否则服务隔离名存实亡。

4.4 AES256 加密与 JCE 无限强度策略

如果你的 KDC 里配置了aes256-cts:normal,而运行组件的 JDK 版本低于 8u161,默认不支持 AES-256,因为美国出口管制时期 Java 默认只能加解密 128 位密钥。低版本 JDK 需要手动替换$JAVA_HOME/jre/lib/security目录下的local_policy.jar和US_export_policy.jar,换成 Java Cryptography Extension 无限强度版本。报错信息一般类似unsupported key size或者Illegal key size。

JDK 8u161 之后默认就支持了,所以我建议直接把集群的 JDK 升到这个版本以上,别再费劲换 policy 文件。如果你不能升 JDK,退一步把 kdc.conf 的 supported_enctypes 去掉 aes256,只留 aes128,也能解决兼容问题,只是加密强度略低。

4.5 代理用户配置导致的“连锁反应”

前面提到的hadoop.proxyuser配置是整个链路里最容易被忽略的。HiveServer2 开启 doAs 后,它以 hive 用户身份连到 HDFS 时,HDFS 看到的是客户端用户,但鉴权时要求 hive 用户具备“代理别人”的权限。Spark 在 YARN 上也是一样,Presto 有自己的一套。

所以我把生产环境需要加的代理用户配置统一贴出来:

<property> <name>hadoop.proxyuser.hive.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.hive.groups</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.spark.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.spark.groups</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.presto-server.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.presto-server.groups</name> <value>*</value> </property>

hosts和groups里的*表示允许代理所有主机和所有用户组,生产环境如果你追求更细粒度,可以只允许代理hdfs用户组或具体主机列表。我当时图省事全写*,后来安全审计被点名了,你还是按实际需求收窄一点。

5. 安全模式下的日常运维与快速验证

整个集群切换成安全模式后,日常运维习惯也要变。以前hdfs dfs -ls /直接敲,现在必须先有凭证。我把自己常用的验证命令和启动顺序整理出来,可以保存成一份团队内部的运维手册。

5.1 重启顺序与逐层验证

安全模式下组件重启顺序非常重要,顺序反了就会出现“找不到服务”的假报错。我的固定顺序是:

  1. ZooKeeper 全部节点
  2. HDFS JournalNode(如果做了 HA)
  3. HDFS NameNode
  4. HDFS DataNode
  5. YARN ResourceManager
  6. YARN NodeManager
  7. Hive Metastore
  8. HiveServer2
  9. Spark HistoryServer
  10. Presto Server

每一步验证都对应一个命令:

验证项命令预期结果
KDC 健康systemctl status krb5kdcactive (running)
keytab 完整性klist -ket /etc/security/keytab/hive.service.keytab列出 principal 和加密类型
HDFSsudo -u hdfs kinit -kt hdfs.service.keytab hdfs/_HOST@EXAMPLE.COM && hdfs dfs -ls /正常列出目录
Hivebeeline -u "jdbc:hive2://bigdata101:10000/default;principal=hive/_HOST@EXAMPLE.COM"进入 beeline 并执行 show tables
Sparkspark-submit --master yarn --deploy-mode client --principal ... --keytab ...跑一个 sparkPiYARN UI 出现 SUCCEEDED
Presto./presto-cli --server https://bigdata101:8443 --krb5-principal presto-server/bigdata101@EXAMPLE.COM --krb5-keytab presto.service.keytab --krb5-remote-service-name presto-server能执行show catalogs

5.2 常见报错速查表

写这个表的时候我在想,这些报错我几乎每一条都在生产环境见过,其实很多问题根源就集中在几个点:时间、hostname、keytab 权限、encryption type。表格如下:

报错信息根因处理方式
Clock skew too great客户端与服务端时间偏差超过 5 分钟统一 chrony/NTP 同步
Server not found in Kerberos databaseprincipal 拼写错误或该主体未创建kadmin.local listprincipals检查
Integrity check on decrypted field failedkeytab 与 principal 的密钥不匹配用ktadd重新导出 keytab
GSSException: No valid credentials provided当前凭证过期或 keytab 无效kinit -R续期或重新登录
Unable to obtain Princpal Name for authenticationJAAS 里 principal 格式错误或 keytab 路径不存在修正 jaas.conf 和 keytab 路径
Please install the JCE Unlimited Strength Jurisdiction Policy filesJDK 不支持 AES-256升级 JDK 8u161+ 或改 aes128
Presto is not allowed to impersonate hdfs代理用户白名单未配置core-site.xml 加 proxyuser 配置
javax.security.auth.login.LoginException: java.io.FileNotFoundExceptionkeytab 路径不存在或权限不足检查属主与 chmod 400

5.3 回滚方案一定要提前想好

Kerberos 改造如果失败或者导致业务中断,几分钟内回滚比修复 bug 更关键。我自己的回滚策略是:

  • 如果只是某个服务起不来,先看日志确认是配置错误还是底层 KDC 问题。配置错误就改完局部重启,不需要回滚。
  • 如果整个集群切换到 Kerberos 后大面积故障,优先把 core-site.xml 的hadoop.security.authentication改回simple,去掉 hdfs-site.xml 里的 keytab 相关项,重启 HDFS 和 YARN。HDFS 数据不会因为回滚丢失,NameNode 的 edits log 也不受影响。
  • ZooKeeper 的回滚更简单,去掉 zoo.cfg 里的 SASLAuthenticationProvider 和 jaas 相关配置,重启即可。
  • 回滚后进程的 ticket 缓存文件要清理,/tmp/krb5cc_*全部删掉,不然残留票据可能导致某些客户端还走旧的认证逻辑。

记住一个原则:回滚要按依赖顺序来,先 Presto 后 Hive 后 Spark 后 HDFS,与启动顺序相反。因为下游组件如果还持有 Kerberos 票据,而上游已经降级成 simple 认证,就会立刻报无法识别的认证包头。

6. 写在最后:给新手的几条实操建议

第一,不要一次性把所有组件都改成 Kerberos。先配 KDC,再配 ZooKeeper 验证通过,再配 HDFS 验证通过,这样一层层推。每层验证通过的时间可能只有几分钟,但能帮你把故障范围缩小到一个组件内,不至于五个组件同时出问题时手忙脚乱。第二,所有 principal 和 keytab 路径一定要在文档里登记清楚,包括哪个节点用了哪个 keytab、对应哪个服务。这个工作看似琐碎,半年后当你需要旋转密钥时,没有这份登记表会非常痛苦。第三,日常任务调度的认证方式尽量统一。比如都在调度平台上通过 kinit 获取凭证后再跑 Spark,避免每个任务都传 keytab 到 HDFS 上的隐患。第四,如果条件允许,把 KDC 做成双机或者接入现有 AD 域,这样即使单台 KDC 挂了,集群内所有组件的票据续期都能继续工作。最后再说一个我自己的体会:Kerberos 属于“配好了没啥存在感,配不好天天刷工单”的组件。耐心按链路逐层验证,比啥都重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询