聊聊 kerberos 的 kinit 命令和 ccache 机制

1. 前言

大家好,最近遇到了个 kerberos 相关问题,“客户端节点上执行 kinit -R 命令报错:KDC can’t fulfill requested option while renewing credentials”, 在次跟大家分享下问题的解决方式,和背后的相关知识点,主要涉及到 kerberos 的 kinit 命令和 ccache 机制。

2. 问题现象与问题日志

  • 问题现象: 客户端执行命令 kinit -R 报错: “KDC can’t fulfill requested option while renewing credentials”
  • 问题日志:查看 KDC 服务端日志/var/log/krb5kdc.log 可知,上述报错对应的请求是 TGS_REQ,细节是 liming@TEST.COM for krbtgt/TEST.COM@TEST.COM,其错误原因是 ticket not renewable, 即 ticket 不可刷新;

image

3. 问题原因

那么 “ticket not renewable” 的原因又有哪些呢?主要有以下几个:

  • 服务端配置文件 /var/kerberos/krb5kdc/kdc.conf 或 /etc/krb5.conf 中对应的 realms 段中没有配置允许 renew ticket;
  • 服务端生成 krbtgt 这个 principal 时,没有配置参数 maxrenewlife,即没有指定其 ticket 的最大可刷新时长;
  • 服务端生成用户的 principal 时,没有配置参数 maxrenewlife,即没有指定其 ticket 的 最大可刷新时长(如报错日志中的 liming@TEST.COM);
  • 客户端上次成功登陆后,获得的 krbtgt 这个 service principal 的可刷新时间已过期,其过期原因是超过了服务端配置的 maxrenewlife(如报错日志中的 krbtgt/TEST.COM@TEST.COM);
  • 客户端上次成功登陆后,用户 principal 的 ticket 已过期,其过期原因是超过了服务端配置的 ticket_lifetime,该参数一般配置为 24 h(如报错日志中的 liming@TEST.COM);
    image

4. 问题解决方案与操作步骤

通过上述分析,我们知道,为解决问题,需要更改服务端的配置参数max_renewable_life,需要更改服务端上述两个 principal 的 maxrenewlife,并确保客户端指定 kinit -R 时 krbtgt 并没有过期,才能确保任务执行成功。

  1. 服务端更改或确认配置文件/var/kerberos/krb5kdc/kdc.conf 或 /etc/krb5.conf 中,对应的 realms 段中需要配置参数允许刷新:max_renewable_life
  2. 服务端更过或确认上述两个 principal 的参数 maxrenewlife,示例命令如下:
  • modprinc -maxrenewlife “1 week” +allow_renewable liming@TEST.COM
  • modprinc -maxrenewlife “1 week” +allow_renewable krbtgt/TEST.COM@TEST.COM
  • kadmin.local -q “getprinc krbtgt/TEST.COM@TEST.COM” | grep -i life
  • kadmin.local -q “getprinc liming@TEST.COM” | grep -i life
  1. 上述配置修改或确认完毕后,还需要重新登录以生成新的 ticket,后续的 kinit -R 命令才能成功执行;
  2. 同时可以看到,改动 principal 的参数 maxrenewlife 前,klist 不提示 renew until …,而改动 principal 的参数 maxrenewlife后,klist 会提示 renew until …,即在次日期之前可以使用 kinit -R 刷新 ticket;

image

image

5. 背景知识: kinit 命令与 ccache 机制

  • 用户在客户端通过 kinit 成功登录 kerberos 后,会将获得的 ticket-granting ticket 缓存到客户端的 ccache (credentail cache) 文件中;
  • ccache 文件地址是通过配置文件 /etc/krb5.conf 中的参数 default_ccache_name来配置的,在 linux 操作系统中一般是配置为 FILE:/tmp/krb5cc_%{uid},实际对应文件 /tmp/krb5cc_0 等;
  • “kinit -R” 命令,可以用来刷新 ticket-granting ticket,即 tgt;
  • “kinit -R” 命令,只能在 ticket 没有过期之前,且还在 krbtgt 可刷新时间之前,刷新 ticket;
  • “kinit -R” 成功刷新 ticket 之后, 会更新 ccache (credentail cache) 文件,大家可以通过 ls -al 命令查看 linux 中该文件的 ctime 确认这一点;
  • kinit 登录,对应的是 AS_REQ,需要 KDC 中的 Authentication Server (AS) 校验用户身份,获得的是krbtgt,对应 kerberos 日志中的:liming@TEST.COM for krbtgt/TEST.COM@TEST.COM;
  • kinit 认证完毕后,后续使用受 kerberos 保护的服务,比如登录 hiveserver2时,命令格式为:beeline -u “jdbc:hive2://uf30-2:10000/default;principal=hive/_HOST@TEST.COM”, 此时在底层是一个 TGS_REQ,对应 kerberos 日志中的:liming@TEST.COM for hive/cdp2@TEST.COM;
  • kinit -R 续期 tgt,对应的是 TGS_REQ, 需要 KDC 中的 Ticket Granting Server (TGS) 的响应,其效果是刷新了krbtgt,更新了 ccache 文件如 /tmp/krb5cc_0, 对应 kerberos 日志中的:liming@TEST.COM for krbtgt/TEST.COM@TEST.COM

