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:
parent
80765ab97d
commit
e3477cf63c
@ -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
|
||||
|
||||
|
@ -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"))
|
||||
}
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user