From e091f565f5b0d92e6bd7d08bf8904946af696327 Mon Sep 17 00:00:00 2001 From: Daniel Jolly Date: Tue, 5 Jul 2022 23:48:09 -0400 Subject: [PATCH] Added probe_tls_certificate_info metric with basic certificate details --- prober/grpc.go | 9 +++++++++ prober/http.go | 11 ++++++++++- prober/tcp.go | 13 +++++++++++-- prober/tcp_test.go | 2 ++ prober/tls.go | 16 ++++++++++++++++ prober/utils_test.go | 1 + 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/prober/grpc.go b/prober/grpc.go index dc616ff22..aea373be5 100644 --- a/prober/grpc.go +++ b/prober/grpc.go @@ -108,6 +108,13 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr }, []string{"version"}, ) + + probeTLSCertInformation = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "probe_tls_certificate_info", + Help: "Returns the information about the certificate", + }, + []string{"subject", "issuer", "subjectalternative"}, + ) ) for _, lv := range []string{"resolve"} { @@ -120,6 +127,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr registry.MustRegister(healthCheckResponseGaugeVec) registry.MustRegister(probeSSLEarliestCertExpiryGauge) registry.MustRegister(probeTLSVersion) + registry.MustRegister(probeTLSCertInformation) if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") { target = "http://" + target @@ -202,6 +210,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr isSSLGauge.Set(float64(1)) probeSSLEarliestCertExpiryGauge.Set(float64(getEarliestCertExpiry(&tlsInfo.State).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(&tlsInfo.State)).Set(1) + probeTLSCertInformation.WithLabelValues(getSubject(&tlsInfo.State), getIssuer(&tlsInfo.State), getDNSNames(&tlsInfo.State)).Set(1) } else { isSSLGauge.Set(float64(0)) } diff --git a/prober/http.go b/prober/http.go index 99d38a2bf..541693dd2 100644 --- a/prober/http.go +++ b/prober/http.go @@ -293,6 +293,14 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr []string{"version"}, ) + probeTLSCertInformation = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "probe_tls_certificate_info", + Help: "Returns the information about the certificate", + }, + []string{"subject", "issuer", "subjectalternative"}, + ) + probeHTTPVersionGauge = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_http_version", Help: "Returns the version of HTTP of the probe response", @@ -642,9 +650,10 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr if resp.TLS != nil { isSSLGauge.Set(float64(1)) - registry.MustRegister(probeSSLEarliestCertExpiryGauge, probeTLSVersion, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation) + registry.MustRegister(probeSSLEarliestCertExpiryGauge, probeTLSVersion, probeTLSCertInformation, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation) probeSSLEarliestCertExpiryGauge.Set(float64(getEarliestCertExpiry(resp.TLS).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(resp.TLS)).Set(1) + probeTLSCertInformation.WithLabelValues(getSubject(resp.TLS), getIssuer(resp.TLS), getDNSNames(resp.TLS)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(resp.TLS).Unix())) probeSSLLastInformation.WithLabelValues(getFingerprint(resp.TLS)).Set(1) if httpConfig.FailIfSSL { diff --git a/prober/tcp.go b/prober/tcp.go index 1923cdb59..71e152161 100644 --- a/prober/tcp.go +++ b/prober/tcp.go @@ -111,6 +111,13 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry }, []string{"version"}, ) + probeTLSCertInformation := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "probe_tls_certificate_info", + Help: "Returns the information about the certificate", + }, + []string{"subject", "issuer", "subjectalternative"}, + ) probeFailedDueToRegex := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_failed_due_to_regex", Help: "Indicates if probe failed due to regex", @@ -135,9 +142,10 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry } if module.TCP.TLS { state := conn.(*tls.Conn).ConnectionState() - registry.MustRegister(probeSSLEarliestCertExpiry, probeTLSVersion, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation) + registry.MustRegister(probeSSLEarliestCertExpiry, probeTLSVersion, probeTLSCertInformation, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation) probeSSLEarliestCertExpiry.Set(float64(getEarliestCertExpiry(&state).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(&state)).Set(1) + probeTLSCertInformation.WithLabelValues(getSubject(&state), getIssuer(&state), getDNSNames(&state)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(&state).Unix())) probeSSLLastInformation.WithLabelValues(getFingerprint(&state)).Set(1) } @@ -201,9 +209,10 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry // Get certificate expiry. state := tlsConn.ConnectionState() - registry.MustRegister(probeSSLEarliestCertExpiry, probeSSLLastChainExpiryTimestampSeconds) + registry.MustRegister(probeSSLEarliestCertExpiry, probeSSLLastChainExpiryTimestampSeconds, probeTLSCertInformation) probeSSLEarliestCertExpiry.Set(float64(getEarliestCertExpiry(&state).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(&state)).Set(1) + probeTLSCertInformation.WithLabelValues(getSubject(&state), getIssuer(&state), getDNSNames(&state)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(&state).Unix())) probeSSLLastInformation.WithLabelValues(getFingerprint(&state)).Set(1) } diff --git a/prober/tcp_test.go b/prober/tcp_test.go index c86e2382f..efcbb4673 100644 --- a/prober/tcp_test.go +++ b/prober/tcp_test.go @@ -198,6 +198,7 @@ func TestTCPConnectionWithTLS(t *testing.T) { "probe_ssl_earliest_cert_expiry": float64(certExpiry.Unix()), "probe_ssl_last_chain_info": 1, "probe_tls_version_info": 1, + "probe_tls_certificate_info": 1, } checkRegistryResults(expectedResults, mfs, t) } @@ -322,6 +323,7 @@ func TestTCPConnectionWithTLSAndVerifiedCertificateChain(t *testing.T) { "probe_ssl_last_chain_expiry_timestamp_seconds": float64(serverCertExpiry.Unix()), "probe_ssl_last_chain_info": 1, "probe_tls_version_info": 1, + "probe_tls_certificate_info": 1, } checkRegistryResults(expectedResults, mfs, t) } diff --git a/prober/tls.go b/prober/tls.go index 38d553361..5b07482d9 100644 --- a/prober/tls.go +++ b/prober/tls.go @@ -17,6 +17,7 @@ import ( "crypto/sha256" "crypto/tls" "encoding/hex" + "strings" "time" ) @@ -36,6 +37,21 @@ func getFingerprint(state *tls.ConnectionState) string { return hex.EncodeToString(fingerprint[:]) } +func getSubject(state *tls.ConnectionState) string { + cert := state.PeerCertificates[0] + return cert.Subject.CommonName +} + +func getIssuer(state *tls.ConnectionState) string { + cert := state.PeerCertificates[0] + return cert.Issuer.CommonName +} + +func getDNSNames(state *tls.ConnectionState) string { + cert := state.PeerCertificates[0] + return strings.Join(cert.DNSNames, ",") +} + func getLastChainExpiry(state *tls.ConnectionState) time.Time { lastChainExpiry := time.Time{} for _, chain := range state.VerifiedChains { diff --git a/prober/utils_test.go b/prober/utils_test.go index def607a03..1b1c41dcb 100644 --- a/prober/utils_test.go +++ b/prober/utils_test.go @@ -85,6 +85,7 @@ func generateCertificateTemplate(expiry time.Time, IPAddressSAN bool) *x509.Cert SubjectKeyId: []byte{1}, SerialNumber: big.NewInt(1), Subject: pkix.Name{ + CommonName: "Example", Organization: []string{"Example Org"}, }, NotBefore: time.Now(),