image

image

[root@uf30-1 ~]# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin/admin@CDH.COM
Valid starting       Expires              Service principal
11/13/2020 13:08:27  11/14/2020 13:08:27  krbtgt/CDH.COM@CDH.COM
    renew until 11/20/2020 13:08:27
[root@uf30-1 ~]# kinit -R
[root@uf30-1 ~]# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin/admin@CDH.COM
Valid starting       Expires              Service principal
11/13/2020 19:38:15  11/14/2020 19:38:15  krbtgt/CDH.COM@CDH.COM
    renew until 11/20/2020 13:08:27
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
The `kinit` command is typically used to obtain and cache a Kerberos ticket-granting ticket (TGT) for a user or service principal. The `-kt` option specifies the path to the keytab file containing the service principal's key, and the principal name `kafka/[email protected]` specifies the service principal to use for authentication. Here is an example Java code snippet that shows how to use the `javax.security.auth.Subject` and `javax.security.auth.login.LoginContext` classes to obtain a Kerberos TGT using a keytab file: ```java import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import java.io.File; public class KerberosAuthenticator { public static void main(String[] args) { String keytabPath = "/etc/keytabs/keytab"; String principalName = "kafka/[email protected]"; // Set up the Kerberos login configuration System.setProperty("java.security.auth.login.config", "/etc/krb5.conf"); // Create a new subject to hold the Kerberos credentials Subject subject = new Subject(); // Create a new login context using the keytab and principal try { LoginContext loginContext = new LoginContext("KafkaClient", subject, null, new KeytabPrincipalAuthenticationModule(keytabPath, principalName)); loginContext.login(); } catch (LoginException e) { System.err.println("Failed to login: " + e.getMessage()); return; } // Print out the Kerberos ticket details System.out.println("Kerberos ticket granted to:"); subject.getPrincipals().forEach(System.out::println); } private static class KeytabPrincipalAuthenticationModule implements javax.security.auth.spi.LoginModule { private final String keytabPath; private final String principalName; private boolean succeeded = false; public KeytabPrincipalAuthenticationModule(String keytabPath, String principalName) { this.keytabPath = keytabPath; this.principalName = principalName; } @Override public void initialize(Subject subject, CallbackHandler callbackHandler, java.util.Map<String, ?> sharedState, java.util.Map<String, ?> options) { } @Override public boolean login() throws LoginException { // Create a new Kerberos login configuration based on the specified keytab and principal javax.security.auth.login.Configuration config = new javax.security.auth.login.AppConfigurationEntry[] { new javax.security.auth.login.AppConfigurationEntry( "com.sun.security.auth.module.Krb5LoginModule", javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, java.util.Map.of( "useKeyTab", "true", "keyTab", keytabPath, "principal", principalName, "storeKey", "true", "doNotPrompt", "true" ) ) }; // Attempt to authenticate using the keytab and principal javax.security.auth.login.LoginContext context = new javax.security.auth.login.LoginContext("", null, null, config); context.login(); // Add the Kerberos credentials to the subject succeeded = true; subject.getPrivateCredentials().add(context.getTicket()); return true; } @Override public boolean commit() throws LoginException { return succeeded; } @Override public boolean abort() throws LoginException { return false; } @Override public boolean logout() throws LoginException { subject.getPrivateCredentials().clear(); return true; } } } ``` This code defines a `K

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明哥的IT随笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值