有哪些方法可以验证kerberos keytab文件的有效性?

简介: 有哪些方法可以验证kerberos keytab文件的有效性?

1 Keytab 文件概述

  • 在开启了kerberos安全认证的环境中,任何用户进行任何操作之前,都要首先通过 AS_REQ 请求向 KDC 的 AS 进行认证以获得总票据 tgt,然后才能通过 TGS_REQ 请求向 KDC 的 TGS申请具体的服务票据 ticket;
  • 而在进行 AS_REQ 请求时,可以通过命令行交互式手动输入密码的方式(比如执行命令 kinit dap),也可以通过keytab文件的方式(比如JAVA代码中的org.apache.hadoop.security.UserGroupInformation#loginUserFromKeytab(String user,String path),或命令行的 kinit dap -kt dap.keytab);
  • keytab 文件包含了单个或多个principal(用户/组/服务/服务器)的身份认证信息(即key),在功能上等同于密码,且有些管理员倾向于定期为 principal 生成符合密码策略 password policy 的随机密码以增强其安全性,所以 keytab 文件的安全性和重要性不言而喻。

image.png


2 keytab文件的有效性概述

管理员经常会在kdc服务端更改某个 principal 的密码,常见的更改密码的场景有:

  • 比如通过命令显示更改密码:kpasswd;
  • 比如通过脚本定期显示更改密码 (password rotation);
  • 比如通过命令kadmin.local -q "xst -k dap.keytab dap",在生成新的keytab文件时隐式同步更改密码。

无论哪种场景,一旦服务端更改密码后,原有的已经分发给客户端的keytab文件都将失效,所有客户端需要验证其keytab的有效性。 由于 keytab 文件是加密的二进制格式,我们并不能通过 less/cat等命令直接查看其内容,那么怎么验证keytab文件的有效性呢?

3 使用 klist 命令查看对比新老 keytab 文件以验证其有效性

  • 每个keytab文件可以包括多个principa的认证信息,也可以包括同一个principal的多个版本的认证信息;
  • 可以通过 klist -ekt xxx.keytab 查看keytab文件内容,在输出内容中的 KVNO 列代表 key version number,较新版本对应列的KVNO值会更大,klist/kinit等命令或程序使用该keytab文件进行认证时,会自动选择并使用KVNO值最大的列;
  • 可以通过以下命令在不更改某个principal原有密码的情况下,将其认证信息写入当前路径下的某个keytab文件中(如果当前路径不存在该keytab文件,则会新建该文件;如果当前路径存在该Keytab文件,则会将该principal认证信息追加到该keytab文件中):kadmin.local -q "xst -norandkey -k spark2.keytab dap2";
  • 可以通过以下命令,更改某个principal的旧密码并生成随机新密码,然后将其新认证信息写入当前路径下的某个keytab文件中(如果当前路径不存在该keytab文件,则会新建该文件;如果当前路径存在该Keytab文件,则会将该principal认证信息追加到该keytab文件中):kadmin.local -q "xst -k spark2.keytab dap2";
  • Multiple keys can be present in a keytab file,the version of the key is shown in its key version number (KVNO).,Refreshing (also called rotating) the principal's key increments the KVNO in the keytab entry.
  • When a key is refreshed, a new entry is added to the keytab with a higher KVNO. The original key remains in the keytab but is no longer used to issue tickets.

image.png


4 使用keytab文件进行认证并查看相关日志

可以通过kinit命令或JAVA代码使用keytab文件进行认证,以验证其有效性。 为进一步细致排查问题,也可以通过以下方式调整kerberos日志级别:

  • 通用配置 OS-level Kerberos Debugging: export KRB5_TRACE=/tmp/kinit.log (技术背景:User can set an environment variable called KRB5_TRACE to a filename or to /dev/stdout, Kerberos programs like kinit, klist and kvno etc., as well as Kerberos libraries libkrb5*, will start printing more interesting details.This is a very powerfull feature and can be used to debug any program which uses Kerberos libraries);
  • JAVA程序,可以配置 JVM Kerberos Library logging:-Dsun.security.krb5.debug=true
  • JAVA程序,可以配置 JVM SPNEGO Logging:-Dsun.security.spnego.debug=true
  • HADOOP可以配置 Hadoop-side JAAS debugging:export HADOOP_JAAS_DEBUG=true
  • HADOOP可以配置 HADOOP_OPTS environment variable:export HADOOP_OPTS="-Djava.net.preferIPv4Stack=true -Dsun.security.krb5.debug=true ${HADOOP_OPTS}“
  • if the env variable HADOOP_JAAS_DEBUG is set to true,then hadoop UGI will set the "debug" flag on any JAAS files it creates;
  • 针对HADOOP配置环境变量时,可以通过以下命令查看环境变量:echo $HADOOP_OPTS(不是 export $HADOOP_OPTS!!!!);

因为 keytab 文件失效而认证失败时,常见的两个错误如下:

## 错误1:javax.security.auth.login.LoginException: Checksum failed,完整信息如下:
Caused by: org.apache.hadoop.security.KerberosAuthException: failure to login: for principal: dap2@CDH.COM from keytab ./dap2.keytab javax.security.auth.login.LoginException: Checksum failed
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1846) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]
        at com.hundsun.broker.dsc.biz.pub.util.JdbcEntityUtils.getHiveJdbcEntity(JdbcEntityUtils.java:867) ~[dsc-biz-pub.jar:?]
        at com.hundsun.broker.dsc.biz.pub.util.JdbcEntityUtils.loadPropConfig(JdbcEntityUtils.java:678) ~[dsc-biz-pub.jar:?]
        at com.hundsun.broker.dsc.biz.pub.util.JdbcEntityUtils.<clinit>(JdbcEntityUtils.java:93) ~[dsc-biz-pub.jar:?]
        ... 2 more
