Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use Kerberos ticket cache on Linux? #468

Open
sliekens opened this issue Oct 10, 2023 · 14 comments
Open

How to use Kerberos ticket cache on Linux? #468

sliekens opened this issue Oct 10, 2023 · 14 comments
Labels
enhancement New feature or request Security
Milestone

Comments

@sliekens
Copy link

Hello,

I want to use Kerberos on Debian 11 to authenticate with SQL Server but I'm struggling to get sqlcmd to catch on with what I'm trying to accomplish.

$ sqlcmd -E -S redacted\\inst01 --driver-logging-level=64
DRIVER:Dialing with protocol tcp
DRIVER:Returning connection from protocol tcp
DRIVER:got token tokenError
DRIVER:got ERROR 18456 Login failed for user ''.
DRIVER:got token tokenDone
DRIVER:got DONE or DONEPROC status=2
mssql: login error: Login failed for user ''.
mssql: login error: Login failed for user ''.

I have krb5-user and krb5-conf packages installed.

I logged in with kinit before running sqlcmd, which created a ticket cache in /tmp/krb5cc as is evident when I run klist.

$ klist
Ticket cache: FILE:/tmp/krb5cc
Default principal: redacteduser@REDACTED.DOMAIN

Valid starting       Expires              Service principal
10/10/2023 13:53:59  10/10/2023 23:53:59  krbtgt/REDACTED.DOMAIN@REDACTED.DOMAIN
        renew until 10/17/2023 13:53:55

Is it possible integrated authentication was just not implemented for Linux? I couldn't find any references to krb5conffile or krbcache in the code (which I believe is what the driver expects according to microsoft/go-mssqldb#35).

@shueybubbles
Copy link
Collaborator

sqlcmd hasn't yet added krb5 support.
I wasn't particularly happy with the go-mssqldb implementation, as it requires the application to provide some parameters explicitly instead of just working with defaults .
I don't have ready access to an environment to test changes either.

What do you think the sqlcmd command line should look like on Linux for proper krb5 support ? Passing individual file paths and settings on a command line is tedious at best, and we don't have very many short flags left.
I'd lean toward using environment variables to set the paths, like KRB5_CONFIG which is defined in the krb5 standard. We can modify sqlcmd first to consume the variables then eventually move it into the driver.

@sliekens
Copy link
Author

@shueybubbles Thanks for confirming. I browsed some of the older discussions and I also think environment variables are the best way to go, in addition to checking default locations like /etc/krb5.conf when the variables are undefined.

I personally don't mind not having a sqlcmd flag, the ability to set the environment per invocation fulfils all my needs

KRB5_CONFIG=krb1.conf sqlcmd -S server1 ...

@shueybubbles
Copy link
Collaborator

the other required parameter for the driver is krb5-realm.
I propose sqlcmd would extract the realm from the user name when you have it fully qualified, ie -U myuser@MYREALM.COM would have the user name as myuser and the realm as MYREALM.COM

If KRB5_CONFIG environment variable is set, sqlcmd will use the krb5 auth from the driver.
I am updating the driver soon to use that variable too.

I don't know how to deal with the cache path in a simple way. The MIT Kerberos environment variables described at https://web.mit.edu/kerberos/krb5-1.12/doc/mitK5defaults.html#mitk5defaults don't make sense to me re: specifying path to a cache file. How would I translate KRB5CACHEDIR to the full name of a cache file? Can I just assume the cache file is named krb5cc ?

@shueybubbles
Copy link
Collaborator

I guess the cache file would have to be set like KRBCCNAME=FILE:/tmp/myfile
I think the jcmturner package that was chosen for the implementation is rather limited since it doesn't work with directories for the cache instead of a file.
vmware says KRBCCNAME can also be set just like a regular file path https://docs.vmware.com/en/VMware-Greenplum/7/greenplum-database/admin_guide-kerberos-win-client.html

I will update the driver to check for KRBCCNAME env variable and use it "as is"

@sliekens
Copy link
Author

I propose sqlcmd would extract the realm from the user name when you have it fully qualified, ie -U myuser@MYREALM.COM would have the user name as myuser and the realm as MYREALM.COM

