Skip to content

Commit

Permalink
Load elasticsearch auth token from file (jaegertracing#1319)
Browse files Browse the repository at this point in the history
* Load elasticsearch auth token from file

Signed-off-by: Pavol Loffay <ploffay@redhat.com>

* Wrap errors

Signed-off-by: Pavol Loffay <ploffay@redhat.com>

* Fix lint

Signed-off-by: Pavol Loffay <ploffay@redhat.com>

* Fix test

Signed-off-by: Pavol Loffay <ploffay@redhat.com>
  • Loading branch information
pavolloffay authored and iori-yja committed Feb 15, 2019
1 parent bcd425d commit 01392f1
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 5 deletions.
50 changes: 49 additions & 1 deletion pkg/es/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"crypto/x509"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
"sync"
"time"

Expand All @@ -38,6 +40,7 @@ type Configuration struct {
Servers []string
Username string
Password string
TokenFilePath string
Sniffer bool // https://github.com/olivere/elastic/wiki/Sniffing
MaxNumSpans int // defines maximum number of spans to fetch from storage per query
MaxSpanAge time.Duration `yaml:"max_span_age"` // configures the maximum lookback on span reads
Expand Down Expand Up @@ -76,6 +79,7 @@ type ClientBuilder interface {
GetAllTagsAsFields() bool
GetTagDotReplacement() string
GetUseReadWriteAliases() bool
GetTokenFilePath() string
}

// NewClient creates a new ElasticSearch client
Expand Down Expand Up @@ -224,6 +228,11 @@ func (c *Configuration) GetUseReadWriteAliases() bool {
return c.UseReadWriteAliases
}

// GetTokenFilePath returns file path containing the bearer token
func (c *Configuration) GetTokenFilePath() string {
return c.TokenFilePath
}

// getConfigOptions wraps the configs to feed to the ElasticSearch client init
func (c *Configuration) getConfigOptions() ([]elastic.ClientOptionFunc, error) {
options := []elastic.ClientOptionFunc{elastic.SetURL(c.Servers...), elastic.SetSniff(c.Sniffer)}
Expand All @@ -240,7 +249,27 @@ func (c *Configuration) getConfigOptions() ([]elastic.ClientOptionFunc, error) {
TLSClientConfig: ctlsConfig,
}
} else {
options = append(options, elastic.SetBasicAuth(c.Username, c.Password))
if c.TokenFilePath != "" {
token, err := loadToken(c.TokenFilePath)
if err != nil {
return nil, err
}
wrapped := &http.Transport{}
if c.TLS.CaPath != "" {
ctls := &TLSConfig{CaPath: c.TLS.CaPath}
ca, err := ctls.loadCertificate()
if err != nil {
return nil, err
}
wrapped.TLSClientConfig = &tls.Config{RootCAs: ca}
}
httpClient.Transport = &tokenAuthTransport{
token: token,
wrapped: wrapped,
}
} else {
options = append(options, elastic.SetBasicAuth(c.Username, c.Password))
}
}
return options, nil
}
Expand Down Expand Up @@ -281,3 +310,22 @@ func (tlsConfig *TLSConfig) loadPrivateKey() (*tls.Certificate, error) {
}
return &privateKey, nil
}

// TokenAuthTransport
type tokenAuthTransport struct {
token string
wrapped *http.Transport
}

func (tr *tokenAuthTransport) RoundTrip(r *http.Request) (*http.Response, error) {
r.Header.Set("Authorization", "Bearer "+tr.token)
return tr.wrapped.RoundTrip(r)
}

func loadToken(path string) (string, error) {
b, err := ioutil.ReadFile(filepath.Clean(path))
if err != nil {
return "", err
}
return strings.TrimRight(string(b), "\r\n"), nil
}
5 changes: 3 additions & 2 deletions plugin/storage/es/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"path/filepath"
"strings"

"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/uber/jaeger-lib/metrics"
"go.uber.org/zap"
Expand Down Expand Up @@ -77,12 +78,12 @@ func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger,