Caused by: javax.security.auth.login.LoginException: Checksum failed
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:804) ~[?:1.8.0_201]
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) ~[?:1.8.0_201]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[?:1.8.0_201]
        at org.apache.hadoop.security.UserGroupInformation$HadoopLoginContext.login(UserGroupInformation.java:1924) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1836) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]
Caused by: sun.security.krb5.KrbCryptoException: Checksum failed
        at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:102) ~[?:1.8.0_201]
        at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:94) ~[?:1.8.0_201]
        at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:175) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsRep.decrypt(KrbAsRep.java:149) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsRep.decryptUsingKeyTab(KrbAsRep.java:121) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsReqBuilder.resolve(KrbAsReqBuilder.java:285) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:361) ~[?:1.8.0_201]
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:776) ~[?:1.8.0_201]
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) ~[?:1.8.0_201]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[?:1.8.0_201]
        at org.apache.hadoop.security.UserGroupInformation$HadoopLoginContext.login(UserGroupInformation.java:1924) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1836) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]
Caused by: java.security.GeneralSecurityException: Checksum failed
        at sun.security.krb5.internal.crypto.dk.AesDkCrypto.decryptCTS(AesDkCrypto.java:451) ~[?:1.8.0_201]
        at sun.security.krb5.internal.crypto.dk.AesDkCrypto.decrypt(AesDkCrypto.java:272) ~[?:1.8.0_201]
        at sun.security.krb5.internal.crypto.Aes128.decrypt(Aes128.java:76) ~[?:1.8.0_201]
        at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:100) ~[?:1.8.0_201]
        at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:94) ~[?:1.8.0_201]
        at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:175) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsRep.decrypt(KrbAsRep.java:149) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsRep.decryptUsingKeyTab(KrbAsRep.java:121) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsReqBuilder.resolve(KrbAsReqBuilder.java:285) ~[?:1.8.0_201]
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:361) ~[?:1.8.0_201]
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:776) ~[?:1.8.0_201]
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) ~[?:1.8.0_201]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) ~[?:1.8.0_201]
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[?:1.8.0_201]
        at org.apache.hadoop.security.UserGroupInformation$HadoopLoginContext.login(UserGroupInformation.java:1924) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1836) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]
##错误2:javax.security.auth.login.LoginException: Unable to obtain password from user,完整信息如下:
Caused by: org.apache.hadoop.security.KerberosAuthException: failure to login: for principal: hundsun@FZCN.ORG from keytab ./spark2.keytab javax.security.auth.login.LoginException: Unable to obtain password from user
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1846) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]
Caused by: javax.security.auth.login.LoginException: Unable to obtain password from user
        at com.sun.security.auth.module.Krb5LoginModule.promptForPass(Krb5LoginModule.java:897) ~[?:1.8.0_221]
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:760) ~[?:1.8.0_221]
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617) ~[?:1.8.0_221]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_221]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_221]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_221]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) ~[?:1.8.0_221]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) ~[?:1.8.0_221]
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[?:1.8.0_221]
        at org.apache.hadoop.security.UserGroupInformation$HadoopLoginContext.login(UserGroupInformation.java:1924) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1836) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytabAndReturnUGI(UserGroupInformation.java:1214) ~[hadoop-common-3.1.4.jar:?]
        at org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(UserGroupInformation.java:1007) ~[hadoop-common-3.1.4.jar:?]


相关文章
|
3月前
|
安全 jenkins 持续交付
Jenkins 用于验证用户的 3 种安全机制
【8月更文挑战第27天】
70 5
|
3月前
|
JSON 安全 API
|
4月前
|
算法 数据安全/隐私保护 Python
数字签名是一种用于验证数据完整性和来源身份的技术。它基于公钥密码学,允许数据的发送方使用其私钥对数据进行签名,而接收方则可以使用发送方的公钥来验证签名的有效性。
数字签名是一种用于验证数据完整性和来源身份的技术。它基于公钥密码学,允许数据的发送方使用其私钥对数据进行签名,而接收方则可以使用发送方的公钥来验证签名的有效性。
|
5月前
|
Java 关系型数据库 MySQL
使用CAS登录模块连接数据库验证用户合法性
使用CAS登录模块连接数据库验证用户合法性
27 0
|
5月前
参数验证工具
参数验证工具
32 0
|
6月前
|
前端开发 安全 Go
CSRF 实验:更改请求方式绕过验证
CSRF 实验:更改请求方式绕过验证
|
6月前
|
数据采集 存储 安全
数据功能验证
数据功能验证
108 4
|
数据安全/隐私保护
JMX安全漏洞修复 服务端增加用户名和密码验证机制
JMX安全漏洞修复 服务端增加用户名和密码验证机制
160 0
|
数据安全/隐私保护 Windows 安全
083.验证歌德巴赫猜想
083.验证歌德巴赫猜想
90 0