Skip to content

Commit

Permalink
Support TLS renegotiation (#83)
Browse files Browse the repository at this point in the history
* Support TLS renegotiation

* Bump version

* Revert version bump

* Extend TLSConfig with renegotiation support

* Update config/config.go - comment formatting

Co-authored-by: Rob Best <robertbest89@gmail.com>

* add dedicated renegotiation example

* Create local NewTLSConfig in order to incorporate local extentions

* go mod tidy

* Move TLS renegotiation parsing into UnmarshalYAML

Co-authored-by: Rob Best <robertbest89@gmail.com>
  • Loading branch information
britcey and ribbybibby authored Dec 9, 2021
1 parent 78306b9 commit 43dee90
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 38 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ prober: <prober_string>
# Disable target certificate validation.
[ insecure_skip_verify: <boolean> | default = false ]
# Configure TLS renegotiation support.
# Valid options: never, once, freely
[ renegotiation: <string> | default = never ]
# The CA cert to use for the targets.
[ ca_file: <filename> ]
Expand Down
67 changes: 60 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -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"
)

Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions examples/ssl_exporter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
25 changes: 12 additions & 13 deletions prober/https_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
},
Expand Down Expand Up @@ -77,7 +76,7 @@ func TestProbeHTTPSTimeout(t *testing.T) {
defer server.Close()

module := config.Module{
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
},
}
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -455,7 +454,7 @@ func TestProbeHTTPSProxy(t *testing.T) {
}

module := config.Module{
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
InsecureSkipVerify: false,
},
Expand Down Expand Up @@ -517,7 +516,7 @@ func TestProbeHTTPSOCSP(t *testing.T) {
defer server.Close()

module := config.Module{
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
},
}
Expand Down Expand Up @@ -598,7 +597,7 @@ func TestProbeHTTPSVerifiedChains(t *testing.T) {
defer server.Close()

module := config.Module{
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
},
}
Expand Down
25 changes: 12 additions & 13 deletions prober/tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -223,7 +222,7 @@ func TestProbeTCPStartTLSSMTP(t *testing.T) {
TCP: config.TCPProbe{
StartTLS: "smtp",
},
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
InsecureSkipVerify: false,
},
Expand Down Expand Up @@ -262,7 +261,7 @@ func TestProbeTCPStartTLSFTP(t *testing.T) {
TCP: config.TCPProbe{
StartTLS: "ftp",
},
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
InsecureSkipVerify: false,
},
Expand Down Expand Up @@ -301,7 +300,7 @@ func TestProbeTCPStartTLSIMAP(t *testing.T) {
TCP: config.TCPProbe{
StartTLS: "imap",
},
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
InsecureSkipVerify: false,
},
Expand Down Expand Up @@ -340,7 +339,7 @@ func TestProbeTCPStartTLSPostgreSQL(t *testing.T) {
TCP: config.TCPProbe{
StartTLS: "postgres",
},
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
InsecureSkipVerify: false,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -502,7 +501,7 @@ func TestProbeTCPVerifiedChains(t *testing.T) {
defer server.Close()

module := config.Module{
TLSConfig: pconfig.TLSConfig{
TLSConfig: config.TLSConfig{
CAFile: caFile,
},
}
Expand Down
6 changes: 3 additions & 3 deletions prober/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
3 changes: 1 addition & 2 deletions ssl_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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,
},
},
Expand Down

0 comments on commit 43dee90

Please sign in to comment.