godap icon indicating copy to clipboard operation
godap copied to clipboard

Kerberos incompatibilities

Open grawity opened this issue 1 year ago • 8 comments

  1. In standard Kerberos implementations (e.g. MIT Kerberos, Heimdal Kerberos) KRB5CCNAME generally defaults to FILE:/tmp/krb5cc_<uid> (although a different default may be set via krb5.conf). Currently godap assumes an empty string by default.

    $ ~/go/bin/godap -k ldap.nullroute.lt
    2024/11/11 18:43:52 open : no such file or directory
    
  2. In standard Kerberos implementations KRB5CCNAME is typically in the form of type:value, with an implied default of FILE: for the type. That is, while KRB5CCNAME="/tmp/cache" is valid, so is KRB5CCNAME="FILE:/tmp/cache", and most software (such as sshd or pam_krb5) uses the latter format, which godap currently does not accept.

    $ klist
    Ticket cache: FILE:/tmp/krb5cc_1000
    
    $ export KRB5CCNAME="FILE:/tmp/krb5cc_1000"
    
    $ ldapwhoami -Q -Y GSSAPI -H ldap://ldap.nullroute.lt
    dn:uid=grawity,cn=gssapi,cn=auth
    
    $ ~/go/bin/godap -k ldap.nullroute.lt
    2024/11/11 18:44:28 open FILE:/tmp/krb5cc_1000: no such file or directory
    
  3. The KDC is not looked up via SRV records, but specifying it manually doesn't seem to work either:

    $ export KRB5CCNAME="/tmp/krb5cc_1000"
    
    $ ~/go/bin/godap -k ldap.nullroute.lt
    2024/11/11 18:46:26 [Root cause: Networking_Error] Networking_Error: TGS Exchange
    Error: issue sending TGS_REQ to KDC: communication error with KDC via TCP: no
    KDCs defined in configuration for realm NULLROUTE.LT
    
    $ ~/go/bin/godap -k --kdc star.nullroute.lt ldap.nullroute.lt
    2024/11/11 18:46:26 [Root cause: Networking_Error] Networking_Error: TGS Exchange
    Error: issue sending TGS_REQ to KDC: communication error with KDC via TCP: no
    KDCs defined in configuration for realm NULLROUTE.LT
    

grawity avatar Nov 11 '24 16:11 grawity

Hello @grawity, thanks for the raising the issue.

  1. Specifying the KRB5CCNAME explicitly is currently the "easiest" way because godap must be cross-platform, and I'm not aware of a good way to infer a "common default path" in a way that works for Linux, Windows & MacOS. If you know a better way to do it I'm totally open to suggestions - Kerberos is not really my area of expertise and most of the Kerberos code here is basically a "hack" that I wrote over a couple of weeks just to get it working for Active Directory.
  2. Godap doesn't parse prefixes like FILE: in the KRB5CCNAME variable; we should make this fact clear in the docs, or raise an error if the user specifies a prefix (I'll do that in the next release). For godap KRB5CCNAME is just a raw path to the CCACHE file.
  3. Looking up the KDC from the domain is a good suggestion and I'll do it in the next release too, but I don't understand the error you had. What's the backend you're using? Is it OpenLDAP?

Macmod avatar Nov 12 '24 03:11 Macmod

One thing that I noticed is that you didn't specify the domain name nullroute.lt with -d, so that field (which is used to fill the realm in the Kerberos config) was probably empty in the call to lc.KerbBindWithCCache. Maybe that was the issue?

Macmod avatar Nov 12 '24 03:11 Macmod

Specifying the KRB5CCNAME explicitly is currently the "easiest" way because godap must be cross-platform, and I'm not aware of a good way to infer a "common default path" in a way that works for Linux, Windows & MacOS. If you know a better way to do it I'm totally open to suggestions - Kerberos is not really my area of expertise and most of the Kerberos code here is basically a "hack" that I wrote over a couple of weeks just to get it working for Active Directory.

