userABC
userABC

Reputation: 1

Kerberos in Active Directory using SSO with constrained double-hop and impersonation fails to renew service ticket

Digging deeper into Kerberos constrained delegation already discussed in
Client/Server app, how to create process on remote system as a domain user without transferring that users username/password to the remote system?
support kerberos constrained delegation using SSPI for multiprocess

I have a distributed application working over multiple servers and relying on SSO via Kerberos tokens for user authentication, and everything is laid out (and working) as discussed in the above-mentioned threads. In brief,

  1. User connects to a service running on Server1
  2. Server1 will dispatch a user’s job to Server2, which is running another service under the service principal account
    a. Server1 requests (and gets) a ticket to relevant SPN
    b. Server1 transmits the ticket to Server 2
  3. Server2 parses that ticket (i.e. AcquireCredentialsHandle and AcceptSecurityContext), and then calls QuerySecurityContextToken,followed by DuplicateHandle, CreateProcess, passes the duplicate handle to a child process, and then the child process calls ImpersonateLoggedOnUser
  4. Child process on Server2 is now running impersonating original user and is able to reach network resources as that user on some Server3

So, everything works just fine…until it doesn’t anymore. The service ticket obtained in step 2a has a lifetime of up to 10 hours (assuming AD is set for the default 10 hour validity for service tickets). The reason for the ticket lifetime sometimes being far less than 10 hrs is because there can be a significant delay between steps 1 and 2, e.g., the user could be doing some prep work for a whole day before submitting a job for processing. Thus, the service ticket end time will be 10 hours from the time of original user login, i.e. matching the end time of the TGT generated at user connection.

About 5 minutes before the service ticket expires, Server2 seems to try to renew this ticket, and a new ticket does show up in klist for LUID of the child process on Server2. However, this new ticket seems to be “misformatted”, and at that point the client process loses the ability to reach network resources as the user being impersonated. Specifically, although the client process still holds a valid Kerberos service ticket to Server3 resources, when reaching out from Server2 to Server3 it drops from Kerberos authentication to NTLM authentication, at which point it is rejected by Server3.

Here is a sample of klist output for LUID running child process on Server2 at the moment of failure;

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:

In the above listing, ticket #4 is the original service ticket requested in step 2a; the SPN is “SVCD/APP.Vnet.com”, and the domain account associated with this SPN (and running the Server2 service process) is “svc”. This ticket was used to create user’s security context on Server2 and child process was impersonating that security context. Tickets #0 and #1 were generated after impersonation when a child process tried to reach LDAP and MS SQL servers (for the work the child process needs to perform), so this confirms that all constrained delegation setups are good and the child process is running as expected for up to 10 hours. In some cases, tickets #0 and #1 need to be renewed - and they are successfully renewed, and the process keeps going.

Now, the problem: ticktes #2 and #3 were generated a few minutes before #4 ends, but what seems strange to me is that the ServerRealm part, i.e., “svc @ …” is blank. Also, at the moment these tickets are generated, the Server2 child process stops being able to open new MS SQL connections to Server3 (and on Server3 events of ANONYMOUS login rejection are logged with matching time stamps). I should also mention that while in the above example there are two identical tickets for “Server: svc @“, in some cases I see 7, 14, and sometimes even 30+ identical tickets like that. All issued at the same time, as if there is some frantic attempt by Server2 to get what it needs from KDC, but failing.

My interpretation is that Server2 wants to renew the service ticket used in impersonation but is failing to do so.

At this point I am not sure whether the problem is in;
a) AD setup (i.e., with constrained delegation details), or
b) in permissions for the “svc” domain account (it has SetImpersonatePrivilege but might need something else), or
c) in the way user’s security context is transferred between the parent process and the child process in Server2, or
d) something completely different

So far, after reading and researching this for significant amount of time, I have tried various permutations of sequence for c) (e.g. use DuplicateTokenEx + CreateProcessAsUser instead, flipping around various flags for duplicate handles and tokens, etc.), but I’m at loss as to what (if anything) I can and should do with a) and b). I tried changing some settings, with no effect, but I avoided using “nuclear” options like setting SeTcbPrivilege on svc account since that would not be acceptable solution in my case.

One final observation is that ticket #4 lacks “Kdc Called” and “Renew Time”, but I was under impression that this is a normal for opaque tickets obtained via InitializeSecurityContext.

What do I need to change in order to get the child process on Server2 to run beyond the original 10 hrs?

Upvotes: 0

Views: 2254

Answers (1)

userABC
userABC

Reputation: 1

I solved the problem via comment provided by Farzan Mirheydari, which can be reduced to a requirement to set "Use any authentication protocol" under constrained delegation setup in AD for svc account. This will set TrustedToAuthForDelegation (T2A4D) flag, which allows for "protocol transition".

The reason why this is required is implied in a Microsoft article. Although my situation is not the same as layout described in that article, it appears (as best as I can tell) that Kerberos ticket generated on Server2 by AcceptSecurityContext and identified by Cache Flags: 0x8 -> ASC is "token...just duplicated for the second service session access."

Thus, when this ASC token expires, svc account which is impersonating user can not renew it since, as duplicate, it lacks KDC/renewal information. Instead it gets S4U2Self ticket for itself, as evidenced by Cache Flags: 0x4 -> S4U, in order to continue impersonating user and running the client process. This would be all good if the client process would not try to create new SQL connections to Server3. However, if the process, now running under S4U2Self protocol, attempts to make a new SQL connection using Kerberos protocol, it will fail unless protocol transition is also allowed.

Setting T2A4D flag for svc will result in S4U ticket receiving forwardable flag

#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

as noted here, and everything now works!

Upvotes: 0

Related Questions