
换了新环境第一个冒出来的问题是一套集群里每个组件都有自己的账号体系数据安全怎么保证别急着上各种围栏插件先把Kerberos这个地基打好。这篇文章讲的就是我最近在一套真实集群上手动把Zookeeper、Hadoop、Hive、Spark、Presto全部接入Kerberos认证的完整过程包含每一处配置改动、启动顺序和踩坑记录适合正在给公司集群做安全加固、或者准备从零搭建安全大数据平台的运维和开发同学参考。为什么这个事值得单独写一篇网上搜“Kerberos配置”出来的博客要么只讲Hadoop一个组件要么就给你丢一个商业发行版的界面截图。真正把这五个组件串起来、讲清楚认证链路、并且把常见坑都排一遍的内容非常少。所以这篇不写原理课本直接按我实际操作的顺序走每一步都给你看真实配置和原因。1. 认清Kerberos在大数据平台里的真实位置1.1 它解决的到底是什么问题大数据平台的组件本质上是分布式进程各自跑在不同机器上进程之间要通信靠的是RPC、HTTP、TCP这类协议。问题来了你怎么确定一个请求真的是来自一个合法的服务端或客户端而不是某个伪装的进程在没有Kerberos的集群里组件之间基本是“裸奔”的——只要网络能通、端口能访问谁都能提交作业、读写HDFS。以前我在测试环境里遇到过一件很尴尬的事一台没设防火墙的机器几个不相关的账号通过HTTP端口就能读到NameNode的状态虽然没造成什么损失但想想就后背发凉。Kerberos做的事说的是“身份认证”四个字本质是在每两个进程建立连接之前先通过一个双方都信任的第三方KDC验证彼此的身份。认证通过后这两个进程之间的通信就建立在一个加密通道上后续的数据包都带上了身份凭证。这样谁在什么时候访问了什么资源全部有据可查也就能配合HDFS的ACL做细粒度权限控制了。打个生活化的比方Kerberos就像小区的物业中心每个住户服务端和客户端进程都在物业备案注册principal进单元门之前必须先到物业窗口刷脸领一张临时通行卡票据每进一栋楼都要向楼管出示这张卡验证身份。没有这张卡你连单元门都进不去。1.2 理解五个组件在认证链路中的角色要一次性把这五个组件配好必须把它们的角色分清否则配置的时候会乱。Zookeeper它是分布式协调服务Hadoop的NameNode高可用、HBase的RegionServer协调、Kafka的broker选举都依赖它。启用Kerberos后Zookeeper要求所有连接到它的客户端都要通过SASL认证这等于给整个集群的“神经中枢”上了一道锁。HadoopHDFS YARN这是集群的存储和调度核心。NameNode、DataNode、ResourceManager、NodeManager这些守护进程全部要以Kerberos身份运行彼此访问时互相验证。客户端提交作业、读写文件也需要先通过Kerberos拿到身份凭证。HiveHiveServer2对外提供SQL服务Metastore存储表结构元数据。启用Kerberos后用户连接HiveServer2、HiveServer2访问Metastore、Metastore访问HDFS中间每一跳都需要身份认证。Spark它作为一个计算框架本身不依赖Kerberos但它的Driver和Executor要读写HDFS、访问Hive Metastore就必须带着Kerberos票据去访问这些服务。通常用keytab加principal的方式给Spark作业一个身份。PrestoPresto以及现在的Trino是分布式SQL查询引擎它的角色比较特殊——它自己一般不做基于Kerberos的彼此认证当然可以对客户端开启LDAP或Kerberos认证但它作为客户端访问启用了Kerberos的Hive Metastore和HDFS时必须配置Kerberos相关的连接器参数。我画了一条认证链路方便你理解配置时信息流的走向客户端/查询引擎Spark/Presto → Zookeeper要认证 ↓ HiveServer2要认证 → Metastore要认证 ↓ NameNode/DataNode要认证理解了这条链路后面配参数的时候就不会东一榔头西一棒槌每个组件配什么本质上都是在处理这条链路中某一环的身份信息。1.3 部署之前必须想清楚的几件事我先把话放前面Kerberos一旦开启就等于把集群入口的管理权收归到一个中心配置失误的代价很高。开始之前有几件事必须确认。第一时钟同步是命根子。Kerberos协议里对时间偏移极其敏感客户端和服务端与KDC的时间差超过默认的5分钟认证直接失败。部署前确保所有机器都配置了NTP同步并且已经在正常同步状态。第二规划好域名和realm。Kerberos的realm通常写成大写的域名格式比如EXAMPLE.COM。principal的格式是service/hostnameREALM这个hostname必须是客户端的实际主机名不能随便写。最好提前把每台机器的主机名、每类服务的principal命名规范列成表。第三准备好keytab的分发和权限方案。keytab文件本质是存储密钥的加密文件谁拿到这个文件谁就能冒充对应的身份。每台机器上的keytab必须设置成只能被运行该服务的用户读取权限一般是400或600并且分发过程要避开不安全渠道。第四确认组件的版本。不同版本对Kerberos的支持程度和配置项名称有差异。我这次用的是Hadoop 3.x、Hive 3.x、Spark 3.x、Presto 0.2xx如果你用的是老版本个别参数名可能需要调整比如老版本Hadoop的core-site.xml里还需要配hadoop.security.credential.provider.bin-path之类的新版本基本不需要了。2. 从KDC开始创建身份票据和keytab文件2.1 装好KDC并完成基础初始化Kerberos需要一个身份中心就是KDCKey Distribution Center。我在一台独立的CentOS 7机器上装了krb5-server其他机器只需要装krb5-client。装完之后做的第一件事是编辑/etc/krb5.conf核心配置是这样的[libdefaults] default_realm EXAMPLE.COM dns_lookup_realm false dns_lookup_kdc false ticket_lifetime 24h renew_lifetime 7d forwardable true udp_preference_limit 1 [realms] EXAMPLE.COM { kdc kdc.example.com admin_server kdc.example.com } [domain_realm] .example.com EXAMPLE.COM example.com EXAMPLE.COM这里重点说说几个容易踩坑的地方。udp_preference_limit 1是我强烈建议加上的因为UDP在复杂网络环境下非常容易丢包Kerberos的认证请求莫名其妙失败改成限制UDP、强制走TCP后网络原因导致的认证超时明显少了很多。ticket_lifetime设成24小时是常规做法但要注意配合Hadoop的renew相关配置一起看否则作业跑长了票据过期后面连接Hive和HDFS会开始报错。接着用kdb5_util create -s创建数据库然后通过kadmin.local来管理principal。这一步我建议只在自己机器上用kadmin.local操作不要急着开放远程管理接口等所有principal建好后再决定要不要对外提供kadmin服务。2.2 用一条命令理清所有需要的principal很多文章会列十来个kadmin.local的addprinc命令看得人头疼。我把需要的principal整理成了下面这张表按服务和主机维度分好类实际操作时一目了然服务principal模式keytab文件建议位置Zookeeperzookeeper/{hostname}EXAMPLE.COM/etc/security/keytabs/zk.service.keytabNameNodenn/{hostname}EXAMPLE.COM/etc/security/keytabs/nn.service.keytabDataNodedn/{hostname}EXAMPLE.COM/etc/security/keytabs/dn.service.keytabResourceManagerrm/{hostname}EXAMPLE.COM/etc/security/keytabs/rm.service.keytabNodeManagernm/{hostname}EXAMPLE.COM/etc/security/keytabs/nm.service.keytabHiveServer2hive/{hostname}EXAMPLE.COM/etc/security/keytabs/hive.service.keytabHive Metastorehive/{hostname}EXAMPLE.COM同上HTTPSPNEGOHTTP/{hostname}EXAMPLE.COM/etc/security/keytabs/spnego.service.keytabSpark查询用户客户端spark/{hostname}EXAMPLE.COM/etc/security/keytabs/spark.service.keytabPresto查询用户客户端presto/{hostname}EXAMPLE.COM/etc/security/keytabs/presto.service.keytab注意HiveServer2和Hive Metastore可以共用同一个principal和keytab因为它们的服务模式都是hive/{hostname}只要两台机器上放同一份keytab就行。但这不意味着你可以把keytab随意拷贝每台机器上的keytab文件权限必须严格控制。建完principal之后用kadmin.local一条一条执行下面的命令以Zookeeper为例kadmin.local -q addprinc -randkey zookeeper/zk1.example.comEXAMPLE.COM kadmin.local -q ktadd -k /etc/security/keytabs/zk.service.keytab zookeeper/zk1.example.comEXAMPLE.COM建议每台机器上的keytab都直接生成在该机器的本地路径里不要生成完再scp到处拷省得在传输过程中泄露。通过网络传keytab这种操作除非你确认网络环境绝对安全否则我劝你还是别偷懒。2.3 keytab文件的权限、备份和验证keytab权限非常关键。我见过太多因为keytab权限过宽导致的认证失败事故不是服务起不来就是客户端连不上日志里还看不到明确原因。生成之后立刻执行chown zookeeper:hadoop /etc/security/keytabs/zk.service.keytab chmod 400 /etc/security/keytabs/zk.service.keytab这里有个经验如果一台机器上同时跑多个Hadoop相关服务比如同时跑NameNode和ResourceManager这在中小集群很常见可以把它们各自的keytab归属到同一个组再把进程用户加进这个组。但每个keytab仍需用独立的文件放避免一个文件被多个进程加载时权限冲突。验证keytab有没有问题用下面的命令先kinit再klist查看票据内容kinit -kt /etc/security/keytabs/zk.service.keytab zookeeper/zk1.example.comEXAMPLE.COM klist如果kinit报错或klist里没有票据先检查主机的hostname是否跟principal里的hostname完全一致再看realm大小写是否对得上。Kerberos对realm大小写是敏感的EXAMPLE.COM和example.com是两个完全不同的realm这坑我踩过不止一次。3. 让Zookeeper具备Kerberos身份认证能力3.1 给Zookeeper进程配置登录认证模块Zookeeper用自己的Jaas配置来加载Kerberos信息。在每台Zookeeper节点上新建一个/etc/zookeeper/conf/jaas.conf内容如下Server { com.sun.security.auth.module.Krb5LoginModule required useKeyTabtrue keyTab/etc/security/keytabs/zk.service.keytab storeKeytrue useTicketCachefalse principalzookeeper/zk1.example.comEXAMPLE.COM; }; Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTabtrue keyTab/etc/security/keytabs/zk.service.keytab storeKeytrue useTicketCachefalse principalzookeeper/zk1.example.comEXAMPLE.COM; };注意Server块和Client块都必须写因为Zookeeper节点既是SASL服务端也是连接其他Zookeeper节点的客户端。如果只配了Server不配Client集群内多个Zookeeper节点之间互相通信时仍然会认证失败表现为leader选举一直选不出来或者follower频繁断开重连。然后在启动Zookeeper的Java进程时把Jaas配置文件的路径传给JVM。我习惯在/etc/zookeeper/conf/zoo.cfg里增加下面两个JVM系统参数或者直接在启动脚本里export JAVA_OPTS写法如下export JVMFLAGS-Djava.security.auth.login.config/etc/zookeeper/conf/jaas.confzoo.cfg里还需要同时开启SASL认证provider并且根据你的zookeeper版本设置是否去除hostname和realm信息authProvider.1org.apache.zookeeper.server.auth.SASLAuthenticationProvider kerberos.removeHostFromPrincipalfalse kerberos.removeRealmFromPrincipalfalse最后这两个参数很多发行版默认是true或者不写结果就是客户端的principal被改得面目全非认证永远对不上。Hadoop生态里访问Zookeeper的客户端principal通常带host和realm所以这里保持false让认证逻辑直接用原始的principal进行匹配。3.2 测试Zookeeper客户端连通性前必须做的检查启动Zookeeper后先别急着让Hadoop连上来先在Zookeeper本机用sql连接方式或者zkCli.sh测试。用zkCli.sh的时候需要在CLASSPATH里带上Jaas配置否则就算Zookeeper服务端已经开启SASL客户端这边没有登录上下文照样连不上。一个常用的做法是给zkCli.sh创建一个单独的Jaas客户端配置文件内容比服务端的简单很多Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTabtrue keyTab/etc/security/keytabs/zk.service.keytab principalzookeeper/zk1.example.comEXAMPLE.COM; };测试命令如下zkCli.sh -server zk1.example.com:2181注意测试用的principal和服务端用的principal必须一致因为Zookeeper的SASL认证要求客户端身份已经在Kerberos库中注册。如果你发现连不上并且Zookeeper日志里有“SASL authentication failed”这样的字眼优先检查Jaas文件路径是否写对、keytab权限是否正常然后是principal的hostname是否跟实际主机名的fqdn一致。另外一个容易忽略的点是如果集群开了防火墙需要放行Zookeeper的2181端口以及Kerberos的88端口。Kerberos认证要是出不去后续所有组件全废。这一步看着基础但实际操作中被防火墙拦住的情况非常多。4. Hadoop组件全面接入Kerberos4.1 core-site.xml和hdfs-site.xml的核心改动Hadoop的Kerberos化是整个配置链路中最关键的一步因为Hive、Spark、Presto最终都要通过HDFS来读写数据。HDFS上的NameNode、DataNode以及YARN上的ResourceManager、NodeManager都要作为Kerberos服务端来启动。先改core-site.xml开启Kerberos认证和授权property namehadoop.security.authentication/name valuekerberos/value /property property namehadoop.security.authorization/name valuetrue/value /property然后改hdfs-site.xml给NameNode和DataNode分别指定keytab和principalproperty namedfs.namenode.keytab.file/name value/etc/security/keytabs/nn.service.keytab/value /property property namedfs.namenode.kerberos.principal/name valuenn/_HOSTEXAMPLE.COM/value /property property namedfs.namenode.kerberos.internal.spnego.principal/name valueHTTP/_HOSTEXAMPLE.COM/value /property property namedfs.datanode.keytab.file/name value/etc/security/keytabs/dn.service.keytab/value /property property namedfs.datanode.kerberos.principal/name valuedn/_HOSTEXAMPLE.COM/value /property关于_HOST这个通配符Hadoop的启动脚本会在进程启动时自动把_HOST替换成本机的主机名所以你在写配置的时候不需要手动改成具体hostname反而写死hostname会让配置失去迁移性以后换机器还得改配置。这个细节是很多新手没注意到的老手都这样配置。DataNode和NameNode的principal我强调一下DataNode的principal必须写成dn/_HOST不要误写成同一个nn的。一旦写错DataNode在注册时会被NameNode拒绝集群会出现DataNode频繁连接又断开的症状HDFS状态页面显示DataNode数为0或者不断跳动。对于YARN在yarn-site.xml里同样要配置ResourceManager和NodeManager的keytab格式和HDFS类似这里不重复贴代码了。原则就一条每一个以独立Java进程运行的服务都要有自己可用的keytab和principal。4.2 启动前要做好的「互相认证」清单Hadoop的守护进程之间是彼此认证的所以启动顺序和身份准备缺一不可。我习惯的启动顺序是先启动KDC确保Kerberos服务在线——然后启动Zookeeper——再启动NameNode和ResourceManager——等它们都完成kerberos登录后再启动DataNode和NodeManager。DataNode在启动时会主动与NameNode建立安全通道如果NameNode还没起来或者身份不对DataNode会在安全握手阶段失败然后不断重试。这里有个心得启动前建议先手动kinit一遍每个服务principal确认keytab可用再启动服务。不要直接启动服务然后满屏日志去找问题。比如NameNode启动前先执行kinit -kt /etc/security/keytabs/nn.service.keytab nn/namenode-hostEXAMPLE.COM如果这条命令成功再启动NameNode进程。很多服务启动时卡在登录阶段原因就是keytab文件里的principal写错了或者keytab路径权限不对。启动完成后第一时间在HDFS Web UI页面确认是否看到了认证机制。如果页面正常显示并且Datanode均已注册说明HDFS层面的Kerberos已经生效。还可以在集群机器上执行hdfs dfs -ls /注意这时候命令行客户端本身也要有Kerberos票据否则你会看到类似“GSSException: No valid credentials provided”的报错。也就是说你用任何未kinit的账号去访问HDFS都会被拒绝这恰好说明认证已经真正起作用了。4.3 HDFS的超级用户和代理用户配置开启Kerberos之后HDFS的超级用户不再像以前那样靠Linux的uid判断而是通过Kerberos principal来识别。比如你是hdfs用户但你想用其他用户身份去访问HDFS就得配置代理用户规则。core-site.xml里需要增加hadoop.proxyuser的相关配置我这里以允许hive、spark、presto用户冒充hadoop组的用户为例property namehadoop.proxyuser.hive.hosts/name value*/value /property property namehadoop.proxyuser.hive.groups/name value*/value /property property namehadoop.proxyuser.spark.hosts/name value*/value /property property namehadoop.proxyuser.spark.groups/name value*/value /property property namehadoop.proxyuser.presto.hosts/name value*/value /property property namehadoop.proxyuser.presto.groups/name value*/value /property这个配置如果不做后面Hive和Spark作业在提交时大概率会遇到“User: xxx is not allowed to impersonate xxx”的报错。实际生产环境里建议把hosts和groups的星号替换成具体的主机名和用户组安全收紧一些。5. HiveServer2与Metastore的认证设置5.1 Hive端三个关键参数一个都不能少Hive的Kerberos配置集中在hive-site.xml。HiveServer2要对外提供经过Kerberos认证的JDBC/ODBC服务Metastore也要在认证框架下工作。HiveServer2需要配置的三项是认证方式、服务principal、keytab路径property namehive.server2.authentication/name valueKERBEROS/value /property property namehive.server2.authentication.kerberos.principal/name valuehive/_HOSTEXAMPLE.COM/value /property property namehive.server2.authentication.kerberos.keytab/name value/etc/security/keytabs/hive.service.keytab/value /propertyMetastore端的配置我一般这样写property namehive.metastore.sasl.enabled/name valuetrue/value /property property namehive.metastore.kerberos.keytab.file/name value/etc/security/keytabs/hive.service.keytab/value /property property namehive.metastore.kerberos.principal/name valuehive/_HOSTEXAMPLE.COM/value /property有人会把hive.server2.authentication.kerberos.keytab省略不配觉得只要在环境变量里kinit过一次就行。但要注意HiveServer2是以独立服务身份运行的长驻进程它启动时必须自己去keytab文件里拿密钥而不是依赖KDC一段时间内分配的临时票据。临时票据有有效期过期之后HiveServer2就无法再认证了。所以keytab这几个配置项一个都不能少。5.2 beeline客户端如何通过Kerberos连接Hive配置好服务端之后还要验证客户端能否正常连接。beeline是Hive自带的命令行客户端开启Kerberos后需要先kinit或者直接在beeline里指定principal和keytab。推荐先kinit再连因为更接近真实应用的用法kinit -kt /etc/security/keytabs/hive.service.keytab hive/hive-hostEXAMPLE.COM beeline -u jdbc:hive2://hive-host.example.com:10000/default;principalhive/_HOSTEXAMPLE.COM那个principal参数是必须的它告诉beeline我要以怎样的服务身份去连接HiveServer2。如果这里写错了报错信息往往是“Server not found in Kerberos database”排查起来很容易绕弯路。实际连过一遍之后你就知道客户端连接时如果没有票据beeline会直接报认证错误如果有票据但principal里host不对又会进入一个很尴尬的认证失败循环。这种问题要快速定位思路是先确保klist里有票据再确保连接URL里的principal和HiveServer2配置的principal一致有时候问题就这么简单。5.3 Hive执行Job时向YARN提交的身份传递问题Hive提交到YARN上的MapReduce或Tez任务也需要能够以Hive用户身份访问HDFS。这个身份传递主要靠Hadoop的UGIUserGroupInformation机制开启Kerberos后会自动使用当前HiveServer2进程的Kerberos身份。如果你发现Hive能正常执行DDL但在执行需要写文件的DML操作时报权限错误大概率是HiveServer2进程的用户缺少HDFS相关目录的写权限又或者代理用户配置没生效。用hadoop fs -ls看看表目录的属主是不是hive用户不是的话用hdfs dfs -chown -R hive:hadoop /user/hive/warehouse修一下然后再跑DML试试。这个阶段最常见的误区是以为只要HiveServer2能启动数据读写就一定正常。实际上HiveServer2的Kerberos身份只是它的“登录身份”具体到每个SQL作业还要看作业用什么样的身份访问HDFS。6. Spark作业如何获取和携带Kerberos票据6.1 Spark on YARN的认证模式选择Spark毕竟不是常驻的无状态服务它的Driver和Executor是动态创建和销毁的所以配置思路和HiveServer2这种长驻进程不同。Spark做Kerberos认证一般分两种场景提交local模式或YARN模式。YARN模式下Spark作业是以YARN容器形式跑的。每个容器内部要访问HDFS、Hive Metastore、Zookeeper等身份来源可以是提交作业时指定的principal和keytab也可以是YARN分配的委托令牌delegation token。我推荐在生产环境中用委托令牌方式因为长时间跑的流式作业或者Spark Structured Streaming不会因为票据过期而挂掉如果只是跑批作业每次提交时提供keytab也行。spark-submit提交时最直观的方式是加如下参数spark-submit \ --master yarn \ --deploy-mode cluster \ --principal sparkEXAMPLE.COM \ --keytab /etc/security/keytabs/spark.service.keytab \ --conf spark.yarn.principalsparkEXAMPLE.COM \ --conf spark.yarn.keytab/etc/security/keytabs/spark.service.keytab \ --conf spark.yarn.credentials.file/tmp/spark-credentials.bin \ --name spark-kerberos-demo \ path/to/your_application.jar这里有个重点principal必须是spark这个已经注册到KDC的账号不能随便用Hive或其他服务的principal。否则就算Spark作业能启动它访问元数据和HDFS时也会被拒。还有keytab文件在集群的每个节点上都需要能被Spark用户读如果YARN把容器调度到别的节点jar包和keytab都要分发到位。6.2 Spark SQL读写Hive表时的Kerberos参数传递很多时候我们用Spark SQL去读Hive表。Spark SQL在做这件事时要通过Hive Metastore获取表结构、通过HDFS读写文件两层都需要认证。如果你在用spark-sql命令行可以这样启动spark-sql \ --master yarn \ --principal sparkEXAMPLE.COM \ --keytab /etc/security/keytabs/spark.service.keytab \ --conf spark.sql.catalogImplementationhive \ --conf spark.sql.hive.metastore.version3.1.2另外一个实用技巧是把Hive的hive-site.xml放到Spark的conf目录里让Spark启动时自动读取Metastore相关配置否则Spark SQL默认只在本地找Derby元数据根本不会连接远程Hive。spark.sql.catalogImplementationhive这句尤其重要。很多新手配了Kerberos之后Spark SQL还是报错找不到元数据或者table not found结果发现Spark根本连的是内嵌的Derby完全没走远程Metastore。6.3 Executor节点上的keytab文件同步Spark作业跑在YARN上Executor可能被调度到集群内任意节点。如果你用了keytab方式提交YARN在启动Executor时会把keytab临时文件和作业资源一起分发过去具体参数是spark.yarn.keytab所以理论上不需要你手动在所有节点都放一份keytab文件。但有一个例外如果你的Spark任务在Driver里直接new了一个Configuration并通过它访问HDFS这时Driver进程需要自己的Kerberos凭证不能只依赖YARN委托令牌。这种情况要么在Driver代码里先执行UserGroupInformation.loginUserFromKeytab要么就在所有可能跑Driver的节点上提前放好keytab然后代码里指向这个文件的绝对路径。我实际踩过一个很隐蔽的坑代码里写死了keytab路径/opt/security/spark.keytab本地提交没问题但作业被调度到另一台机器上就报文件找不到。后来我把keytab放到每台机器的相同路径并确保目录权限对问题才彻底解决。所以在没有任何自动化分发工具的情况下把所有节点纳入并同步keytab文件是最稳妥的路径。7. Presto如何连接Kerberos化的Hive和HDFS7.1 Presto和Presto本身的关系定位先说明一点PrestoTrino前身作为SQL查询引擎它本身的节点之间有自己的内部通信方式内部通信的认证一般不在Kerberos讨论范围内。我们常说“Presto配置Kerberos”实际上是指Presto的Hive连接器如何去访问启用了Kerberos的Metastore和HDFS。具体到配置层面Presto的Hive连接器配置文件位于etc/catalog/hive.properties你要在里面指定Metastore和HDFS的认证方式。我实际配置时hive.properties核心内容是这样的connector.namehive-hadoop2 hive.metastore.urithrift://metastore-host.example.com:9083 hive.metastore.authentication.typeKERBEROS hive.metastore.service.principalhive/_HOSTEXAMPLE.COM hive.metastore.client.principalprestoEXAMPLE.COM hive.metastore.client.keytab/etc/security/keytabs/presto.service.keytab hive.hdfs.authentication.typeKERBEROS hive.hdfs.impersonation.enabledtrue hive.hdfs.presto.principalprestoEXAMPLE.COM hive.hdfs.presto.keytab/etc/security/keytabs/presto.service.keytabhive.hdfs.impersonation.enabledtrue的意思是Presto访问HDFS时会以提交查询的用户身份去访问而不是Presto服务自己的身份。这样不同用户查询的数据权限是按照他们各自的Kerberos身份来鉴权的更符合数据安全要求。如果把这个参数设为false那么所有查询都会以Presto的principal身份访问HDFS权限边界会显得很混乱。7.2 Presto节点的keytab配置和JVM参数Presto服务需要能访问到它的keytab并且Presto进程的用户一般是presto要有读权限。我通常把presto.service.keytab放在/etc/security/keytabs/目录然后chown成presto用户。除了连接器配置Presto节点本身还需要在启动时能加载Kerberos相关的Java安全配置。通常做法是在每个Presto节点的etc/jvm.config里加上-Djava.security.krb5.conf/etc/krb5.conf -Djava.security.auth.login.config/etc/presto/jaas.confjaas.conf内容指向presto的keytab和Hive的Jaas配置类似只是principal换成presto。如果不加这个配置Presto连接Hive Metastore时会报“Unable to obtain password from user”这类错误因为Java的登录模块根本没被初始化。这里还要注意Metastore URI必须指向实际运行Metastore服务的主机名不能用localhost。因为principal里的host和Metastore URI里的host要能对上Kerberos认证才能通过。我在排障时发现很多人把hive.metastore.uri写成localhost后再怎么配都失败改成真实主机名就好了说到底是认证时hostname匹配不上。7.3 用Presto CLI查数据验证整个认证链路配置完成后用presto-cli连接并执行一个简单查询来验证./presto --server presto-coordinator.example.com:8080 --catalog hive --schema default进入交互界面后执行SHOW TABLES; SELECT count(*) FROM some_table;如果查询能正常返回说明Presto到Metastore、Presto到HDFS这两段认证链路都通了。如果执行SHOW TABLES时卡住或者报错大部分情况下是Metastore认证失败如果SHOW TABLES正常但SELECT报权限错误多半是HDFS的impersonation或keytab权限问题。我碰到过一种情况SHOW TABLES能过但SELECT一张有数据的表时报“Permission denied: useranonymous accessPREVIEW_ADMIN”。这实际上是因为HDFS连接的principal没有配置成功Presto的HDFS级Kerberos身份仍是空的。检查hive.properties里hive.hdfs.authentication.type和hive.hdfs.presto.principal是否正确然后在每个Presto节点上用pestc的测试工具或者简单点直接kinit一把验证能否用presto这个principal访问HDFS对应目录。8. 配置完以后五个高频报错和排查思路亲测有效8.1 Clock skew too great这个报错是我在配置阶段最常遇到的之一。Kerberos对时间容忍度极低客户端和服务端时间差超过5分钟默认值就会直接拒绝认证。检查所有机器是否正常NTP同步执行ntpstat或者timedatectl确认。如果NTP暂时无法修正可以临时把Kerberos的最大容忍时间调大一点比如在krb5.conf里加clockskew 300但这是权宜之计根治还是要同步时间。另外一个隐藏点容器化环境下特别容易中招。多个容器节点共用一个宿主机时间源如果宿主机时间漂移所有容器一起遭殃。排查时先看宿主机时间再看容器内时间。8.2 Server not found in Kerberos database这条报错信息很直白但指认故障点的范围很大。看到它就说明你访问的服务principal在KDC里没有注册。优先检查三点principal是手打的还是复制粘贴的hostname是否完全等于实际主机名的FQDN。该principal是否真的在KDC里存在用kadmin.local去查。keytab文件里包含的principal是否和配置里写的principal一致。不一致的情况常见于你给NameNode配了nn/host1但keytab里存的却是nn/host2。排查命令kadmin.local -q getprinc nn/host1EXAMPLE.COM klist -kt /etc/security/keytabs/nn.service.keytab这两个命令输出对不上那问题就很明显了。8.3 Unable to obtain password from user这个错误通常出现在客户端比如你直接用spark-submit或beeline连接时系统想读取本地票据缓存但找不到又或者keytab文件无法读取。解决办法很朴素先确认keytab文件存在且权限正确。然后手动kinit一遍再看klist里有没有票据。如果是Spark作业检查是否在spark-submit参数里加了principal和keytab。还有一种情况是keytab路径写在配置里但配置文件的读取权限不满足。比如Presto的presto用户读不了root用户创建的keytab文件就会报类似错误。这时候chown一下就好。8.4 GSS initiate failed 或 No valid credentials provided这类错误表示客户端没有有效的Kerberos凭证。对于长驻服务HiveServer2、Presto、Hadoop daemon它可能是服务启动时没有成功获取登录上下文对于临时客户端spark-submit、hdfs命令行往往是当前shell用户没有kinit或者kinit的票据已过期。最直接的排查方式就是看服务的启动日志搜索LoginException或者GSSException。如果是服务端日志里出现重点检查Jaas配置和keytab如果是客户端日志出现重点检查当前凭证缓存和keytab参数传递。8.5 Unable to load authentication callback handler这个报错多见于Hive的JDBC连接或Spark SQL访问Hive时说明服务端或客户端的Jaas配置中没有合适的回调处理器。本质还是身份认证方式配置不一致。比如HiveServer2如果配置了KERBEROS认证那么客户端连接时必须提供principal而JDBC URL中也要带principal参数少一个都会导致这种报错。在用beeline连接时加上principal同时确保服务端hive.server2.authenticationKERBEROS再检查一下jaas.conf文件的配置格式有没有语法问题。8.6 常见问题速查表报错核心关键字可能原因优先排查动作Clock skew too great时间不同步检查NTP校准时间Server not foundprincipal不存在或host不对kadmin查principalklist查keytabUnable to obtain password读取不到keytab或凭证调整权限手动kinit验证GSS initiate failed无有效凭证检查服务启动日志和klistAuthentication failedSASL认证失败检查Jaas配置和客户端principalAccessControlException代理用户配置或权限不足检查proxyuser配置和HDFS ACLPermission denied useranonymousPresto的HDFS身份未认证检查hive.hdfs.authentication.type配置9. 最后一些实际维护建议配置完Kerberos不是终点日常运营里还有几件事需要持续关注。我比较看重的是票据自动续期机制。Hadoop生态提供的工具是hadoop-kerberos-renew或者通过Dynamically renewable delegation tokens。最简单稳妥的办法是给长驻服务配置cron计划任务每隔一段时间用keytab重新kinit避免票据过期导致长任务中断。生产环境我最常用的是一个简单的shell脚本配合cron因为轻量而且好排查。新节点上线时keytab分发要纳入自动化流程。每次扩容一个新DataNode节点你都要在新节点上放DataNode的keytab、配置Hadoop客户端环境然后重启服务。如果靠手工做漏掉任何一步都可能导致新节点一直连不上NameNode。建议把这些步骤写成Ansible Playbook或者Shell脚本减少人为失误。启用Kerberos后监控指标要跟着变化。以前你对某个服务的监控可以只看端口存活现在还要看它的Kerberos登录状态、keytab文件一致性、票据剩余时间。这些指标可以通过自定义脚本定期执行klist、kadmin来收集并上报到监控系统。否则服务的端口活着但内部凭证已经失效表面指标一切正常实际查询全部失败这种状态是最难察觉的。不要忽略日志审计。开启Kerberos后所有组件连接都会有认证记录这些日志对定位问题和外部审计都非常有价值。建议把各组件的auth日志单独归档保留足够长的周期出现问题回溯时才能看清认证链路在哪一环断开。我个人在实际使用中最大的体会是Kerberos这套体系不能一次配完就扔到脑后它更像是一个需要持续维护的基础设施。最开始的配置工作占了三分力气剩下的七分全在日常监控、故障排查和对新组件的适配调整上。但只要把身份认证这件事做踏实了后面再上Ranger、Sentry或者SentryAgent之类的授权组件时就能站在一个非常稳的地基上不用回头补安全漏洞。如果你准备开始做这件事我建议先把每台机器的主机名、服务规划、principal列表整理成一张表哪怕用Excel都行。没有这张表配置过程中百分之百会混。祝你在安全的集群上跑得又快又稳。