PowerShell / Win32-OpenSSH

Win32 port of OpenSSH
7.2k stars 739 forks source link

ssh login with constrained kerberos delegation #2244

Open fvollmer opened 1 week ago

fvollmer commented 1 week ago

Summary of the new feature / enhancement

Currently, we use unconstrained Kerberos delegation for logging in and accessing network drives, which poses security concerns.

When attempting to switch to constrained Kerberos delegation, the error sspi delegation was requested but not fulfilled occurs, and no tickets are available on the host. It would be beneficial to utilize constrained Kerberos delegation.

This issue is related to #2214

Proposed technical implementation details (optional)

I think we want S4U2proxy. According to https://web.mit.edu/kerberos/krb5-1.20/doc/appdev/gssapi.html gss_acquire_cred_impersonate_name has to be used, which is similar to gss_acquire_cred, which is currently used.

jborean93 commented 6 days ago

Constrained delegation definitely works it just doesn't work like the normal GSSAPIDelegateCredentials option. This means the client doesn't explicitly opt into it, the service just needs to be configured. The S4UProxy call happens implicitly on the server side if you attempt to access a service that the constrained delegation allows for. For example the server2025$ principal is allowed to delegate to cifs/dc01.domain.test and klist.exe shows the retrieved ticket

jborean:~/dev$ ssh server2025.domain.test pwsh -Command 'gci \\dc01.domain.test\c$; klist'

    Directory: \\dc01.domain.test\c$

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----           8/06/2024  8:39 PM                PerfLogs
d-r--          16/06/2024  8:37 AM                Program Files
d-r--          15/06/2024 11:03 AM                Program Files (x86)
d----          16/06/2024  5:59 AM                temp
d-r--          16/06/2024  5:58 AM                Users
d----          20/06/2024  5:32 AM                Windows

Current LogonId is 0:0x356d42

Cached Tickets: (2)

#0>     Client: vagrant-domain @ DOMAIN.TEST
        Server: cifs/dc01.domain.test @ DOMAIN.TEST
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize 
        Start Time: 6/22/2024 23:45:16 (local)
        End Time:   6/23/2024 0:00:16 (local)
        Renew Time: 6/29/2024 23:45:15 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0 
        Kdc Called: DC01.domain.test

#1>     Client: vagrant-domain @ DOMAIN.TEST
        Server: host/server2025.domain.test @ DOMAIN.TEST
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40210000 -> forwardable pre_authent name_canonicalize 
        Start Time: 6/22/2024 23:42:44 (local)
        End Time:   6/23/2024 9:42:42 (local)
        Renew Time: 0
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x8 -> ASC 
        Kdc Called: 

One thing to note is that the client must request a TGT that is forwardable. It doesn't have to be explicitly forwarded (unconstrained delegation) but if on Linux/macOS it means using the -f flag with kinit or setting forwardable = true in the krb5.conf. For Windows clients this works like normal.

fvollmer commented 6 days ago

Great to know that this should be working.

I'm trying to ssh from a windows client to a linux server (ubuntu 24.04, OpenSSH_9.6p1 Ubuntu-3ubuntu13, OpenSSL 3.0.13 30 Jan 2024). Is there some special config setting that I need to enable? Or is constrained delegation not supported in this use case?

Unconstrained delegation works fine, but with constrained delegation I get no tickets:

ssh -K -v my.server.com
[...]
debug1: Next authentication method: gssapi-with-mic
debug1: Delegating credentials
debug1: sspi delegation was requested but not fulfilled
debug1: Delegating credentials
debug1: sspi delegation was requested but not fulfilled
debug1: Authentication succeeded (gssapi-with-mic).
[...]

klist
klist: No credentials cache found (filename: /tmp/krb5cc_<myuserid>)
jborean93 commented 5 days ago

Ah ok sorry I thought your target was a Windows host.

Unconstrained delegation works fine, but with constrained delegation I get no tickets:

This is the problem unfortunately, you have no ticket because you don't actually have a proper TGT that can be used to request a normal service ticket like unconstrained delegation does. With constrained delegation (S4UProxy) you use the service principals context to request the additional ticket based on the limited data provided by the client in the initial exchange.

Based on the great docs for MIT krb5 constrained delegation on GSSAPI looks like https://web.mit.edu/kerberos/krb5-devel/doc/appdev/gssapi.html#constrained-delegation-s4u

So while OpenSSH does seem to store the proxied credential it won't have this proxied credential because it's using GSS_C_ACCEPT rather than GSS_C_BOTH on the acceptor credential. The bigger issue though is doing the S4UProxy dance as the service principal SSH is running as. This means you need to either have access to the service's keytab (security risk) or have some sort of privileged broker that perform S4UProxy using the service principal's Kerberos context but with the provided proxy credential. Window's opted for the latter solution as the SMB request is done automatically for you but I'm not aware of a way to do this with SSH on Linux. Granted there may be a solution to this that I don't know off but unfortunately I just don't think it is possible right now outside of Windows as the target environment.