-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
WIP - Adding scram authentication for kafka #2110
Changes from all commits
bc9e1b1
8c7033d
5ec140a
4cb4263
48a9ead
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,14 @@ const ( | |
|
||
defaultPlainTextUserName = "" | ||
defaultPlainTextPassword = "" | ||
|
||
// Scram configuration options | ||
scramPrefix = ".scram" | ||
suffixScramUserName = ".username" | ||
suffixScramAlgorithm = ".algorithm" | ||
suffixScramPassword = ".password" | ||
|
||
defaultScramAlgorithm = "sha512" | ||
) | ||
|
||
func addKerberosFlags(configPrefix string, flagSet *flag.FlagSet) { | ||
|
@@ -93,6 +101,21 @@ func addPlainTextFlags(configPrefix string, flagSet *flag.FlagSet) { | |
"The plaintext Password for SASL/PLAIN authentication") | ||
} | ||
|
||
func addScramFlags(configPrefix string, flagSet *flag.FlagSet) { | ||
flagSet.String( | ||
configPrefix+scramPrefix+suffixScramUserName, | ||
"", | ||
"Scram username used to authenticate with the client") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here as well |
||
flagSet.String( | ||
configPrefix+scramPrefix+suffixScramPassword, | ||
"", | ||
"Scram password used to authenticat with the client") | ||
flagSet.String( | ||
configPrefix+scramPrefix+suffixScramAlgorithm, | ||
defaultScramAlgorithm, | ||
"Scram algorithm, 'sha256' or 'sha512'") | ||
} | ||
|
||
// AddFlags add configuration flags to a flagSet. | ||
func AddFlags(configPrefix string, flagSet *flag.FlagSet) { | ||
flagSet.String( | ||
|
@@ -110,4 +133,5 @@ func AddFlags(configPrefix string, flagSet *flag.FlagSet) { | |
tlsClientConfig.AddFlags(flagSet) | ||
|
||
addPlainTextFlags(configPrefix, flagSet) | ||
addScramFlags(configPrefix, flagSet) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Copyright (c) 2020 The Jaeger Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package auth | ||
|
||
import ( | ||
"crypto/sha512" | ||
"fmt" | ||
"hash" | ||
|
||
"github.com/Shopify/sarama" | ||
scrampkg "github.com/xdg/scram" | ||
) | ||
|
||
// ScramConfig describes the configuration properties required for the SCRAM handshake | ||
// between the collector and the pipeline | ||
type ScramConfig struct { | ||
UserName string `mapstructure:"username"` | ||
Password string `mapstructure:"password"` | ||
Algorithm string `mapstructure:"algorithm"` | ||
} | ||
|
||
// SetSCRAMConfiguration ... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... ? :-) |
||
func setSCRAMConfiguration(config *ScramConfig, saramaConfig *sarama.Config) error { | ||
var fn func() sarama.SCRAMClient | ||
|
||
var mechanism sarama.SASLMechanism | ||
|
||
switch config.Algorithm { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Matter of taste I guess, but I think the version from this PR more readable: open-telemetry/opentelemetry-collector#2322 |
||
case "sha512": | ||
fn = func() sarama.SCRAMClient { | ||
return &scramClient{ | ||
HashGeneratorFcn: func() hash.Hash { return sha512.New() }, | ||
} | ||
} | ||
mechanism = sarama.SASLMechanism(sarama.SASLTypeSCRAMSHA512) | ||
case "sha256": | ||
fn = func() sarama.SCRAMClient { | ||
return &scramClient{ | ||
HashGeneratorFcn: scrampkg.SHA256, | ||
} | ||
} | ||
mechanism = sarama.SASLMechanism(sarama.SASLTypeSCRAMSHA256) | ||
default: | ||
return fmt.Errorf("invalid SHA algorithm '%s': can be either 'sha256' or 'sha512'", config.Algorithm) | ||
} | ||
saramaConfig.Net.SASL.SCRAMClientGeneratorFunc = fn | ||
saramaConfig.Net.SASL.Mechanism = mechanism | ||
saramaConfig.Net.SASL.Enable = true | ||
saramaConfig.Net.SASL.User = config.UserName | ||
saramaConfig.Net.SASL.Password = config.Password | ||
|
||
return nil | ||
} | ||
|
||
type scramClient struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment I had in the similar PR from OpenTelemetry: you should probably do a type assert here, ensuring that this is a |
||
*scrampkg.Client | ||
*scrampkg.ClientConversation | ||
scrampkg.HashGeneratorFcn | ||
} | ||
|
||
// Begin uses a username password and authid to generate a new client and instantiate a new conversation | ||
func (client *scramClient) Begin(userName, password, authzID string) (err error) { | ||
client.Client, err = client.HashGeneratorFcn.NewClient(userName, password, authzID) | ||
if err != nil { | ||
return fmt.Errorf("Begin method failed on: %s", err) | ||
} | ||
client.ClientConversation = client.Client.NewConversation() | ||
return nil | ||
} | ||
|
||
// Step takes a challenge string | ||
func (client *scramClient) Step(challenge string) (response string, err error) { | ||
response, err = client.ClientConversation.Step(challenge) | ||
if err != nil { | ||
return "", fmt.Errorf("Step method failed on: %s", err) | ||
|
||
} | ||
return response, nil | ||
} | ||
|
||
// Done returns a bool based on a completed conversation | ||
func (client *scramClient) Done() bool { | ||
return client.ClientConversation.Done() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) 2020 The Jaeger Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package auth_test | ||
|
||
import ( | ||
"flag" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/jaegertracing/jaeger/pkg/config" | ||
"github.com/jaegertracing/jaeger/pkg/kafka/auth" | ||
) | ||
|
||
func TestSCRAMClientFlags(t *testing.T) { | ||
|
||
addFlags := func(flagSet *flag.FlagSet) { | ||
flagSet.String("--kafka.scram.username", "fakeuser", "") | ||
flagSet.String("--kafka.scram.password", "fakepassword", "") | ||
flagSet.String("--kafka.scram.algorithm", "sha256", "") | ||
} | ||
|
||
v, _ := config.Viperize(addFlags) | ||
|
||
authCfg := auth.AuthenticationConfig{ | ||
Authentication: "scram", | ||
} | ||
|
||
authCfg.InitFromViper("--kafka", v) | ||
// check to see if the configs are the same | ||
assert.Equal(t, auth.ScramConfig{ | ||
UserName: "fakeuser", | ||
Password: "fakepassword", | ||
Algorithm: "sha256", | ||
}, authCfg.SCRAM) | ||
} | ||
|
||
// testing Begin, Step, and Done require a network connection to test, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it hard to mock this? |
||
// they otherwise will have a perpetual connection that cannot be closed |
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.
Not a huge fan of the convention, but Go rules state that acronyms should be all in caps, so,
SCRAM
everywhere in the next few lines.