diff --git a/README.md b/README.md index f03cdb8c..ef624304 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,10 @@ prober: # Disable target certificate validation. [ insecure_skip_verify: | default = false ] +# Configure TLS renegotiation support. +# Valid options: never, once, freely +[ renegotiation: | default = never ] + # The CA cert to use for the targets. [ ca_file: ] diff --git a/config/config.go b/config/config.go index e1fa2674..c6c63ad3 100644 --- a/config/config.go +++ b/config/config.go @@ -1,12 +1,13 @@ package config import ( + "crypto/tls" "fmt" "net/url" "os" "time" - "github.com/prometheus/common/config" + pconfig "github.com/prometheus/common/config" yaml "gopkg.in/yaml.v3" ) @@ -63,12 +64,64 @@ type Config struct { // Module configures a prober type Module struct { - Prober string `yaml:"prober,omitempty"` - Timeout time.Duration `yaml:"timeout,omitempty"` - TLSConfig config.TLSConfig `yaml:"tls_config,omitempty"` - HTTPS HTTPSProbe `yaml:"https,omitempty"` - TCP TCPProbe `yaml:"tcp,omitempty"` - Kubernetes KubernetesProbe `yaml:"kubernetes,omitempty"` + Prober string `yaml:"prober,omitempty"` + Timeout time.Duration `yaml:"timeout,omitempty"` + TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + HTTPS HTTPSProbe `yaml:"https,omitempty"` + TCP TCPProbe `yaml:"tcp,omitempty"` + Kubernetes KubernetesProbe `yaml:"kubernetes,omitempty"` +} + +// TLSConfig is a superset of config.TLSConfig that supports TLS renegotiation +type TLSConfig struct { + CAFile string `yaml:"ca_file,omitempty"` + CertFile string `yaml:"cert_file,omitempty"` + KeyFile string `yaml:"key_file,omitempty"` + ServerName string `yaml:"server_name,omitempty"` + InsecureSkipVerify bool `yaml:"insecure_skip_verify"` + // Renegotiation controls what types of TLS renegotiation are supported. + // Supported values: never (default), once, freely. + Renegotiation renegotiation `yaml:"renegotiation,omitempty"` +} + +type renegotiation tls.RenegotiationSupport + +func (r *renegotiation) UnmarshalYAML(unmarshal func(interface{}) error) error { + var v string + if err := unmarshal(&v); err != nil { + return err + } + switch v { + case "", "never": + *r = renegotiation(tls.RenegotiateNever) + case "once": + *r = renegotiation(tls.RenegotiateOnceAsClient) + case "freely": + *r = renegotiation(tls.RenegotiateFreelyAsClient) + default: + return fmt.Errorf("unsupported TLS renegotiation type %s", v) + } + + return nil +} + +// NewTLSConfig creates a new tls.Config from the given TLSConfig, +// plus our local extensions +func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { + tlsConfig, err := pconfig.NewTLSConfig(&pconfig.TLSConfig{ + CAFile: cfg.CAFile, + CertFile: cfg.CertFile, + KeyFile: cfg.KeyFile, + ServerName: cfg.ServerName, + InsecureSkipVerify: cfg.InsecureSkipVerify, + }) + if err != nil { + return nil, err + } + + tlsConfig.Renegotiation = tls.RenegotiationSupport(cfg.Renegotiation) + + return tlsConfig, nil } // TCPProbe configures a tcp probe diff --git a/examples/ssl_exporter.yaml b/examples/ssl_exporter.yaml index d54a540c..dd9d7fc1 100644 --- a/examples/ssl_exporter.yaml +++ b/examples/ssl_exporter.yaml @@ -5,6 +5,10 @@ modules: prober: https tls_config: insecure_skip_verify: true + https_renegotiation: + prober: https + tls_config: + renegotiation: freely https_proxy: prober: https https: diff --git a/prober/https_test.go b/prober/https_test.go index a177eac4..a10378b8 100644 --- a/prober/https_test.go +++ b/prober/https_test.go @@ -17,7 +17,6 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - pconfig "github.com/prometheus/common/config" "github.com/ribbybibby/ssl_exporter/config" "github.com/ribbybibby/ssl_exporter/test" "golang.org/x/crypto/ocsp" @@ -35,7 +34,7 @@ func TestProbeHTTPS(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -77,7 +76,7 @@ func TestProbeHTTPSTimeout(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, }, } @@ -105,7 +104,7 @@ func TestProbeHTTPSInvalidName(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -139,7 +138,7 @@ func TestProbeHTTPSNoScheme(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -186,7 +185,7 @@ func TestProbeHTTPSServerName(t *testing.T) { } module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, ServerName: u.Hostname(), @@ -263,7 +262,7 @@ func TestProbeHTTPSClientAuth(t *testing.T) { defer os.Remove(keyFile) module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, CertFile: certFile, KeyFile: keyFile, @@ -327,7 +326,7 @@ func TestProbeHTTPSClientAuthWrongClientCert(t *testing.T) { defer os.Remove(keyFile) module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, CertFile: certFile, KeyFile: keyFile, @@ -365,7 +364,7 @@ func TestProbeHTTPSExpired(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -402,7 +401,7 @@ func TestProbeHTTPSExpiredInsecure(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: true, }, @@ -455,7 +454,7 @@ func TestProbeHTTPSProxy(t *testing.T) { } module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -517,7 +516,7 @@ func TestProbeHTTPSOCSP(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, }, } @@ -598,7 +597,7 @@ func TestProbeHTTPSVerifiedChains(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, }, } diff --git a/prober/tcp_test.go b/prober/tcp_test.go index cc26ec76..8b478b8a 100644 --- a/prober/tcp_test.go +++ b/prober/tcp_test.go @@ -17,7 +17,6 @@ import ( "golang.org/x/crypto/ocsp" "github.com/prometheus/client_golang/prometheus" - pconfig "github.com/prometheus/common/config" ) // TestProbeTCP tests the typical case @@ -32,7 +31,7 @@ func TestProbeTCP(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -69,7 +68,7 @@ func TestProbeTCPInvalidName(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -102,7 +101,7 @@ func TestProbeTCPServerName(t *testing.T) { host, listenPort, _ := net.SplitHostPort(server.Listener.Addr().String()) module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, ServerName: host, @@ -147,7 +146,7 @@ func TestProbeTCPExpired(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -184,7 +183,7 @@ func TestProbeTCPExpiredInsecure(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: true, }, @@ -223,7 +222,7 @@ func TestProbeTCPStartTLSSMTP(t *testing.T) { TCP: config.TCPProbe{ StartTLS: "smtp", }, - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -262,7 +261,7 @@ func TestProbeTCPStartTLSFTP(t *testing.T) { TCP: config.TCPProbe{ StartTLS: "ftp", }, - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -301,7 +300,7 @@ func TestProbeTCPStartTLSIMAP(t *testing.T) { TCP: config.TCPProbe{ StartTLS: "imap", }, - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -340,7 +339,7 @@ func TestProbeTCPStartTLSPostgreSQL(t *testing.T) { TCP: config.TCPProbe{ StartTLS: "postgres", }, - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -377,7 +376,7 @@ func TestProbeTCPTimeout(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -420,7 +419,7 @@ func TestProbeTCPOCSP(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, InsecureSkipVerify: false, }, @@ -502,7 +501,7 @@ func TestProbeTCPVerifiedChains(t *testing.T) { defer server.Close() module := config.Module{ - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, }, } diff --git a/prober/tls.go b/prober/tls.go index 0c3bdc2d..1eb43bf7 100644 --- a/prober/tls.go +++ b/prober/tls.go @@ -7,13 +7,13 @@ import ( "net" "github.com/prometheus/client_golang/prometheus" - pconfig "github.com/prometheus/common/config" + "github.com/ribbybibby/ssl_exporter/config" ) // newTLSConfig sets up TLS config and instruments it with a function that // collects metrics for the verified chain -func newTLSConfig(target string, registry *prometheus.Registry, pTLSConfig *pconfig.TLSConfig) (*tls.Config, error) { - tlsConfig, err := pconfig.NewTLSConfig(pTLSConfig) +func newTLSConfig(target string, registry *prometheus.Registry, cfg *config.TLSConfig) (*tls.Config, error) { + tlsConfig, err := config.NewTLSConfig(cfg) if err != nil { return nil, err } diff --git a/ssl_exporter_test.go b/ssl_exporter_test.go index 643d69e9..e0073df3 100644 --- a/ssl_exporter_test.go +++ b/ssl_exporter_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/go-kit/log" - pconfig "github.com/prometheus/common/config" "github.com/ribbybibby/ssl_exporter/config" "github.com/ribbybibby/ssl_exporter/test" ) @@ -29,7 +28,7 @@ func TestProbeHandler(t *testing.T) { Modules: map[string]config.Module{ "https": config.Module{ Prober: "https", - TLSConfig: pconfig.TLSConfig{ + TLSConfig: config.TLSConfig{ CAFile: caFile, }, },