-
Notifications
You must be signed in to change notification settings - Fork 840
Add SASL support #134
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 SASL support #134
Conversation
error.go
Outdated
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.
Add details too?
conn.go
Outdated
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.
Consider return some an error if error message is set too? Should we add the message to kafka.Error (currently just an int)?
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 we change the type of kafka.Error it's likely that a lot of code is going to break. The best I can think of is introducing an error type which exposes both the error value and the message and that program can test against.
frekui
left a 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.
Please let me know if there is anything I can help out with to move this forward. I have added some comments to the PR.
Before I knew this PR existed I started to add support for SASL myself. I used github.com/xdg/scram for the SCRAM code, but it's probably a good idea to make kafka-go independent of any SASL implementation as done in this PR.
|
@frekui thanks, I will clean up the code and ping the maintainers. I assume they want integration tests too, so I will have to look at that too. |
|
Regarding integration tests, currently Kafka 0.11.0.1 is used in the tests. That version doesn't have support for SaslHandshakeRequest v1, only v0 is supported. When v0 is used for the handshake the serialization of SaslAuthenticate must be changed. With v1 the usual Kafka protocol message headers are used, but with v0 a simpler encapsulation is used see http://kafka.apache.org/protocol.html#sasl_handshake for details (however the documentation fails to mention that each message is prefixed with its length encoded as a big-end 4-byte integer, see https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/security/authenticator/SaslServerAuthenticator.java#L245). |
Add support for SASL authentication by allowing the user to set the SASLClient field on the kafka.Dialer struct. The user must provide its own implementation of kafka.SASLClient because there is currently no SASL library for Go with support for all the implementations Kafka supports, and this will allow kafka-go to support more SASL mechanisms without changing the core library. The tests have been updated to test PLAIN authentication against a live server. The implementation has also been tested using SCRAM-SHA-256 and SCRAM-SHA-512, against 0.11.0.3 and 2.0.1. This commit introduces four new calls agains kafka, which will only be used if SASLClient is set: - ApiVersionsRequest v1 - SaslHandshakeRequest v0 and v1 - SaslAuthenticateRequestV0 - Raw SASL packets For more information about the authentication sequence, please see https://kafka.apache.org/protocol#sasl_handshake TODO: For Kerberos and SCRAM-SHA-256-PLUS support the interface methods for kafka.SASLClient might need to be extended. Example using github.com/xdg/scram to implement SCRAM-SHA-512: import ( "context" "crypto/sha512" "hash" "log" kafka "github.com/segmentio/kafka-go" "github.com/xdg/scram" ) var SHA512 scram.HashGeneratorFcn = func() hash.Hash { return sha512.New() } type SCRAMClient struct { client *scram.ClientConversation } func (s *SCRAMClient) Mechanism() string { return "SCRAM-SHA-512" } func (s *SCRAMClient) Start(ctx context.Context) ([]byte, error) { str, err := s.client.Step("") return []byte(str), err } func (s *SCRAMClient) Next(ctx context.Context, challenge []byte) (bool, []byte, error) { str, err := s.client.Step(string(challenge)) return s.client.Done(), []byte(str), err } func main() { scramClient, err := SHA512.NewClient("adminscram", "admin-secret", "") if err != nil { log.Fatal(err) } r := kafka.NewReader(kafka.ReaderConfig{ Dialer: &kafka.Dialer{ SASLClient: func() kafka.SASLClient { return &SCRAMClient{scramClient.NewConversation()} }, }, Brokers: []string{"localhost:9094"}, Topic: "test-writer-1", })
|
I've updated the PR with integration tests and support for Kafka 0.11. Could someone take a look? @achille-roussel If we want
The interface might need changes. |
frekui
left a 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.
FWIW this looks good to me. I have tested it in my environment and it works. Good job @chlunde!
|
Hi @abraithwaite, I see you created the original ticket. Is there anything I can do to move this forward? |
conn.go
Outdated
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 we change the type of kafka.Error it's likely that a lot of code is going to break. The best I can think of is introducing an error type which exposes both the error value and the message and that program can test against.
|
|
||
| // The SASLClient interface is used to enable plugging in different | ||
| // SASL implementations at compile time. | ||
| type SASLClient interface { |
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 do you think about using the same interface than go-sasl here? https://godoc.org/github.com/emersion/go-sasl#Client
It could help to promote interoperability instead of requiring programs to provide a shim to bridge the two interfaces.
|
@chlunde what changes would need to be made to support the other features you mentioned? |
|
I've tested this with consumer groups, it seems to be hanging/getting stuck at :
CODE : |
|
@sirajmansour you may have to rebase this branch on master to make sure you're not running in the bug we fixed in #143 If you want to provide a dump of your stack trace that could help identify the issue as well. |
|
@achille-roussel i can confirm this works after rebasing on master 👍 |
|
Any news on this? It would be really nice to support SASL in Go finally :) |
|
@chlunde do you think you'll be able to take this to completion? Otherwise I think we can hand this change to another contributor to get it finished. |
|
From what I understand, the PR works well and only need changes if we want to add the kerberos and negotiation features. This can probably be done in another PR. I know for sure that several companies (including mine) really need this SASL support a soon as possible. If I can make anything in order to help, please tell me. |
|
@achille-roussel Sorry, I don't know when I will have time to look at this again, at least not this week, so if someone has time it would be awesome if they could help. I think the interface in https://godoc.org/mellium.im/sasl#Option looks most extensible, it can support SASL-SCRAM-..-PLUS, and probably kerberos in the future, without a breaking API change. Negotiation support might require a breaking change in the main library, if I remember correctly it would require a "probe" connection to find the supported mechanisms, or reconnecting during the normal connection flow. @SamWhited is mellium.im/sasl stable? |
SCRAM-*-PLUS is implemented in the main package of course, and I believe there was a fork that added Kerberos support floating around somewhere, but it would also be easily possible to create a new package with a Kerberos mechanism, it really doesn't need to be in the main library. Extensibility is actually a bit of a problem right now, but that's something I need to rethink and see if it can be made better (see below).
I'm not sure how Kafka handles auth, but I don't see why this would be the case. Basically everything has to probe for the supported mechanisms first, you just do that before creating the state machine used for auth; it doesn't need to be part of the actual SASL library. For example, I use this library with XMPP and all the protocol specific stuff like probing for mechanisms happens out of band. Feel free to ping me to discuss though if I'm missing something and the current API doesn't meet your needs.
TL;DR — Soon maybe, but probably not right this moment, sorry. Now that Go Modules is a thing I'm more inclined to tag a stable release (since there is a clear path to upgrading if something happens that breaks the API). There are a few design decisions I want to rethink first though (suggestions welcome) such as whether the API should be based on If you're interested in discussing any of this or how we can make the package meet your needs better, please ping me via email or the Jabber network; my address is |
|
Thanks for the great work and discussion so far! I'm really excited to be helping to shepherd this PR into kafka-go. First off, a couple of exciting things have happened since this PR was initially opened:
I think that the best course of action from here would be to merge
Knowing that we have future work in mind, it would be great to do some up-front work to prepare for adding more mechanisms. I think that means a) getting the configuration, packaging, and interface correct, and b) setting up good, re-usable testing. I've broken down feedback/asks into groups below: PackagingOne goal that we have with kafka-go is to minimize the number of external dependencies. If you take the compression code as an example, you can see that a client of the kafka-go only needs to import compression codecs (and their associated dependencies) that they actually use. Having done a survey of the Go SASL libraries, I don't think there's going to be a single one that's going to work for all mechanisms present and future. We'll probably end up using different libs for different mechanisms, which underscores the importance of packaging as a means to avoid bloat. InterfaceI read the SASL RFC, and did a survey of the Go SASL libraries, and the interface I liked best was the one @achille-roussel linked: https://godoc.org/github.com/emersion/go-sasl#Client. I propose we adopt that one. However, I prefer the interface name to be With SASL mechanisms in their own packages, you can export constructors , e.g. ConfigI would like to see configuration options on the SCRAMAFAICT, Kafka only supports TestingI'd like to see two test functions: one that takes a I know this is a lot of feedback, but fortunately the code is already most of the way there. I think that if we do this little bit more work now that it's going to pay off big time by enabling us to add more SASL mechanisms later without bloating kafka-go or having to make backward incompatible changes. Thanks again for your work so far, and let me know if I can help in any way! |
|
@chlunde I wanted to check in to see if you were still working on this PR. If not, would you mind if I picked it up and finished it off? Thanks! |
|
Thanks for getting started here! We picked it up and incorporated it into #223. |
|
@stevevls sorry, I missed your message, and as you assumed I don't have any extra time now. Thanks a lot for picking this up again! |
The kafka-go reader doesn't support SASL for know: segmentio/kafka-go#134
Add support for SASL authentication by allowing the user to set the
SASLClient field on the kafka.Dialer struct.
The user must provide its own implementation of kafka.SASLClient because
there is currently no SASL library for Go with support for all the
implementations Kafka supports, and this will allow kafka-go to support
more SASL mechanisms without changing the core library.
The tests have been updated to test PLAIN authentication against a live
server. The implementation has also been tested using SCRAM-SHA-256
and SCRAM-SHA-512, against 0.11.0.3 and 2.0.1.
This commit introduces four new calls agains kafka, which will only be
used if SASLClient is set:
For more information about the authentication sequence, please see
https://kafka.apache.org/protocol#sasl_handshake
TODO: For Kerberos and SCRAM-SHA-256-PLUS support the interface methods
for kafka.SASLClient might need to be extended.
Example using github.com/xdg/scram to implement SCRAM-SHA-512:
Updates #109