使用具有受限双跳和模拟的 SSO 的 Active Directory 中的 Kerberos 无法更新服务票证
Kerberos in Active Directory using SSO with constrained double-hop and impersonation fails to renew service ticket
深入研究已在
中讨论的 Kerberos 约束委派
我有一个在多个服务器上运行的分布式应用程序,并通过 Kerberos 令牌依赖 SSO 进行用户身份验证,并且一切都按照上述线程中的讨论进行了布局(并且正在运行)。简而言之,
- 用户连接到服务器 运行ning 上的服务 1
- Server1 会将用户的作业分派给 Server2,即 运行ning
服务主体帐户下的另一项服务
一种。 Server1 请求(并获得)相关 SPN
的票证
b.服务器 1 将票据传输到服务器 2
- Server2 解析该票证(即 AcquireCredentialsHandle 和 AcceptSecurityContext),然后调用 QuerySecurityContextToken ,接着是 DuplicateHandle,
CreateProcess,将重复句柄传递给子进程,并
然后子进程调用 ImpersonateLoggedOnUser
- Server2 上的子进程现在正在 运行ning 模拟原始用户并且是
能够以该用户身份访问某些 Server3
上的网络资源
所以,一切正常……直到不再正常。步骤2a中获取的服务票据的生命周期最长为10小时(假设AD设置为服务票据默认10小时有效期)。票证生命周期有时远少于 10 小时的原因是因为步骤 1 和步骤 2 之间可能存在明显的延迟,例如,用户可能在提交作业进行处理之前做了一整天的准备工作。因此,服务票据结束时间将从原始用户登录时间起 10 小时,即与用户连接时生成的 TGT 的结束时间相匹配。
在服务票过期前大约 5 分钟,Server2 似乎尝试更新这张票,并且一张新票确实出现在 klist 中,用于 Server2 上子进程的 LUID .然而,这张新票据似乎“格式错误”,此时客户端进程失去了访问网络资源的能力,就像被冒充的用户一样。具体来说,虽然客户端进程仍然持有对 Server3 资源的有效 Kerberos 服务票证,但当从 Server2 向 Server3 伸出时,它从 Kerberos 身份验证下降到 NTLM 身份验证,此时它被 Server3 拒绝。
这是失败时 Server2 上 LUID 运行ning 子进程的 klist 输出示例;
Current LogonId is 0:0x5777e
Targeted LogonId is 0:0x3966b5
Cached Tickets: (5)
#0> Client: user @ VNET.COM
Server: MSSQLSvc/sql.vnet.com:1433 @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0
Kdc Called: DC.Vnet.com
#1> Client: user @ VNET.COM
Server: ldap/DC.Vnet.com/Vnet.com @ VNET.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: DC.Vnet.com
#2> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#3> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#4> Client: user @ VNET.COM
Server: SVCD/APP.Vnet.com @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:11:39 (local)
End Time: 2/20/2020 22:26:39 (local)
Renew Time: 0
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x8 -> ASC
Kdc Called:
在上面的清单中,工单#4 是在步骤 2a 中请求的原始服务工单; SPN 是“SVCD/APP.Vnet.com”,与此 SPN 关联的域帐户(以及 运行 宁服务器 2 服务进程)是“ svc”。此票证用于在 Server2 上创建用户的安全上下文,子进程模拟该安全上下文。工单 #0 和 #1 是在子进程尝试访问 LDAP 和 MS SQL 服务器(用于子进程需要执行的工作)后模拟后生成的,因此这确认所有约束委派设置都很好并且子进程按预期 运行ning 长达 10 小时。在某些情况下,工单 #0 和 #1 需要更新 - 它们已成功更新,并且该过程继续进行。
现在,问题是:ticktes #2 和 #3 是在 #4 结束前几分钟生成的,但对我来说奇怪的是 ServerRealm 部分,即“svc @ …”为空白。此外,在生成这些票证的那一刻,Server2 子进程停止能够打开新的 MS SQL 到 Server3 的连接(并且在 Server3 上,匿名登录拒绝事件被记录为具有匹配的时间戳)。我还应该提到,虽然在上面的示例中有两张相同的“Server: svc @”票,但在某些情况下,我看到 7、14,有时甚至 30 多张相同的票,例如那。所有这些都是同时发出的,就好像 Server2 疯狂地尝试从 KDC 获得它需要的东西,但失败了。
我的解释是 Server2 想要更新模拟中使用的服务票证,但没有这样做。
此时我不确定问题是否出在;
a) AD 设置(即,具有受约束的委派详细信息),或
b) 在“svc”域帐户的权限中(它具有 SetImpersonatePrivilege 但可能需要其他东西),或
c) 在Server2中父进程和子进程之间传递用户安全上下文的方式,或者
d) 完全不同的东西
到目前为止,在阅读和研究了大量时间之后,我已经尝试了 c) 的各种序列排列(例如使用 DuplicateTokenEx + CreateProcessAsUser 相反,为重复的句柄和标记等翻转各种标志,但我不知道我可以和应该用 a) 和 b) 做什么(如果有的话)。我尝试更改一些设置,但没有效果,但我避免使用“核心”选项,例如在 svc 帐户上设置 SeTcbPrivilege,因为这是不可接受的我的解决方案。
最后一个观察是票 #4 缺少“Kdc Called”和“更新时间”,但我的印象是这是通过 InitializeSecurityContext.
获得的不透明票证的正常现象
我需要更改什么才能使 Server2 上的子进程 运行 超过原来的 10 小时?
我通过 Farzan Mirheydari 提供的评论解决了这个问题,这可以简化为在 AD 中为 svc[=36= 的约束委派设置下设置 "Use any authentication protocol" 的要求] 帐户。这将设置 TrustedToAuthForDelegation (T2A4D) 标志,允许 "protocol transition"。
Microsoft article 中隐含了为什么需要这样做的原因。尽管我的情况与那篇文章中描述的布局不同,但看起来(据我所知)Kerberos 票证由 AcceptSecurityContext 在 Server2 上生成并由 Cache Flags: 0x8 -> ASC
标识是 "token...just duplicated for the second service session access."
因此,当此 ASC 令牌过期时,模拟 user 的 svc 帐户无法更新它,因为它是重复的,缺少KDC/renewal 信息。相反,它为自己获取 S4U2Self ticket,如 Cache Flags: 0x4 -> S4U
所示,以便继续模拟 user 和 运行 客户端进程。如果客户端进程不尝试创建到 Server3 的新 SQL 连接,这一切都很好。但是,如果现在 运行 在 S4U2Self 协议下的进程尝试使用 Kerberos 协议建立新的 SQL 连接,除非也允许协议转换,否则它将失败。
为 svc 设置 T2A4D 标志将导致 S4U 票据接收 forwardable
标志
#2> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
如前所述here,现在一切正常!
深入研究已在
中讨论的 Kerberos 约束委派
我有一个在多个服务器上运行的分布式应用程序,并通过 Kerberos 令牌依赖 SSO 进行用户身份验证,并且一切都按照上述线程中的讨论进行了布局(并且正在运行)。简而言之,
- 用户连接到服务器 运行ning 上的服务 1
- Server1 会将用户的作业分派给 Server2,即 运行ning
服务主体帐户下的另一项服务
一种。 Server1 请求(并获得)相关 SPN
的票证 b.服务器 1 将票据传输到服务器 2 - Server2 解析该票证(即 AcquireCredentialsHandle 和 AcceptSecurityContext),然后调用 QuerySecurityContextToken ,接着是 DuplicateHandle, CreateProcess,将重复句柄传递给子进程,并 然后子进程调用 ImpersonateLoggedOnUser
- Server2 上的子进程现在正在 运行ning 模拟原始用户并且是 能够以该用户身份访问某些 Server3 上的网络资源
所以,一切正常……直到不再正常。步骤2a中获取的服务票据的生命周期最长为10小时(假设AD设置为服务票据默认10小时有效期)。票证生命周期有时远少于 10 小时的原因是因为步骤 1 和步骤 2 之间可能存在明显的延迟,例如,用户可能在提交作业进行处理之前做了一整天的准备工作。因此,服务票据结束时间将从原始用户登录时间起 10 小时,即与用户连接时生成的 TGT 的结束时间相匹配。
在服务票过期前大约 5 分钟,Server2 似乎尝试更新这张票,并且一张新票确实出现在 klist 中,用于 Server2 上子进程的 LUID .然而,这张新票据似乎“格式错误”,此时客户端进程失去了访问网络资源的能力,就像被冒充的用户一样。具体来说,虽然客户端进程仍然持有对 Server3 资源的有效 Kerberos 服务票证,但当从 Server2 向 Server3 伸出时,它从 Kerberos 身份验证下降到 NTLM 身份验证,此时它被 Server3 拒绝。
这是失败时 Server2 上 LUID 运行ning 子进程的 klist 输出示例;
Current LogonId is 0:0x5777e
Targeted LogonId is 0:0x3966b5
Cached Tickets: (5)
#0> Client: user @ VNET.COM
Server: MSSQLSvc/sql.vnet.com:1433 @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0
Kdc Called: DC.Vnet.com
#1> Client: user @ VNET.COM
Server: ldap/DC.Vnet.com/Vnet.com @ VNET.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
Start Time: 2/20/2020 22:21:02 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: DC.Vnet.com
#2> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#3> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
#4> Client: user @ VNET.COM
Server: SVCD/APP.Vnet.com @ VNET.COM
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:11:39 (local)
End Time: 2/20/2020 22:26:39 (local)
Renew Time: 0
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x8 -> ASC
Kdc Called:
在上面的清单中,工单#4 是在步骤 2a 中请求的原始服务工单; SPN 是“SVCD/APP.Vnet.com”,与此 SPN 关联的域帐户(以及 运行 宁服务器 2 服务进程)是“ svc”。此票证用于在 Server2 上创建用户的安全上下文,子进程模拟该安全上下文。工单 #0 和 #1 是在子进程尝试访问 LDAP 和 MS SQL 服务器(用于子进程需要执行的工作)后模拟后生成的,因此这确认所有约束委派设置都很好并且子进程按预期 运行ning 长达 10 小时。在某些情况下,工单 #0 和 #1 需要更新 - 它们已成功更新,并且该过程继续进行。
现在,问题是:ticktes #2 和 #3 是在 #4 结束前几分钟生成的,但对我来说奇怪的是 ServerRealm 部分,即“svc @ …”为空白。此外,在生成这些票证的那一刻,Server2 子进程停止能够打开新的 MS SQL 到 Server3 的连接(并且在 Server3 上,匿名登录拒绝事件被记录为具有匹配的时间戳)。我还应该提到,虽然在上面的示例中有两张相同的“Server: svc @”票,但在某些情况下,我看到 7、14,有时甚至 30 多张相同的票,例如那。所有这些都是同时发出的,就好像 Server2 疯狂地尝试从 KDC 获得它需要的东西,但失败了。
我的解释是 Server2 想要更新模拟中使用的服务票证,但没有这样做。
此时我不确定问题是否出在;
a) AD 设置(即,具有受约束的委派详细信息),或
b) 在“svc”域帐户的权限中(它具有 SetImpersonatePrivilege 但可能需要其他东西),或
c) 在Server2中父进程和子进程之间传递用户安全上下文的方式,或者
d) 完全不同的东西
到目前为止,在阅读和研究了大量时间之后,我已经尝试了 c) 的各种序列排列(例如使用 DuplicateTokenEx + CreateProcessAsUser 相反,为重复的句柄和标记等翻转各种标志,但我不知道我可以和应该用 a) 和 b) 做什么(如果有的话)。我尝试更改一些设置,但没有效果,但我避免使用“核心”选项,例如在 svc 帐户上设置 SeTcbPrivilege,因为这是不可接受的我的解决方案。
最后一个观察是票 #4 缺少“Kdc Called”和“更新时间”,但我的印象是这是通过 InitializeSecurityContext.
获得的不透明票证的正常现象我需要更改什么才能使 Server2 上的子进程 运行 超过原来的 10 小时?
我通过 Farzan Mirheydari 提供的评论解决了这个问题,这可以简化为在 AD 中为 svc[=36= 的约束委派设置下设置 "Use any authentication protocol" 的要求] 帐户。这将设置 TrustedToAuthForDelegation (T2A4D) 标志,允许 "protocol transition"。
Microsoft article 中隐含了为什么需要这样做的原因。尽管我的情况与那篇文章中描述的布局不同,但看起来(据我所知)Kerberos 票证由 AcceptSecurityContext 在 Server2 上生成并由 Cache Flags: 0x8 -> ASC
标识是 "token...just duplicated for the second service session access."
因此,当此 ASC 令牌过期时,模拟 user 的 svc 帐户无法更新它,因为它是重复的,缺少KDC/renewal 信息。相反,它为自己获取 S4U2Self ticket,如 Cache Flags: 0x4 -> S4U
所示,以便继续模拟 user 和 运行 客户端进程。如果客户端进程不尝试创建到 Server3 的新 SQL 连接,这一切都很好。但是,如果现在 运行 在 S4U2Self 协议下的进程尝试使用 Kerberos 协议建立新的 SQL 连接,除非也允许协议转换,否则它将失败。
为 svc 设置 T2A4D 标志将导致 S4U 票据接收 forwardable
标志
#2> Client: user @ VNET.COM
Server: svc @
KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/20/2020 22:23:37 (local)
End Time: 2/21/2020 7:07:45 (local)
Renew Time: 2/27/2020 21:07:45 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x4 -> S4U
Kdc Called: DC.Vnet.com
如前所述here,现在一切正常!