Spark Shell在Kerberos启用的K8s集群中认证问题求助
在Kerberos认证的K8s集群中Spark Shell认证问题及配置需求
问题背景
在启用Kerberos的Kubernetes集群中,Spark Submit的集群模式、客户端模式均可正常完成Kerberos认证,但Spark Shell(3.3.1)无法正常通过认证。
正常运行场景
集群模式
- 创建包含
krb5.conf的ConfigMap,以及包含hdfs-site.xml、core-site.xml的ConfigMap - 创建keytab文件并挂载到执行
spark-submit的Pod中 - 通过
spark.kubernetes.hadoop.configMapName和spark.kubernetes.kerberos.krb5.configMapName配置Spark挂载上述ConfigMap - 设置
spark.kerberos.keytab和spark.kerberos.principal参数
客户端模式
- 将
hdfs-site.xml和core-site.xml挂载到提交Pod的Spark配置目录 - 将
krb5.conf挂载到/etc/krb5.conf - 两种认证方式均有效:使用
kinit获取Kerberos票据,或设置spark.kerberos.keytab和spark.kerberos.principal参数
Spark Shell异常场景
- 已将
hdfs-site.xml、core-site.xml挂载到提交Pod的Spark配置目录 - 已将
krb5.conf挂载到/etc/krb5.conf - 尝试两种认证方式均无效:
kinit获取票据,或设置spark.kerberos.keytab和spark.kerberos.principal参数
已尝试的操作
- 使用
kinit获取票据,设置spark.kerberos.renewal.credentials为ccache,并配置环境变量KRB5CCNAME指向票据存储路径(无效果) - 验证配置文件已在Spark历史服务器中加载
- 将
krb5.conf放入Spark配置目录 - 通过Java环境参数指定Spark配置目录中的
krb5.conf路径
初始报错信息
Exception in thread "main" java.lang.IllegalArgumentException: Can't get Kerberos realm at org.apache.hadoop.security.HadoopKerberosName.setConfiguration(HadoopKerberosName.java:71) at org.apache.hadoop.security.UserGroupInformation.initialize(UserGroupInformation.java:315) at org.apache.hadoop.security.UserGroupInformation.setConfiguration(UserGroupInformation.java:366) at org.apache.spark.deploy.SparkHadoopUtil.<init>(SparkHadoopUtil.scala:50) at org.apache.spark.deploy.SparkHadoopUtil$.instance$lzycompute(SparkHadoopUtil.scala:397) at org.apache.spark.deploy.SparkHadoopUtil$.instance(SparkHadoopUtil.scala:397) at org.apache.spark.deploy.SparkHadoopUtil$.get(SparkHadoopUtil.scala:418) at org.apache.spark.executor.CoarseGrainedExecutorBackend$.run(CoarseGrainedExecutorBackend.scala:424) at org.apache.spark.executor.CoarseGrainedExecutorBackend$.main(CoarseGrainedExecutorBackend.scala:413) at org.apache.spark.executor.CoarseGrainedExecutorBackend.main(CoarseGrainedExecutorBackend.scala) Caused by: java.lang.IllegalArgumentException: KrbException: Cannot locate default realm at javax.security.auth.kerberos.KerberosPrincipal.<init>(KerberosPrincipal.java:159) at org.apache.hadoop.security.authentication.util.KerberosUtil.getDefaultRealm(KerberosUtil.java:120) at org.apache.hadoop.security.HadoopKerberosName.setConfiguration(HadoopKerberosName.java:69) ... 9 more
后续尝试与新问题
将krb5.conf放置在所有节点并挂载到Executor后,初始报错消失,使用命令:
spark-shell \ --conf spark.kubernetes.executor.volumes.hostPath.krb5.mount.path=/opt/krb5 \ --conf spark.kubernetes.executor.volumes.hostPath.krb5.options.path=/etc \ --conf spark.executor.extraJavaOptions="-Djava.security.krb5.conf=/opt/krb5/krb5.conf"
但执行kinit后出现新错误:
java.io.IOException: org.apache.hadoop.security.AccessControlException: Client cannot authenticate via:[TOKEN, KERBEROS] ...(省略完整错误栈)
通过--files参数上传keytab后可正常运行,但存在弊端:
- Spark Shell使用的
krb5.conf与节点配置不一致 - 上传keytab存在安全风险
需求
希望实现与Spark Submit一致的配置:通过ConfigMap挂载krb5.conf,通过Secret使用keytab。
解决方案建议
1. 用ConfigMap为Driver和Executor挂载krb5.conf
如果集群中已有包含krb5.conf的ConfigMap(比如krb5-config-map),在Spark Shell命令中配置挂载规则:
# 挂载到Driver --conf spark.kubernetes.driver.volumes.configMap.krb5-config.mount.path=/etc \ --conf spark.kubernetes.driver.volumes.configMap.krb5-config.options.name=krb5-config-map \ # 挂载到Executor --conf spark.kubernetes.executor.volumes.configMap.krb5-config.mount.path=/etc \ --conf spark.kubernetes.executor.volumes.configMap.krb5-config.options.name=krb5-config-map \ # 指定JVM加载krb5.conf的路径 --conf spark.driver.extraJavaOptions="-Djava.security.krb5.conf=/etc/krb5.conf" \ --conf spark.executor.extraJavaOptions="-Djava.security.krb5.conf=/etc/krb5.conf"
2. 用Secret为Driver和Executor挂载keytab
创建存储keytab的Secret(比如spark-keytab-secret),然后配置挂载:
# 挂载到Driver --conf spark.kubernetes.driver.volumes.secret.keytab-secret.mount.path=/etc/security/keytabs \ --conf spark.kubernetes.driver.volumes.secret.keytab-secret.options.name=spark-keytab-secret \ # 挂载到Executor --conf spark.kubernetes.executor.volumes.secret.keytab-secret.mount.path=/etc/security/keytabs \ --conf spark.kubernetes.executor.volumes.secret.keytab-secret.options.name=spark-keytab-secret \ # 指定认证参数 --conf spark.kerberos.keytab=/etc/security/keytabs/spark.keytab \ --conf spark.kerberos.principal=spark@YOUR.REALM
3. 挂载Hadoop配置ConfigMap
复用Spark Submit使用的Hadoop配置ConfigMap:
--conf spark.kubernetes.hadoop.configMapName=hadoop-config-map
4. 完整命令示例
整合所有配置,形成可直接使用的Spark Shell命令:
spark-shell \ # 挂载Hadoop配置 --conf spark.kubernetes.hadoop.configMapName=hadoop-config-map \ # 挂载krb5.conf(Driver+Executor) --conf spark.kubernetes.driver.volumes.configMap.krb5-config.mount.path=/etc \ --conf spark.kubernetes.driver.volumes.configMap.krb5-config.options.name=krb5-config-map \ --conf spark.kubernetes.executor.volumes.configMap.krb5-config.mount.path=/etc \ --conf spark.kubernetes.executor.volumes.configMap.krb5-config.options.name=krb5-config-map \ --conf spark.driver.extraJavaOptions="-Djava.security.krb5.conf=/etc/krb5.conf" \ --conf spark.executor.extraJavaOptions="-Djava.security.krb5.conf=/etc/krb5.conf" \ # 挂载keytab(Driver+Executor) --conf spark.kubernetes.driver.volumes.secret.keytab-secret.mount.path=/etc/security/keytabs \ --conf spark.kubernetes.driver.volumes.secret.keytab-secret.options.name=spark-keytab-secret \ --conf spark.kubernetes.executor.volumes.secret.keytab-secret.mount.path=/etc/security/keytabs \ --conf spark.kubernetes.executor.volumes.secret.keytab-secret.options.name=spark-keytab-secret \ # Kerberos认证参数 --conf spark.kerberos.keytab=/etc/security/keytabs/spark.keytab \ --conf spark.kerberos.principal=spark@YOUR.REALM
关键说明
- 替换命令中的ConfigMap、Secret名称为集群中实际存在的资源名称
- 必须同时配置Driver和Executor的挂载:Spark Shell的Driver运行在提交Pod内,Executor分布在集群节点,两者都需要Kerberos配置文件
- 通过Secret挂载keytab避免了敏感文件的明文传输,安全性更高,且配置逻辑与Spark Submit完全对齐
内容的提问来源于stack exchange,提问作者jonas.hartwig
相关产品推荐
相关产品推荐

