-
Notifications
You must be signed in to change notification settings - Fork 66
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
add Kerberos auth #35
Conversation
Can you separate the krb5 code into non-Windows .go files and stub the implementation in a Windows .go file so Windows apps don't need to pick up this code? In reply to: 1184565905 |
@dzsquared @chandanjainn @stuartpa the krb code requires go 1.13 and higher. In reply to: 1190471174 |
apologies for the late response @shueybubbles working on this. the only issue at my end is lack of a windows system to test out the changes. In reply to: 1191093407 |
* add windows stub for krb * add import for msdsn * fix ci lint issue Co-authored-by: chandan jain <Chandan.Jain@ocean.ibm.com>
@shueybubbles have added the stub file for windows so that krb is not added as a dependency for windows based systems. In reply to: 1213081795 |
you can also add a In reply to: 1214441216 |
* remove krb dep for windows * remove krb dep * unit test coverage Co-authored-by: chandan jain <Chandan.Jain@ocean.ibm.com>
@shueybubbles done with the suggested changes. please review |
Hi. There appear to be some logic issues and opportunities for more thorough error checking here. For instance, I'm attempting to connect using a keytab. I dont supply a KrbCache param in the connection string, which I believe is valid and correct. However the code panics inside auth.go func getKrbParams in the dereference of :
Aside from the unchecked type assertion, the function as a whole enforces the connection string contain both a KrbCache and KeytabFile parameter. Their use should be mutually exclusive. The conn string is user supplied and as such can be mangled entirely, a sensible error message should tell the caller of the issue. Also I dont believe there is currently a way to connect using specified username and password on the connection string. e.g. something like We use the methodology in certain scenarios where distribution of key keytab files across a server estate would prohibitive. When initially investigating use of keytabs we found that if a domain account password is somehow locked out or the password becomes changed, even changing the password back to it's original value will not make the currently existing keytabs valid again. New keytabs must the created and distributed to all servers. Some services are sufficiently critical that they must be able to re connect in the face of malicious action or similar, even if the acc in question is set to |
@PeteBassettBet365 have fixed all unchecked assertion based issues by using structs everywhere and made cache and keytab mutually exclusive with proper error messages. All of this was was there in the earlier commits but got lost while removing the dependencies for windows system in the last couple of commits. Regarding the ability to connect using username and password, am not sure what you are expecting here? Why would we use password in the connection string along with kerberos config? if you see the code at https://github.com/microsoft/go-mssqldb/pull/35/files#diff-1f48700829d7e0cdba7f3729d6a7c1c5df3aa11f2aeeed583c7e1e39aa7b66d1R21 , it falls back to username/password based authN given that the user is not sending any krb related config in the conn string and if the user does we'll get relevant errors thrown. |
Hi again @chandanjainn thanks for sorting the few issues! Sorry, I'm not talking about sqlserver auth fallback, this is kerberos auth. The reason I'd like to support supplying the kerberos username and password is because, for certain use cases as I said previously, it is easier/faster than distribution of new keytabs to servers. github.com/jcmturner/gokrb5/v8/client supports this via NewWithPassword |
Codecov Report
@@ Coverage Diff @@
## main #35 +/- ##
==========================================
+ Coverage 73.08% 73.25% +0.16%
==========================================
Files 25 25
Lines 5458 5458
==========================================
+ Hits 3989 3998 +9
+ Misses 1230 1224 -6
+ Partials 239 236 -3
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
AuthProviderFunc integratedauth.Provider = integratedauth.ProviderFunc(getAuth) | ||
) | ||
|
||
func init() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If my app includes this package, and my connection string doesn't specify a specific authenticator for integrated auth, will it use this authenticator with some default setting ?
IE, I'd like my connection string to be the same on Windows as Linux.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this init also do:
integratedAuth.DefaultProviderName = "krb5"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shueybubbles this comment by Pete should answer your question https://github.com/microsoft/go-mssqldb/blob/main/integratedauth/auth.go#L23
yes, it will fallback to default provider i.e ntlm
for unix and winsspi
for windows if the authenticator is not provided in the connection string.
refer https://github.com/microsoft/go-mssqldb/blob/main/auth_windows.go#L17 and https://github.com/microsoft/go-mssqldb/blob/main/auth_unix.go#L14
And for your second question, no I dont think so we should do integratedAuth.DefaultProviderName = "krb5"
as this is meant to be a fallback.
@PeteBassettBet365 this is correct right?
@@ -59,6 +60,31 @@ Other supported formats are listed below. | |||
* `Workstation ID` - The workstation name (default is the host name) | |||
* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. The `database` must be specified when connecting with `Application Intent` set to `ReadOnly`. | |||
|
|||
### Kerberos Active Directory authentication outside Windows | |||
The package supports authentication via 3 methods. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the default approach used if the connection string doesn't specify one explicitly? If a keytab file exists in some default location will it be used without having to specify it in the connection string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shueybubbles as of now, no. The user needs to explicitly specify the locations for keytab/cache.
A default location can be added. Should we?
Refer this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the MIT doc itself says to put it in /etc by default, or set environment variable KRB5_CONFIG. Couldn't we just rely on those too? I'm a bit surprised the jcmturner/gokrb5 module isn't already doing that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect someone to be able to set the kerberos environment variables https://web.mit.edu/kerberos/krb5-1.12/doc/admin/env_variables.html and not have to put them all explicitly in the connection string here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read https://github.com/jcmturner/gokrb5/blob/master/config/krb5conf.go and have a recommendation for a fallback model for the kr5b.conf file location.
- Specified in the connection string
- Check KRB5_CONFIG environment variable
- Check for /etc/krb5.conf
- just use config.NewConfig()
If the user doesn't specify paths to keytab or cache, they probably can rely on the defaults defined in krb5.conf.
If there's no krb5.conf file in a default location or the environment variables aren't set, the authentication will fail but that's by design.
Does this seem reasonable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shueybubbles yes, it does. will make the changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx I think trying to follow the MIT spec will help developers. If jcmturner/go-krb5
isn't following the spec for environment variables and defaults, you should open some issues against that module to do so.
@@ -28,6 +28,7 @@ Other supported formats are listed below. | |||
* `false` - Data sent between client and server is not encrypted beyond the login packet. (Default) | |||
* `true` - Data sent between client and server is encrypted. | |||
* `app name` - The application name (default is go-mssqldb) | |||
* `authenticator` - Can be used to specify use of a registered authentication provider. (e.g. ntlm, winsspi (on windows) or krb5 (on linux)) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I don't set a specific authenticator, can the integratedAuth code in the core try to connect using the default provider first, then fall back to any other registered providers ?
This is the scenario:
- My service has a single connection string of a server name with no user name.
- The client apps run on both Linux and Windows hosts
- My preproduction environment Linux only has NTLM while production has krb5
If my client app imports the krb5 package will the runtime behavior correctly use SSPI on Windows, krb5 in prod, and ntlm in preprod?
If my connection string does have an authenticator tag then I'd expect it to fail to connect if that method isn't available or is mis-configured on the host.
If the connection string doesn't have an authenticator tag, I'd expect to have a predictable behavior based on what is available on the host at runtime and not have to create separate connection strings for every possible environment.
} | ||
} | ||
if c["krbcache"] == "" && c["keytabfile"] == "" { | ||
missingParam = "atleast krbcache or keytab is required" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there no default location for these files or a default behavior that can be determined based on looking for krb5.conf in a well-known location ?
By contrast it seems most of these parameters are optional in the JDBC SQL driver.
https://docs.microsoft.com/en-us/sql/connect/jdbc/using-kerberos-integrated-authentication-to-connect-to-sql-server?view=sql-server-ver16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, there's a default location for keytab and krbcache at /etc/krb5/ and /tmp/krb5cc_%{uid} respectively.
the reason we didn't look there in the first place was so that the user will be aware of the exact keytab file being used just in case their system has multiple keytabs.
do we want to check this location in case the user hasnt provided one ? can add this support.
README.md
Outdated
### Kerberos Parameters | ||
|
||
* `krb5conffile` - path to kerberos configuration file. | ||
* `realm` - Domain name for kerberos authentication. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JDBC driver docs have "realm" as optional
https://docs.microsoft.com/sql/connect/jdbc/setting-the-connection-properties?view=sql-server-ver16
(Version 9.4+) The realm for Kerberos authentication. Set this value to override the Kerberos authentication realm the driver autodetects from the server's realm.
Do you know what it means by "autodetects from the server's realm"? Is that a feature in JDBC we are missing here? Or is it something handled in the krb module itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will check up on the JDBC part and revert. I hope, I have answered rest of your questions?
I'd like to see my questions about how apps will need to manage integrated auth connection strings, protocol fallback behavior, etc answered in the README.md at least so it's clear what the limitations are about connection string reuse across Windows and Linux for integrated auth. |
Activity on this has stalled - what do we need to do to get this moving again ? @shueybubbles - Have all your points been addressed ? @chandanjainn - @PeteBassettBet365 is available to assist with any blockers. |
@LessTravelledWay @shueybubbles apologies for the late response here. I have been on a medical leave for some time and will need some more time to recover fully. Can we get the current PR merged as a V1 and then take up the suggestions as enhancement in future releases? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi. I would add one point, I think the server name needs to be canonicalized with a call to |
Should we merge this as-is then @PeteBassettBet365 could follow up with any tweaks after testing? I don't have a working kerberos Linux setup to test with. In reply to: 1274962421 |
Understood. I can give it a test this end. |
@chandanjainn @shueybubbles Hi. There are some bugs to be addressed here. Raw Credentials dont work as the validateKerbConfig function https://github.com/microsoft/go-mssqldb/blob/main/integratedauth/krb5/krb5.go#L224 Example conn string: If I bypass that validation issue then the ServerSpn parsing code fails to handle .co.uk domains e.g. "server.domain.co.uk" will result in a domain of "server.domain.co" Also, the Realm field If I bypass that I get further errors regarding KDC issues. I will check this further. This is not ready for a tag. |
@chandanjainn @shueybubbles Further issues. DisablePAFXFAST is required in the Password and CredentialCache paths The serverSPN needs to be canonicalized before the call to GetServiceTicket https://github.com/microsoft/go-mssqldb/pull/35/files#diff-043475ad621581173830d43c2fd895aa7455acd099e156fb045eda996146f6f9R152 |
Have added support for kerberos authentication for go-mssqldb using the GOKRB5 package.
To enable the support for krb the users need to pass the connection string as the following
server=server;user id=user;port=1345;realm=domain;trustservercertificate=true;krb5conffile=/etc/krb5.conf;keytabfile=/path/to/keytabFile.keytab
"server=server;port=1345;realm=domain;trustservercertificate=true;krb5conffile=/etc/krb5.conf;krbcache=/tmp/krb5cc_1000"