1
0
mirror of https://github.com/ribbybibby/ssl_exporter.git synced 2024-11-24 08:22:17 +02:00

add TLS version metric (#24)

This commit is contained in:
Rob Best 2020-03-08 18:50:25 +00:00 committed by GitHub
parent 80765ab97d
commit e3477cf63c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 13 deletions

View File

@ -85,6 +85,7 @@ metric indicates if the probe has been successful.
| ssl_cert_not_before | The date before which the certificate is not valid. Expressed as a Unix Epoch Time. | serial_no, issuer_cn, cn, dnsnames, ips, emails, ou |
| ssl_client_protocol | The protocol used by the exporter to connect to the target. Boolean. | protocol |
| ssl_tls_connect_success | Was the TLS connection successful? Boolean. | |
| ssl_tls_version_info | The TLS version used. Always 1. | version |
## Prometheus

View File

@ -30,6 +30,11 @@ var (
"If the TLS connection was a success",
nil, nil,
)
tlsVersion = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", "tls_version_info"),
"The TLS version used",
[]string{"version"}, nil,
)
clientProtocol = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", "client_protocol"),
"The protocol used by the exporter to connect to the target",
@ -64,7 +69,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
// Collect metrics
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
var peerCertificates []*x509.Certificate
var state tls.ConnectionState
// Parse the target and return the appropriate connection protocol and target address
target, proto, err := parseTarget(e.target)
@ -116,7 +121,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
return
}
peerCertificates = resp.TLS.PeerCertificates
state = *resp.TLS
} else if proto == "tcp" {
ch <- prometheus.MustNewConstMetric(
@ -132,17 +137,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
return
}
state := conn.ConnectionState()
peerCertificates = state.PeerCertificates
if len(peerCertificates) < 1 {
log.Errorln("No certificates found in connection state for " + target)
ch <- prometheus.MustNewConstMetric(
tlsConnectSuccess, prometheus.GaugeValue, 0,
)
return
}
state = conn.ConnectionState()
} else {
log.Errorln("Unrecognised protocol: " + string(proto) + " for target: " + target)
ch <- prometheus.MustNewConstMetric(
@ -151,6 +146,21 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
return
}
// Get the TLS version from the connection state and export it as a metric
ch <- prometheus.MustNewConstMetric(
tlsVersion, prometheus.GaugeValue, 1, getTLSVersion(&state),
)
// Retrieve certificates from the connection state
peerCertificates := state.PeerCertificates
if len(peerCertificates) < 1 {
log.Errorln("No certificates found in connection state for " + target)
ch <- prometheus.MustNewConstMetric(
tlsConnectSuccess, prometheus.GaugeValue, 0,
)
return
}
ch <- prometheus.MustNewConstMetric(
tlsConnectSuccess, prometheus.GaugeValue, 1,
)
@ -281,6 +291,21 @@ func parseTarget(target string) (parsedTarget string, proto string, err error) {
return u.Host, "tcp", nil
}
func getTLSVersion(state *tls.ConnectionState) string {
switch state.Version {
case tls.VersionTLS10:
return "TLS 1.0"
case tls.VersionTLS11:
return "TLS 1.1"
case tls.VersionTLS12:
return "TLS 1.2"
case tls.VersionTLS13:
return "TLS 1.3"
default:
return "unknown"
}
}
func init() {
prometheus.MustRegister(version.NewCollector(namespace + "_exporter"))
}

View File

@ -454,6 +454,26 @@ func TestProbeHandlerExpiredInsecure(t *testing.T) {
server.Close()
}
// Test against a server with TLS v1.2
func TestProbeHandlerTLSVersion12(t *testing.T) {
server, err := serverTLSVersion12()
if err != nil {
t.Fatalf(err.Error())
}
rr, err := probe(server.URL)
if err != nil {
t.Fatalf(err.Error())
}
ok := strings.Contains(rr.Body.String(), "ssl_tls_version_info{version=\"TLS 1.2\"} 1")
if !ok {
t.Errorf("expected `ssl_tls_version_info{version=\"TLS 1.2\"} 1`")
}
server.Close()
}
func probe(url string) (*httptest.ResponseRecorder, error) {
uri := "/probe?target=" + url
req, err := http.NewRequest("GET", uri, nil)
@ -615,6 +635,26 @@ func serverHTTP() (*httptest.Server, error) {
return server, nil
}
func serverTLSVersion12() (*httptest.Server, error) {
serverCertificate, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey))
if err != nil {
return nil, err
}
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello world")
}))
server.TLS = &tls.Config{
Certificates: []tls.Certificate{serverCertificate},
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS12,
}
server.StartTLS()
return server, nil
}
func certPool() *x509.CertPool {
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM([]byte(caCert))