diff --git a/config/config.go b/config/config.go index 2be3524d1..eeb2c72d5 100644 --- a/config/config.go +++ b/config/config.go @@ -626,22 +626,6 @@ type MarathonSDConfig struct { XXX map[string]interface{} `yaml:",inline"` } -// KubernetesSDConfig is the configuration for Kubernetes service discovery. -type KubernetesSDConfig struct { - Masters []URL `yaml:"masters"` - KubeletPort int `yaml:"kubelet_port,omitempty"` - InCluster bool `yaml:"in_cluster,omitempty"` - BearerTokenFile string `yaml:"bearer_token_file,omitempty"` - Username string `yaml:"username,omitempty"` - Password string `yaml:"password,omitempty"` - RetryInterval Duration `yaml:"retry_interval,omitempty"` - RequestTimeout Duration `yaml:"request_timeout,omitempty"` - TLSConfig TLSConfig `yaml:"tls_config,omitempty"` - - // Catches all undefined fields and must be empty after parsing. - XXX map[string]interface{} `yaml:",inline"` -} - // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *MarathonSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { *c = DefaultMarathonSDConfig @@ -657,6 +641,22 @@ func (c *MarathonSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) erro return checkOverflow(c.XXX, "marathon_sd_config") } +// KubernetesSDConfig is the configuration for Kubernetes service discovery. +type KubernetesSDConfig struct { + Masters []URL `yaml:"masters"` + KubeletPort int `yaml:"kubelet_port,omitempty"` + InCluster bool `yaml:"in_cluster,omitempty"` + BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"` + BearerToken string `yaml:"bearer_token,omitempty"` + BearerTokenFile string `yaml:"bearer_token_file,omitempty"` + RetryInterval Duration `yaml:"retry_interval,omitempty"` + RequestTimeout Duration `yaml:"request_timeout,omitempty"` + TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + + // Catches all undefined fields and must be empty after parsing. + XXX map[string]interface{} `yaml:",inline"` +} + // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *KubernetesSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { *c = DefaultKubernetesSDConfig @@ -668,6 +668,12 @@ func (c *KubernetesSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) er if len(c.Masters) == 0 { return fmt.Errorf("Kubernetes SD configuration requires at least one Kubernetes master") } + if len(c.BearerToken) > 0 && len(c.BearerTokenFile) > 0 { + return fmt.Errorf("at most one of bearer_token & bearer_token_file must be configured") + } + if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) { + return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") + } return checkOverflow(c.XXX, "kubernetes_sd_config") } diff --git a/config/config_test.go b/config/config_test.go index 28324c97a..a6a03b42a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -203,9 +203,11 @@ var expectedConf = &Config{ KubernetesSDConfigs: []*KubernetesSDConfig{ { - Masters: []URL{kubernetesSDHostURL()}, - Username: "myusername", - Password: "mypassword", + Masters: []URL{kubernetesSDHostURL()}, + BasicAuth: &BasicAuth{ + Username: "myusername", + Password: "mypassword", + }, KubeletPort: 10255, RequestTimeout: Duration(10 * time.Second), RetryInterval: Duration(1 * time.Second), @@ -324,6 +326,12 @@ var expectedErrors = []struct { }, { filename: "bearertoken_basicauth.bad.yml", errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured", + }, { + filename: "kubernetes_bearertoken.bad.yml", + errMsg: "at most one of bearer_token & bearer_token_file must be configured", + }, { + filename: "kubernetes_bearertoken_basicauth.bad.yml", + errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured", }, { filename: "marathon_no_servers.bad.yml", errMsg: "Marathon SD config must contain at least one Marathon server", diff --git a/config/testdata/conf.good.yml b/config/testdata/conf.good.yml index 783c75393..259b011c8 100644 --- a/config/testdata/conf.good.yml +++ b/config/testdata/conf.good.yml @@ -107,8 +107,10 @@ scrape_configs: kubernetes_sd_configs: - masters: - 'https://localhost:1234' - username: 'myusername' - password: 'mypassword' + + basic_auth: + username: 'myusername' + password: 'mypassword' - job_name: service-marathon marathon_sd_configs: diff --git a/config/testdata/kubernetes_bearertoken.bad.yml b/config/testdata/kubernetes_bearertoken.bad.yml new file mode 100644 index 000000000..15aa7aad2 --- /dev/null +++ b/config/testdata/kubernetes_bearertoken.bad.yml @@ -0,0 +1,10 @@ +scrape_configs: + - job_name: prometheus + + kubernetes_sd_configs: + - masters: + - 'https://localhost:1234' + + bearer_token: 1234 + bearer_token_file: somefile + diff --git a/config/testdata/kubernetes_bearertoken_basicauth.bad.yml b/config/testdata/kubernetes_bearertoken_basicauth.bad.yml new file mode 100644 index 000000000..f138d9e50 --- /dev/null +++ b/config/testdata/kubernetes_bearertoken_basicauth.bad.yml @@ -0,0 +1,12 @@ +scrape_configs: + - job_name: prometheus + + kubernetes_sd_configs: + - masters: + - 'https://localhost:1234' + + bearer_token: 1234 + basic_auth: + username: user + password: password + diff --git a/retrieval/discovery/kubernetes/discovery.go b/retrieval/discovery/kubernetes/discovery.go index c981c8ee8..903478f96 100644 --- a/retrieval/discovery/kubernetes/discovery.go +++ b/retrieval/discovery/kubernetes/discovery.go @@ -624,16 +624,22 @@ func newKubernetesHTTPClient(conf *config.KubernetesSDConfig) (*http.Client, err TLSClientConfig: tlsConfig, } - bearerToken, err := ioutil.ReadFile(bearerTokenFile) - if err != nil { - return nil, err + // If a bearer token is provided, create a round tripper that will set the + // Authorization header correctly on each request. + bearerToken := conf.BearerToken + if len(bearerToken) == 0 && len(bearerTokenFile) > 0 { + b, err := ioutil.ReadFile(bearerTokenFile) + if err != nil { + return nil, fmt.Errorf("unable to read bearer token file %s: %s", bearerTokenFile, err) + } + bearerToken = string(b) + } + if len(bearerToken) > 0 { + rt = httputil.NewBearerAuthRoundTripper(bearerToken, rt) } - if len(bearerToken) > 0 { - rt = httputil.NewBearerAuthRoundTripper(string(bearerToken), rt) - } - if len(conf.Username) > 0 && len(conf.Password) > 0 { - rt = httputil.NewBasicAuthRoundTripper(conf.Username, conf.Password, rt) + if conf.BasicAuth != nil { + rt = httputil.NewBasicAuthRoundTripper(conf.BasicAuth.Username, conf.BasicAuth.Password, rt) } return &http.Client{