go-sqlcmd
go-sqlcmd copied to clipboard
How to use Kerberos ticket cache on Linux?
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: [email protected]
Valid starting Expires Service principal
10/10/2023 13:53:59 10/10/2023 23:53:59 krbtgt/[email protected]
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 https://github.com/microsoft/go-mssqldb/pull/35).
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.
@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 ...
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 [email protected] 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 ?
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"
I propose sqlcmd would extract the realm from the user name when you have it fully qualified, ie
-U [email protected]would have the user name asmyuserand the realm asMYREALM.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
I am reluctant to have the driver directly load or parse krb5.conf to get the defaults
I propose sqlcmd would extract the realm from the user name when you have it fully qualified, ie
-U [email protected]would have the user name asmyuserand the realm asMYREALM.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.
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
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.
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?
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?
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.
Also just to make sure, did you take notice of my previous https://github.com/microsoft/go-sqlcmd/issues/468#issuecomment-1760394919 about having to pass a -U with integrated auth? I think it may got lost in the noise.
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.
Hi folks. Does anyone know if this has progressed any further? Looking to auth using integrated security and kinit in Linux.
Thanks,
Dunno but in general there have been no new commits in 4 months, and not for lack of work items, so I guess this project is kind of dead.