Right, it gets a bit complex with macOS, and I guess it should be the job of go-krb5 to determine the actual default (as it already supports reading /etc/krb5.conf anyway). Though /tmp/krb5cc_<uid> is the traditional Unix default, so still perhaps better than nothing (especially if go-krb5 only supports file-based caches and won't be able to support the macOS default API cache anyway...)

Unfortunately go-krb5 seems a bit unmaintained these days.

For Windows there is no default path, and not even any tools to create such a path – programs are meant to use SSPI (e.g. alexbrainman/sspi) and don't have any direct access to the cache. One would have to install MIT Kerberos or Java to get any sort of file-based cache.

Godap doesn't parse prefixes like FILE: in the KRB5CCNAME variable; we should make this fact clear in the docs, or raise an error if the user specifies a prefix (I'll do that in the next release). For godap KRB5CCNAME is just a raw path to the CCACHE file.

Yeah, that's exactly the 'incompatibility' problem I was talking about – it has to parse the type prefix because KRB5CCNAME often already comes "from outside", e.g. it may be set by the OS when the user logs in to the system with an AD or Kerberos account, or when the user SSH's into the system with Kerberos ticket delegation enabled... In other words there's a pre-existing format for it.

So if KRB5CCNAME is used then the code should at least accept and trim the "FILE:" prefix specifically (and I guess warn about other unsupported types)... If not, then IMO it's better to ignore KRB5CCNAME entirely and use an option like --cache for the path.

Looking up the KDC from the domain is a good suggestion and I'll do it in the next release too, but I don't understand the error you had. What's the backend you're using? Is it OpenLDAP?

It's OpenLDAP + MIT Kerberos, but I see the program doesn't even start talking to the LDAP server.

One thing that I noticed is that you didn't specify the domain name nullroute.lt with -d, so that field (which is used to fill the realm in the Kerberos config) was probably empty in the call to lc.KerbBindWithCCache. Maybe that was the issue?

It might be (will test once I get back home). The error message implied that it already knows the realm, so it didn't occur to me that -d was needed.

grawity avatar Nov 12 '24 07:11 grawity

Hello @grawity,

Did it work for you with -d?

I'm still thinking about the possibilities here for the next release, but I'll make sure to include some of your suggestions (you made solid points).

Macmod avatar Dec 03 '24 00:12 Macmod

I also ran into similar issues.

File-based ccaches are not used as much as they used to be due to security concerns. I can mainly speak to Linux, where KEYRING caches are usually the default in modern Linux distros. I was able to work around this by creating a ccache file.

kinit -c krb5cc user

Though, it may be better to lock it down a bit with

knit -F -l 1h -r 1h -c krb5cc user

More information of the types of credential caches can be found in the MIT docs.

This still didn't let me authenticate. I had to add -t ldap/domain_controler.domain -d domain. These could definitely be looked up in DNS.

So my full command looked like this:

KRB5CCNAME=krb5cc godap -k -t ldap/domain_controler.domain -d domain domain

At least I was able to try out godap and it looks very useful!

I know this stuff is squirrelly. Is there any way to hand the Kerberos work off to the system libraries?

avylove avatar Feb 23 '25 19:02 avylove

Is there any way to hand the Kerberos work off to the system libraries?

For Linux, https://github.com/openshift/gssapi would do that; unfortunately it's very unmaintained. (Though the GSS-API interface hasn't changed much, so bindings don't need much maintenance – after all, the security-sensitive code lives elsewhere – but still.)

(The other "Golang GSS-API" project I found seems to be a pure Golang implementation, I've not dug deep into its quality or compatibility with MIT Kerberos.)

grawity avatar Feb 24 '25 09:02 grawity

Thanks for the contributions @grawity @avylove. The DNS resolution behavior will be implemented in v2.10.5, but I'll keep this issue open until we find a good solution for the more complete ccache handling behavior.

Macmod avatar Mar 01 '25 19:03 Macmod

Just to let everyone know, some time has passed since my last comment, and I decided to implement some other improvements before these changes. Since we're a little behind in the releases I'll release v2.10.5 now and incorporate improvements regarding the DNS lookups later.

I'm looking into using https://github.com/RedTeamPentesting/adauth, which is an implementation of several authentication mechanisms for AD, with more interesting features than the regular go-ldap library, and with some of these lookups built-in. If that happens, I'll make sure to simplify the code and the command-line and assert that it works for non-AD backends too, but since this can be an important change I'll have to run many tests before continuing.

Macmod avatar Jun 02 '25 20:06 Macmod