You've already forked ssl_exporter
							
							
				mirror of
				https://github.com/ribbybibby/ssl_exporter.git
				synced 2025-10-31 00:07:44 +02:00 
			
		
		
		
	add TLS version metric (#24)
This commit is contained in:
		| @@ -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,19 +137,24 @@ 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) | ||||
| 		state = conn.ConnectionState() | ||||
| 	} else { | ||||
| 		log.Errorln("Unrecognised protocol: " + string(proto) + " for target: " + target) | ||||
| 		ch <- prometheus.MustNewConstMetric( | ||||
| 			tlsConnectSuccess, prometheus.GaugeValue, 0, | ||||
| 		) | ||||
| 		return | ||||
| 	} | ||||
| 	} else { | ||||
| 		log.Errorln("Unrecognised protocol: " + string(proto) + " for target: " + target) | ||||
|  | ||||
| 	// 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, | ||||
| 		) | ||||
| @@ -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)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user