From 58839cefb50e56ae5b157b37e9814ae83ceee70b Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 20 Jul 2017 15:22:49 -0700 Subject: Upgrading server dependancies (#6984) --- .../github.com/prometheus/common/config/config.go | 17 ++ .../prometheus/common/config/http_config.go | 279 +++++++++++++++++++++ .../prometheus/common/config/http_config_test.go | 157 ++++++++++++ .../http.conf.bearer-token-and-file-set.bad.yml | 5 + .../common/config/testdata/http.conf.empty.bad.yml | 4 + .../common/config/testdata/http.conf.good.yml | 4 + .../http.conf.invalid-bearer-token-file.bad.yml | 1 + .../prometheus/common/config/tls_config.go | 79 ------ .../prometheus/common/config/tls_config_test.go | 4 +- 9 files changed, 469 insertions(+), 81 deletions(-) create mode 100644 vendor/github.com/prometheus/common/config/http_config.go create mode 100644 vendor/github.com/prometheus/common/config/http_config_test.go create mode 100644 vendor/github.com/prometheus/common/config/testdata/http.conf.bearer-token-and-file-set.bad.yml create mode 100644 vendor/github.com/prometheus/common/config/testdata/http.conf.empty.bad.yml create mode 100644 vendor/github.com/prometheus/common/config/testdata/http.conf.good.yml create mode 100644 vendor/github.com/prometheus/common/config/testdata/http.conf.invalid-bearer-token-file.bad.yml delete mode 100644 vendor/github.com/prometheus/common/config/tls_config.go (limited to 'vendor/github.com/prometheus/common/config') diff --git a/vendor/github.com/prometheus/common/config/config.go b/vendor/github.com/prometheus/common/config/config.go index 33eb922ce..9195c34bf 100644 --- a/vendor/github.com/prometheus/common/config/config.go +++ b/vendor/github.com/prometheus/common/config/config.go @@ -28,3 +28,20 @@ func checkOverflow(m map[string]interface{}, ctx string) error { } return nil } + +// Secret special type for storing secrets. +type Secret string + +// MarshalYAML implements the yaml.Marshaler interface for Secrets. +func (s Secret) MarshalYAML() (interface{}, error) { + if s != "" { + return "", nil + } + return nil, nil +} + +//UnmarshalYAML implements the yaml.Unmarshaler interface for Secrets. +func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error { + type plain Secret + return unmarshal((*plain)(s)) +} diff --git a/vendor/github.com/prometheus/common/config/http_config.go b/vendor/github.com/prometheus/common/config/http_config.go new file mode 100644 index 000000000..ff5837fa5 --- /dev/null +++ b/vendor/github.com/prometheus/common/config/http_config.go @@ -0,0 +1,279 @@ +// Copyright 2016 The Prometheus 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 config + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + yaml "gopkg.in/yaml.v2" +) + +// BasicAuth contains basic HTTP authentication credentials. +type BasicAuth struct { + Username string `yaml:"username"` + Password Secret `yaml:"password"` + + // Catches all undefined fields and must be empty after parsing. + XXX map[string]interface{} `yaml:",inline"` +} + +// URL is a custom URL type that allows validation at configuration load time. +type URL struct { + *url.URL +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface for URLs. +func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + + urlp, err := url.Parse(s) + if err != nil { + return err + } + u.URL = urlp + return nil +} + +// MarshalYAML implements the yaml.Marshaler interface for URLs. +func (u URL) MarshalYAML() (interface{}, error) { + if u.URL != nil { + return u.String(), nil + } + return nil, nil +} + +// HTTPClientConfig configures an HTTP client. +type HTTPClientConfig struct { + // The HTTP basic authentication credentials for the targets. + BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"` + // The bearer token for the targets. + BearerToken Secret `yaml:"bearer_token,omitempty"` + // The bearer token file for the targets. + BearerTokenFile string `yaml:"bearer_token_file,omitempty"` + // HTTP proxy server to use to connect to the targets. + ProxyURL URL `yaml:"proxy_url,omitempty"` + // TLSConfig to use to connect to the targets. + TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + + // Catches all undefined fields and must be empty after parsing. + XXX map[string]interface{} `yaml:",inline"` +} + +func (c *HTTPClientConfig) validate() error { + 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 nil +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface +func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + type plain HTTPClientConfig + err := unmarshal((*plain)(c)) + if err != nil { + return err + } + err = c.validate() + if err != nil { + return c.validate() + } + return checkOverflow(c.XXX, "http_client_config") +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error { + type plain BasicAuth + err := unmarshal((*plain)(a)) + if err != nil { + return err + } + return checkOverflow(a.XXX, "basic_auth") +} + +// NewHTTPClientFromConfig returns a new HTTP client configured for the +// given config.HTTPClientConfig. +func NewHTTPClientFromConfig(cfg *HTTPClientConfig) (*http.Client, error) { + tlsConfig, err := NewTLSConfig(&cfg.TLSConfig) + if err != nil { + return nil, err + } + + // It's the caller's job to handle timeouts + var rt http.RoundTripper = &http.Transport{ + Proxy: http.ProxyURL(cfg.ProxyURL.URL), + DisableKeepAlives: true, + TLSClientConfig: tlsConfig, + } + + // If a bearer token is provided, create a round tripper that will set the + // Authorization header correctly on each request. + bearerToken := cfg.BearerToken + if len(bearerToken) == 0 && len(cfg.BearerTokenFile) > 0 { + b, err := ioutil.ReadFile(cfg.BearerTokenFile) + if err != nil { + return nil, fmt.Errorf("unable to read bearer token file %s: %s", cfg.BearerTokenFile, err) + } + bearerToken = Secret(strings.TrimSpace(string(b))) + } + + if len(bearerToken) > 0 { + rt = NewBearerAuthRoundTripper(bearerToken, rt) + } + + if cfg.BasicAuth != nil { + rt = NewBasicAuthRoundTripper(cfg.BasicAuth.Username, Secret(cfg.BasicAuth.Password), rt) + } + + // Return a new client with the configured round tripper. + return &http.Client{Transport: rt}, nil +} + +type bearerAuthRoundTripper struct { + bearerToken Secret + rt http.RoundTripper +} + +type basicAuthRoundTripper struct { + username string + password Secret + rt http.RoundTripper +} + +// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a request unless it has +// already been set. +func NewBasicAuthRoundTripper(username string, password Secret, rt http.RoundTripper) http.RoundTripper { + return &basicAuthRoundTripper{username, password, rt} +} + +func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Authorization")) == 0 { + req = cloneRequest(req) + req.Header.Set("Authorization", "Bearer "+string(rt.bearerToken)) + } + + return rt.rt.RoundTrip(req) +} + +// NewBearerAuthRoundTripper adds the provided bearer token to a request unless the authorization +// header has already been set. +func NewBearerAuthRoundTripper(bearer Secret, rt http.RoundTripper) http.RoundTripper { + return &bearerAuthRoundTripper{bearer, rt} +} + +func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Authorization")) != 0 { + return rt.RoundTrip(req) + } + req = cloneRequest(req) + req.SetBasicAuth(rt.username, string(rt.password)) + return rt.rt.RoundTrip(req) +} + +// cloneRequest returns a clone of the provided *http.Request. +// The clone is a shallow copy of the struct and its Header map. +func cloneRequest(r *http.Request) *http.Request { + // Shallow copy of the struct. + r2 := new(http.Request) + *r2 = *r + // Deep copy of the Header. + r2.Header = make(http.Header) + for k, s := range r.Header { + r2.Header[k] = s + } + return r2 +} + +// NewTLSConfig creates a new tls.Config from the given config.TLSConfig. +func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { + tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify} + + // If a CA cert is provided then let's read it in so we can validate the + // scrape target's certificate properly. + if len(cfg.CAFile) > 0 { + caCertPool := x509.NewCertPool() + // Load CA cert. + caCert, err := ioutil.ReadFile(cfg.CAFile) + if err != nil { + return nil, fmt.Errorf("unable to use specified CA cert %s: %s", cfg.CAFile, err) + } + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig.RootCAs = caCertPool + } + + if len(cfg.ServerName) > 0 { + tlsConfig.ServerName = cfg.ServerName + } + + // If a client cert & key is provided then configure TLS config accordingly. + if len(cfg.CertFile) > 0 && len(cfg.KeyFile) == 0 { + return nil, fmt.Errorf("client cert file %q specified without client key file", cfg.CertFile) + } else if len(cfg.KeyFile) > 0 && len(cfg.CertFile) == 0 { + return nil, fmt.Errorf("client key file %q specified without client cert file", cfg.KeyFile) + } else if len(cfg.CertFile) > 0 && len(cfg.KeyFile) > 0 { + cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile) + if err != nil { + return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", cfg.CertFile, cfg.KeyFile, err) + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + tlsConfig.BuildNameToCertificate() + + return tlsConfig, nil +} + +// TLSConfig configures the options for TLS connections. +type TLSConfig struct { + // The CA cert to use for the targets. + CAFile string `yaml:"ca_file,omitempty"` + // The client cert file for the targets. + CertFile string `yaml:"cert_file,omitempty"` + // The client key file for the targets. + KeyFile string `yaml:"key_file,omitempty"` + // Used to verify the hostname for the targets. + ServerName string `yaml:"server_name,omitempty"` + // Disable target certificate validation. + InsecureSkipVerify bool `yaml:"insecure_skip_verify"` + + // Catches all undefined fields and must be empty after parsing. + XXX map[string]interface{} `yaml:",inline"` +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + type plain TLSConfig + if err := unmarshal((*plain)(c)); err != nil { + return err + } + return checkOverflow(c.XXX, "TLS config") +} + +func (c HTTPClientConfig) String() string { + b, err := yaml.Marshal(c) + if err != nil { + return fmt.Sprintf("", err) + } + return string(b) +} diff --git a/vendor/github.com/prometheus/common/config/http_config_test.go b/vendor/github.com/prometheus/common/config/http_config_test.go new file mode 100644 index 000000000..1e2490bbb --- /dev/null +++ b/vendor/github.com/prometheus/common/config/http_config_test.go @@ -0,0 +1,157 @@ +// Copyright 2015 The Prometheus 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 config + +import ( + "io/ioutil" + "net/http" + "net/url" + "strings" + "testing" + + yaml "gopkg.in/yaml.v2" +) + +var invalidHTTPClientConfigs = []struct { + httpClientConfigFile string + errMsg string +}{ + { + httpClientConfigFile: "testdata/http.conf.bearer-token-and-file-set.bad.yml", + errMsg: "at most one of bearer_token & bearer_token_file must be configured", + }, + { + httpClientConfigFile: "testdata/http.conf.empty.bad.yml", + errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured", + }, +} + +func TestAuthRoundTrippers(t *testing.T) { + + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") + if err != nil { + t.Errorf("Error loading HTTP client config: %v", err) + } + + tlsConfig, err := NewTLSConfig(&cfg.TLSConfig) + if err != nil { + t.Errorf("Error creating new TLS config: %v", err) + } + + rt := &http.Transport{ + Proxy: http.ProxyURL(cfg.ProxyURL.URL), + DisableKeepAlives: true, + TLSClientConfig: tlsConfig, + } + req := new(http.Request) + + bearerAuthRoundTripper := NewBearerAuthRoundTripper("mysecret", rt) + bearerAuthRoundTripper.RoundTrip(req) + + basicAuthRoundTripper := NewBasicAuthRoundTripper("username", "password", rt) + basicAuthRoundTripper.RoundTrip(req) +} + +func TestHideHTTPClientConfigSecrets(t *testing.T) { + c, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") + if err != nil { + t.Errorf("Error parsing %s: %s", "testdata/http.conf.good.yml", err) + } + + // String method must not reveal authentication credentials. + s := c.String() + if strings.Contains(s, "mysecret") { + t.Fatal("http client config's String method reveals authentication credentials.") + } +} + +func mustParseURL(u string) *URL { + parsed, err := url.Parse(u) + if err != nil { + panic(err) + } + return &URL{URL: parsed} +} + +func TestNewClientFromConfig(t *testing.T) { + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") + if err != nil { + t.Errorf("Error loading HTTP client config: %v", err) + } + _, err = NewHTTPClientFromConfig(cfg) + if err != nil { + t.Errorf("Error creating new client from config: %v", err) + } +} + +func TestNewClientFromInvalidConfig(t *testing.T) { + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.invalid-bearer-token-file.bad.yml") + if err != nil { + t.Errorf("Error loading HTTP client config: %v", err) + } + _, err = NewHTTPClientFromConfig(cfg) + if err == nil { + t.Error("Expected error creating new client from invalid config but got none") + } + if !strings.Contains(err.Error(), "unable to read bearer token file file: open file: no such file or directory") { + t.Errorf("Expected error with config but got: %s", err.Error()) + } +} + +func TestValidateHTTPConfig(t *testing.T) { + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") + if err != nil { + t.Errorf("Error loading HTTP client config: %v", err) + } + err = cfg.validate() + if err != nil { + t.Fatalf("Error validating %s: %s", "testdata/http.conf.good.yml", err) + } +} + +func TestInvalidHTTPConfigs(t *testing.T) { + for _, ee := range invalidHTTPClientConfigs { + _, _, err := LoadHTTPConfigFile(ee.httpClientConfigFile) + if err == nil { + t.Error("Expected error with config but got none") + continue + } + if !strings.Contains(err.Error(), ee.errMsg) { + t.Errorf("Expected error for invalid HTTP client configuration to contain %q but got: %s", ee.errMsg, err) + } + } +} + +// LoadHTTPConfig parses the YAML input s into a HTTPClientConfig. +func LoadHTTPConfig(s string) (*HTTPClientConfig, error) { + cfg := &HTTPClientConfig{} + err := yaml.Unmarshal([]byte(s), cfg) + if err != nil { + return nil, err + } + return cfg, nil +} + +// LoadHTTPConfigFile parses the given YAML file into a HTTPClientConfig. +func LoadHTTPConfigFile(filename string) (*HTTPClientConfig, []byte, error) { + content, err := ioutil.ReadFile(filename) + if err != nil { + return nil, nil, err + } + cfg, err := LoadHTTPConfig(string(content)) + if err != nil { + return nil, nil, err + } + return cfg, content, nil +} diff --git a/vendor/github.com/prometheus/common/config/testdata/http.conf.bearer-token-and-file-set.bad.yml b/vendor/github.com/prometheus/common/config/testdata/http.conf.bearer-token-and-file-set.bad.yml new file mode 100644 index 000000000..c613bacb0 --- /dev/null +++ b/vendor/github.com/prometheus/common/config/testdata/http.conf.bearer-token-and-file-set.bad.yml @@ -0,0 +1,5 @@ +basic_auth: + username: username + password: "mysecret" +bearer_token: mysecret +bearer_token_file: file diff --git a/vendor/github.com/prometheus/common/config/testdata/http.conf.empty.bad.yml b/vendor/github.com/prometheus/common/config/testdata/http.conf.empty.bad.yml new file mode 100644 index 000000000..ea2811f7c --- /dev/null +++ b/vendor/github.com/prometheus/common/config/testdata/http.conf.empty.bad.yml @@ -0,0 +1,4 @@ +basic_auth: + username: username + password: mysecret +bearer_token_file: file diff --git a/vendor/github.com/prometheus/common/config/testdata/http.conf.good.yml b/vendor/github.com/prometheus/common/config/testdata/http.conf.good.yml new file mode 100644 index 000000000..46ca63908 --- /dev/null +++ b/vendor/github.com/prometheus/common/config/testdata/http.conf.good.yml @@ -0,0 +1,4 @@ +basic_auth: + username: username + password: "mysecret" +proxy_url: "http://remote.host" diff --git a/vendor/github.com/prometheus/common/config/testdata/http.conf.invalid-bearer-token-file.bad.yml b/vendor/github.com/prometheus/common/config/testdata/http.conf.invalid-bearer-token-file.bad.yml new file mode 100644 index 000000000..4b1349bf4 --- /dev/null +++ b/vendor/github.com/prometheus/common/config/testdata/http.conf.invalid-bearer-token-file.bad.yml @@ -0,0 +1 @@ +bearer_token_file: file diff --git a/vendor/github.com/prometheus/common/config/tls_config.go b/vendor/github.com/prometheus/common/config/tls_config.go deleted file mode 100644 index 7c7e7cb02..000000000 --- a/vendor/github.com/prometheus/common/config/tls_config.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 The Prometheus 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 config - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" -) - -// TLSConfig configures the options for TLS connections. -type TLSConfig struct { - // The CA cert to use for the targets. - CAFile string `yaml:"ca_file,omitempty"` - // The client cert file for the targets. - CertFile string `yaml:"cert_file,omitempty"` - // The client key file for the targets. - KeyFile string `yaml:"key_file,omitempty"` - // Disable target certificate validation. - InsecureSkipVerify bool `yaml:"insecure_skip_verify"` - - // Catches all undefined fields and must be empty after parsing. - XXX map[string]interface{} `yaml:",inline"` -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - type plain TLSConfig - if err := unmarshal((*plain)(c)); err != nil { - return err - } - return checkOverflow(c.XXX, "TLS config") -} - -// GenerateConfig produces a tls.Config based on TLS connection options. -// It loads certificate files from disk if they are defined. -func (c *TLSConfig) GenerateConfig() (*tls.Config, error) { - tlsConfig := &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify} - - // If a CA cert is provided then let's read it in so we can validate the - // scrape target's certificate properly. - if len(c.CAFile) > 0 { - caCertPool := x509.NewCertPool() - // Load CA cert. - caCert, err := ioutil.ReadFile(c.CAFile) - if err != nil { - return nil, fmt.Errorf("unable to use specified CA cert %s: %s", c.CAFile, err) - } - caCertPool.AppendCertsFromPEM(caCert) - tlsConfig.RootCAs = caCertPool - } - - if len(c.CertFile) > 0 && len(c.KeyFile) == 0 { - return nil, fmt.Errorf("client cert file %q specified without client key file", c.CertFile) - } else if len(c.KeyFile) > 0 && len(c.CertFile) == 0 { - return nil, fmt.Errorf("client key file %q specified without client cert file", c.KeyFile) - } else if len(c.CertFile) > 0 && len(c.KeyFile) > 0 { - cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile) - if err != nil { - return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.CertFile, c.KeyFile, err) - } - tlsConfig.Certificates = []tls.Certificate{cert} - } - tlsConfig.BuildNameToCertificate() - - return tlsConfig, nil -} diff --git a/vendor/github.com/prometheus/common/config/tls_config_test.go b/vendor/github.com/prometheus/common/config/tls_config_test.go index 444303532..e2bd68edb 100644 --- a/vendor/github.com/prometheus/common/config/tls_config_test.go +++ b/vendor/github.com/prometheus/common/config/tls_config_test.go @@ -33,7 +33,7 @@ func LoadTLSConfig(filename string) (*tls.Config, error) { if err = yaml.Unmarshal(content, cfg); err != nil { return nil, err } - return cfg.GenerateConfig() + return NewTLSConfig(cfg) } var expectedTLSConfigs = []struct { @@ -57,7 +57,7 @@ func TestValidTLSConfig(t *testing.T) { t.Errorf("Error parsing %s: %s", cfg.filename, err) } if !reflect.DeepEqual(*got, *cfg.config) { - t.Fatalf("%s: unexpected config result: \n\n%s\n expected\n\n%s", cfg.filename, got, cfg.config) + t.Fatalf("%v: unexpected config result: \n\n%v\n expected\n\n%v", cfg.filename, got, cfg.config) } } } -- cgit v1.2.3-1-g7c22