primaryClient, err := f.primaryConfig.NewClient(logger, metricsFactory)
if err != nil {
return err
return errors.Wrap(err, "failed to create primary Elasticsearch client")
}
f.primaryClient = primaryClient
archiveClient, err := f.archiveConfig.NewClient(logger, metricsFactory)
if err != nil {
return err
return errors.Wrap(err, "failed to create archive Elasticsearch client")
}
f.archiveClient = archiveClient
return nil
Expand Down
4 changes: 2 additions & 2 deletions plugin/storage/es/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ func TestElasticsearchFactory(t *testing.T) {
// after InitFromViper, f.primaryConfig points to a real session builder that will fail in unit tests,
// so we override it with a mock.
f.primaryConfig = &mockClientBuilder{err: errors.New("made-up error")}
assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop(), healthcheck.GetNullStatusReporter()), "made-up error")
assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop(), healthcheck.GetNullStatusReporter()), "failed to create primary Elasticsearch client: made-up error")

f.primaryConfig = &mockClientBuilder{}
f.archiveConfig = &mockClientBuilder{err: errors.New("made-up error2")}
assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop(), healthcheck.GetNullStatusReporter()), "made-up error2")
assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop(), healthcheck.GetNullStatusReporter()), "failed to create archive Elasticsearch client: made-up error2")

f.archiveConfig = &mockClientBuilder{}
assert.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop(), healthcheck.GetNullStatusReporter()))
Expand Down
6 changes: 6 additions & 0 deletions plugin/storage/es/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
suffixUsername = ".username"
suffixPassword = ".password"
suffixSniffer = ".sniffer"
suffixTokenPath = ".token-file"
suffixServerURLs = ".server-urls"
suffixMaxSpanAge = ".max-span-age"
suffixMaxNumSpans = ".max-num-spans"
Expand Down Expand Up @@ -119,6 +120,10 @@ func addFlags(flagSet *flag.FlagSet, nsConfig *namespaceConfig) {
nsConfig.namespace+suffixPassword,
nsConfig.Password,
"The password required by ElasticSearch")
flagSet.String(
nsConfig.namespace+suffixTokenPath,
nsConfig.TokenFilePath,
"Path to a file containing bearer token. This flag also uses CA if it is specified")
flagSet.Bool(
nsConfig.namespace+suffixSniffer,
nsConfig.Sniffer,
Expand Down Expand Up @@ -217,6 +222,7 @@ func (opt *Options) InitFromViper(v *viper.Viper) {
func initFromViper(cfg *namespaceConfig, v *viper.Viper) {
cfg.Username = v.GetString(cfg.namespace + suffixUsername)
cfg.Password = v.GetString(cfg.namespace + suffixPassword)
cfg.TokenFilePath = v.GetString(cfg.namespace + suffixTokenPath)
cfg.Sniffer = v.GetBool(cfg.namespace + suffixSniffer)
cfg.servers = stripWhiteSpace(v.GetString(cfg.namespace + suffixServerURLs))
cfg.MaxSpanAge = v.GetDuration(cfg.namespace + suffixMaxSpanAge)
Expand Down
2 changes: 2 additions & 0 deletions plugin/storage/es/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func TestOptionsWithFlags(t *testing.T) {
"--es.server-urls=1.1.1.1, 2.2.2.2",
"--es.username=hello",
"--es.password=world",
"--es.token-file=/foo/bar",
"--es.sniffer=true",
"--es.max-span-age=48h",
"--es.num-shards=20",
Expand All @@ -60,6 +61,7 @@ func TestOptionsWithFlags(t *testing.T) {

primary := opts.GetPrimary()
assert.Equal(t, "hello", primary.Username)
assert.Equal(t, "/foo/bar", primary.TokenFilePath)
assert.Equal(t, []string{"1.1.1.1", "2.2.2.2"}, primary.Servers)
assert.Equal(t, 48*time.Hour, primary.MaxSpanAge)
assert.True(t, primary.Sniffer)
Expand Down

0 comments on commit 01392f1

Please sign in to comment.