That seems right, with a fallback to default_realm from the krb5.conf.

I guess the cache file would have to be set like KRBCCNAME=FILE:/tmp/myfile

The best explanation I could find:

The default credential cache name is determined by the following, in descending order of priority:

  • The KRB5CCNAME environment variable. For example, KRB5CCNAME=DIR:/mydir/.
  • The default_ccache_name profile variable in [libdefaults].
  • The hardcoded default, DEFCCNAME.
    • FILE:/tmp/krb5cc_%{uid}

Source https://web.mit.edu/kerberos/krb5-1.12/doc/basic/ccache_def.html#default-ccache-name

@shueybubbles
Copy link
Collaborator

I am reluctant to have the driver directly load or parse krb5.conf to get the defaults

@sliekens
Copy link
Author

I propose sqlcmd would extract the realm from the user name when you have it fully qualified, ie -U myuser@MYREALM.COM would have the user name as myuser and the realm as MYREALM.COM

Actually I'm having second thoughts about this, that's not how SQLCMD based on ODBC works. You run it without -U/-P and then it automatically uses the credential cache with whatever default principal is present. Useful in scripting where you don't want to pass around the principal name and just use the integrated auth.

@sliekens
Copy link
Author

sliekens commented Oct 12, 2023

I wasn't particularly happy with the go-mssqldb implementation, as it requires the application to provide some parameters explicitly instead of just working with defaults .

I am reluctant to have the driver directly load or parse krb5.conf to get the defaults

I might be reading the code wrong (I never used Go) but doesn't gokrb5 already contain all the bits to parse the krb5.conf?

https://github.com/jcmturner/gokrb5/blob/855dbc707a37a21467aef6c0245fcf3328dc39ed/config/krb5conf.go#L166-L167

And it's already used in go-msqldb, for example here
https://github.com/microsoft/go-mssqldb/blob/e51fa150588f719f052ab5b715cc595f94088bc3/integratedauth/krb5/krb5.go#L278

@shueybubbles
Copy link
Collaborator

yeah looking closer I think the main issue is the go-mssqldb change that happened originally could have just tried to load the config from the default location and used it directly if no krb-specific parameters are set.

When I first peeked at the jcmturner package, I didn't see any references to the environment variables though.

I don't have a TON of time to spend on this, so I think i will just get the minimum going for now. Once the current driver PR goes through, I can update sqlcmd to use it and sqlcmd will set krb authentication if KRB5_CONFIG variable is set.

@sliekens
Copy link
Author

Sounds reasonable. 👍

One thing that I found curious is that the driver can handle Kerberos logins with a password or keytab file. I only expected to find support for the credential cache. Contacting the KDC server is usually handled out-of-band like a in a cronjob, isn't it? I don't believe the old SQLCMD supported anything but the credential cache?

@shueybubbles
Copy link
Collaborator

I am far from an expert here.
One question I have is which key tab file to use - DefaultClientKeytabName or DefaultKeyTabName. It kinda feels like it depends on what kind of application is running.
Sqlcmd would probably use a client keytab, correct?

@sliekens
Copy link
Author

I think you are correct. Based on information in https://web.mit.edu/kerberos/krb5-1.12/doc/basic/keytab_def.html

And
https://web.mit.edu/kerberos/krb5-1.11/doc/appdev/gssapi.html#initiator-credentials

The Client keytab is used to obtain tickets.

The other keytab would be used in server applications to decrypt the tickets of inbound users.

@sliekens
Copy link
Author

Also just to make sure, did you take notice of my previous #468 (comment) about having to pass a -U with integrated auth? I think it may got lost in the noise.

@shueybubbles
Copy link
Collaborator

I am still a while away from getting to this implementation. My hope is to allow integrated auth with krb5 to "just work" with sqlcmd from the end user perspective, but I will have to work within the limitations of the go-mssqldb implementation. It might be that if you want to force it to use the cache you need to set an environment variable; I'm not 100% clear on the final result yet.

@dlevy-msft dlevy-msft added the enhancement New feature or request label Nov 28, 2023
@dlevy-msft dlevy-msft added this to the Backlog milestone Nov 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Security
Projects
None yet
Development

No branches or pull requests

3 participants