diff --git a/config/http_config.go b/config/http_config.go index 37cb37ce..eedb2169 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -36,25 +36,58 @@ import ( "gopkg.in/yaml.v2" ) -// DefaultHTTPClientConfig is the default HTTP client configuration. -var DefaultHTTPClientConfig = HTTPClientConfig{ - FollowRedirects: true, - EnableHTTP2: true, -} +var ( + // DefaultHTTPClientConfig is the default HTTP client configuration. + DefaultHTTPClientConfig = HTTPClientConfig{ + FollowRedirects: true, + EnableHTTP2: true, + } -// defaultHTTPClientOptions holds the default HTTP client options. -var defaultHTTPClientOptions = httpClientOptions{ - keepAlivesEnabled: true, - http2Enabled: true, - // 5 minutes is typically above the maximum sane scrape interval. So we can - // use keepalive for all configurations. - idleConnTimeout: 5 * time.Minute, -} + // defaultHTTPClientOptions holds the default HTTP client options. + defaultHTTPClientOptions = httpClientOptions{ + keepAlivesEnabled: true, + http2Enabled: true, + // 5 minutes is typically above the maximum sane scrape interval. So we can + // use keepalive for all configurations. + idleConnTimeout: 5 * time.Minute, + } +) type closeIdler interface { CloseIdleConnections() } +type TLSVersion uint16 + +var TLSVersions = map[string]TLSVersion{ + "TLS13": (TLSVersion)(tls.VersionTLS13), + "TLS12": (TLSVersion)(tls.VersionTLS12), + "TLS11": (TLSVersion)(tls.VersionTLS11), + "TLS10": (TLSVersion)(tls.VersionTLS10), +} + +func (tv *TLSVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + err := unmarshal((*string)(&s)) + if err != nil { + return err + } + if v, ok := TLSVersions[s]; ok { + *tv = v + return nil + } + return fmt.Errorf("unknown TLS version: %s", s) +} + +func (tv *TLSVersion) MarshalYAML() (interface{}, error) { + for s, v := range TLSVersions { + if *tv == v { + return s, nil + } + } + return fmt.Sprintf("%v", tv), nil +} + // BasicAuth contains basic HTTP authentication credentials. type BasicAuth struct { Username string `yaml:"username" json:"username"` @@ -669,7 +702,10 @@ func cloneRequest(r *http.Request) *http.Request { // NewTLSConfig creates a new tls.Config from the given TLSConfig. func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { - tlsConfig := &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify} + tlsConfig := &tls.Config{ + InsecureSkipVerify: cfg.InsecureSkipVerify, + MinVersion: uint16(cfg.MinVersion), + } // If a CA cert is provided then let's read it in so we can validate the // scrape target's certificate properly. @@ -714,6 +750,8 @@ type TLSConfig struct { ServerName string `yaml:"server_name,omitempty" json:"server_name,omitempty"` // Disable target certificate validation. InsecureSkipVerify bool `yaml:"insecure_skip_verify" json:"insecure_skip_verify"` + // Minimum TLS version. + MinVersion TLSVersion `yaml:"min_version,omitempty"` } // SetDirectory joins any relative file paths with dir. @@ -726,12 +764,6 @@ func (c *TLSConfig) SetDirectory(dir string) { c.KeyFile = JoinDir(dir, c.KeyFile) } -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - type plain TLSConfig - return unmarshal((*plain)(c)) -} - // getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate. func (c *TLSConfig) getClientCertificate(*tls.CertificateRequestInfo) (*tls.Certificate, error) { cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile) diff --git a/config/http_config_test.go b/config/http_config_test.go index 884f344c..06eb6d04 100644 --- a/config/http_config_test.go +++ b/config/http_config_test.go @@ -627,7 +627,8 @@ func TestTLSConfig(t *testing.T) { CertFile: ClientCertificatePath, KeyFile: ClientKeyNoPassPath, ServerName: "localhost", - InsecureSkipVerify: false} + InsecureSkipVerify: false, + } tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath) if err != nil { @@ -640,7 +641,8 @@ func TestTLSConfig(t *testing.T) { expectedTLSConfig := &tls.Config{ RootCAs: rootCAs, ServerName: configTLSConfig.ServerName, - InsecureSkipVerify: configTLSConfig.InsecureSkipVerify} + InsecureSkipVerify: configTLSConfig.InsecureSkipVerify, + } tlsConfig, err := NewTLSConfig(&configTLSConfig) if err != nil { diff --git a/config/testdata/tls_config.tlsversion.good.yml b/config/testdata/tls_config.tlsversion.good.yml new file mode 100644 index 00000000..ee24ee67 --- /dev/null +++ b/config/testdata/tls_config.tlsversion.good.yml @@ -0,0 +1 @@ +min_version: TLS11 diff --git a/config/tls_config_test.go b/config/tls_config_test.go index 2b965ea6..b164a2f3 100644 --- a/config/tls_config_test.go +++ b/config/tls_config_test.go @@ -45,6 +45,9 @@ var expectedTLSConfigs = []struct { }, { filename: "tls_config.insecure.good.yml", config: &tls.Config{InsecureSkipVerify: true}, + }, { + filename: "tls_config.tlsversion.good.yml", + config: &tls.Config{MinVersion: tls.VersionTLS11}, }, }