-
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
Enable IAM based auth to ES for AWS clients (#465) #1036
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,10 @@ import ( | |
"sync" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws/session" | ||
"github.com/aws/aws-sdk-go/aws/signer/v4" | ||
"github.com/pkg/errors" | ||
"github.com/sha1sum/aws_signing_client" | ||
"github.com/uber/jaeger-lib/metrics" | ||
"go.uber.org/zap" | ||
"gopkg.in/olivere/elastic.v5" | ||
|
@@ -42,6 +45,12 @@ type Configuration struct { | |
BulkActions int | ||
BulkFlushInterval time.Duration | ||
IndexPrefix string | ||
AwsIamConfig AwsIamConfiguration | ||
} | ||
|
||
// AwsIamConfiguration describes the AWS-specific configuration needed to connect to ElasticSearch with IAM authn | ||
type AwsIamConfiguration struct { | ||
Enabled bool | ||
} | ||
|
||
// ClientBuilder creates new es.Client | ||
|
@@ -58,7 +67,13 @@ func (c *Configuration) NewClient(logger *zap.Logger, metricsFactory metrics.Fac | |
if len(c.Servers) < 1 { | ||
return nil, errors.New("No servers specified") | ||
} | ||
rawClient, err := elastic.NewClient(c.GetConfigs()...) | ||
|
||
clientOptionFuncs, err := c.GetConfigs() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
rawClient, err := elastic.NewClient(clientOptionFuncs...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -143,6 +158,9 @@ func (c *Configuration) ApplyDefaults(source *Configuration) { | |
if c.BulkFlushInterval == 0 { | ||
c.BulkFlushInterval = source.BulkFlushInterval | ||
} | ||
if !c.AwsIamConfig.Enabled { | ||
c.AwsIamConfig.Enabled = source.AwsIamConfig.Enabled | ||
} | ||
} | ||
|
||
// GetNumShards returns number of shards from Configuration | ||
|
@@ -166,10 +184,26 @@ func (c *Configuration) GetIndexPrefix() string { | |
} | ||
|
||
// GetConfigs wraps the configs to feed to the ElasticSearch client init | ||
func (c *Configuration) GetConfigs() []elastic.ClientOptionFunc { | ||
func (c *Configuration) GetConfigs() ([]elastic.ClientOptionFunc, error) { | ||
options := make([]elastic.ClientOptionFunc, 3) | ||
options[0] = elastic.SetURL(c.Servers...) | ||
options[1] = elastic.SetBasicAuth(c.Username, c.Password) | ||
options[2] = elastic.SetSniff(c.Sniffer) | ||
return options | ||
|
||
// if AWS IAM is enabled, instantiate the elastic client with a signing client created via the AWS SDK | ||
if c.AwsIamConfig.Enabled { | ||
sess, err := session.NewSession() | ||
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. why is a live session needed here? Looks like you're only accessing Config from it. |
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
signer := v4.NewSigner(sess.Config.Credentials) | ||
awsSigningClient, err := aws_signing_client.New(signer, nil, "es", *sess.Config.Region) | ||
if err != nil { | ||
return nil, err | ||
} | ||
options = append(options, elastic.SetHttpClient(awsSigningClient)) | ||
} | ||
|
||
return options, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ const ( | |
suffixBulkActions = ".bulk.actions" | ||
suffixBulkFlushInterval = ".bulk.flush-interval" | ||
suffixIndexPrefix = ".index-prefix" | ||
suffixAwsIamEnabled = ".aws.iam_enabled" | ||
) | ||
|
||
// TODO this should be moved next to config.Configuration struct (maybe ./flags package) | ||
|
@@ -75,6 +76,9 @@ func NewOptions(primaryNamespace string, otherNamespaces ...string) *Options { | |
BulkWorkers: 1, | ||
BulkActions: 1000, | ||
BulkFlushInterval: time.Millisecond * 200, | ||
AwsIamConfig: config.AwsIamConfiguration{ | ||
Enabled: false, | ||
}, | ||
}, | ||
servers: "http://127.0.0.1:9200", | ||
namespace: primaryNamespace, | ||
|
@@ -146,6 +150,10 @@ func addFlags(flagSet *flag.FlagSet, nsConfig *namespaceConfig) { | |
nsConfig.namespace+suffixIndexPrefix, | ||
nsConfig.IndexPrefix, | ||
"Optional prefix of Jaeger indices. For example \"production\" creates \"production:jaeger-*\".") | ||
flagSet.Bool( | ||
nsConfig.namespace+suffixAwsIamEnabled, | ||
nsConfig.AwsIamConfig.Enabled, | ||
"Whether to connect to AWS ElasticSearch with IAM authentication. Requires the proper .aws/ files to be setup to connect.") | ||
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. should there be an option with the directory name of these aws files? Relying on the working directory seems brittle. 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. Yeah, agreed. I think I'm actually leaning back to preferring that clients explicitly pass in the credential values that we require, rather than implicitly loading them from a file. Furthermore, see discussion #465 (comment) as to why we can't actually directly use the session created from such file. I can go back to accepting the appropriate credential params. cc @jmwaniki 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. Before I push over theses changes, here's the commit that has the params explicitly passed in, that I'm now in favor in. Mind taking a peak at that? wesleyk@b3eb1a1 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. @wesleyk I have a solution I've been testing that forces the credentials to be refreshed before expiring and it's worked for 2 days without a problem. That solution involves using the ec2RoleCreds Thanks! 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. Heads up, I was out for a bit. Will take a closer look at this sometime this week! Also, @jmwaniki feel free to push out another change if you have something locally. |
||
} | ||
|
||
// InitFromViper initializes Options with properties from viper | ||
|
@@ -169,6 +177,7 @@ func initFromViper(cfg *namespaceConfig, v *viper.Viper) { | |
cfg.BulkActions = v.GetInt(cfg.namespace + suffixBulkActions) | ||
cfg.BulkFlushInterval = v.GetDuration(cfg.namespace + suffixBulkFlushInterval) | ||
cfg.IndexPrefix = v.GetString(cfg.namespace + suffixIndexPrefix) | ||
cfg.AwsIamConfig.Enabled = v.GetBool(cfg.namespace + suffixAwsIamEnabled) | ||
} | ||
|
||
// GetPrimary returns primary configuration. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,11 +33,13 @@ func TestOptions(t *testing.T) { | |
assert.Equal(t, int64(1), primary.NumReplicas) | ||
assert.Equal(t, 72*time.Hour, primary.MaxSpanAge) | ||
assert.False(t, primary.Sniffer) | ||
assert.Equal(t, false, primary.AwsIamConfig.Enabled) | ||
|
||
aux := opts.Get("archive") | ||
assert.Equal(t, primary.Username, aux.Username) | ||
assert.Equal(t, primary.Password, aux.Password) | ||
assert.Equal(t, primary.Servers, aux.Servers) | ||
assert.Equal(t, primary.AwsIamConfig, aux.AwsIamConfig) | ||
} | ||
|
||
func TestOptionsWithFlags(t *testing.T) { | ||
|
@@ -50,7 +52,7 @@ func TestOptionsWithFlags(t *testing.T) { | |
"--es.sniffer=true", | ||
"--es.max-span-age=48h", | ||
"--es.num-shards=20", | ||
"--es.num-replicas=10", | ||
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. why is this one removed? 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. My bad, reverting! |
||
"--es.aws.iam_enabled=true", | ||
// a couple overrides | ||
"--es.aux.server-urls=3.3.3.3,4.4.4.4", | ||
"--es.aux.max-span-age=24h", | ||
|
@@ -62,6 +64,7 @@ func TestOptionsWithFlags(t *testing.T) { | |
assert.Equal(t, "hello", primary.Username) | ||
assert.Equal(t, []string{"1.1.1.1", "2.2.2.2"}, primary.Servers) | ||
assert.Equal(t, 48*time.Hour, primary.MaxSpanAge) | ||
assert.Equal(t, true, primary.AwsIamConfig.Enabled) | ||
assert.True(t, primary.Sniffer) | ||
|
||
aux := opts.Get("es.aux") | ||
|
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 need to consult our lawyers if embedding crypto capability creates an export issue for Jaeger binaries.