Skip to content

Commit

Permalink
TLS config: Enable selection of min and max TLS version
Browse files Browse the repository at this point in the history
go1.18 changes the default minimum TLS version to 1.2.

In order not to break our users, let's make the default minimum version
configurable.

The allowed values (TLS10, ..) come from the exporter-toolkit:
https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md

TLSVersion is exported so the exporter toolkit can reuse them later.
DefaultTLSVersion is exposed so Prometheus can keep a conservative
default.

Signed-off-by: Julien Pivotto <roidelapluie@o11y.eu>
  • Loading branch information
roidelapluie committed Apr 16, 2022
1 parent 0c7319a commit 734398a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 18 deletions.
79 changes: 65 additions & 14 deletions config/http_config.go
Expand Up @@ -36,25 +36,63 @@ 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,
}

// DefaultTLSConfig holds the default TLS configuration.
DefaultTLSConfig = TLSConfig{
MinVersion: tls.VersionTLS12,
}
)

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"`
Expand Down Expand Up @@ -669,7 +707,17 @@ 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}
// Ensure that min and max versions are set even if TLSConfig is from its
// zero-value.
minv := uint16(cfg.MinVersion)
if minv == 0 {
minv = uint16(DefaultTLSConfig.MinVersion)
}

tlsConfig := &tls.Config{
InsecureSkipVerify: cfg.InsecureSkipVerify,
MinVersion: minv,
}

// If a CA cert is provided then let's read it in so we can validate the
// scrape target's certificate properly.
Expand Down Expand Up @@ -714,6 +762,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.
Expand All @@ -728,6 +778,7 @@ func (c *TLSConfig) SetDirectory(dir string) {

// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultTLSConfig
type plain TLSConfig
return unmarshal((*plain)(c))
}
Expand Down
9 changes: 7 additions & 2 deletions config/http_config_test.go
Expand Up @@ -627,7 +627,9 @@ func TestTLSConfig(t *testing.T) {
CertFile: ClientCertificatePath,
KeyFile: ClientKeyNoPassPath,
ServerName: "localhost",
InsecureSkipVerify: false}
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
}

tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath)
if err != nil {
Expand All @@ -640,7 +642,9 @@ func TestTLSConfig(t *testing.T) {
expectedTLSConfig := &tls.Config{
RootCAs: rootCAs,
ServerName: configTLSConfig.ServerName,
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify}
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify,
MinVersion: tls.VersionTLS12,
}

tlsConfig, err := NewTLSConfig(&configTLSConfig)
if err != nil {
Expand Down Expand Up @@ -683,6 +687,7 @@ func TestTLSConfigEmpty(t *testing.T) {

expectedTLSConfig := &tls.Config{
InsecureSkipVerify: configTLSConfig.InsecureSkipVerify,
MinVersion: tls.VersionTLS12,
}

tlsConfig, err := NewTLSConfig(&configTLSConfig)
Expand Down
1 change: 1 addition & 0 deletions config/testdata/tls_config.tlsversion.good.yml
@@ -0,0 +1 @@
min_version: TLS11
7 changes: 5 additions & 2 deletions config/tls_config_test.go
Expand Up @@ -41,10 +41,13 @@ var expectedTLSConfigs = []struct {
}{
{
filename: "tls_config.empty.good.yml",
config: &tls.Config{},
config: &tls.Config{MinVersion: tls.VersionTLS12},
}, {
filename: "tls_config.insecure.good.yml",
config: &tls.Config{InsecureSkipVerify: true},
config: &tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionTLS12},
}, {
filename: "tls_config.tlsversion.good.yml",
config: &tls.Config{MinVersion: tls.VersionTLS11},
},
}

Expand Down

0 comments on commit 734398a

Please sign in to comment.