From: Daniel Jolly Date: Tue, 9 Aug 2022 10:17:33 +0000 (-0400) Subject: Add leaf certificate details in probe_tls_certificate_info metric (#943) X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=cc533f125b41f65719cc00f25c54c8191515b9d9;p=blackbox_exporter.git Add leaf certificate details in probe_tls_certificate_info metric (#943) Add left certificate's "subject", "issuer", "subjectalternative" labels in `probe_tls_certificate_info` metric. See relevent discussion in #892 Co-authored-by: Daniel Jolly --- diff --git a/prober/grpc.go b/prober/grpc.go index dc616ff..e24f510 100644 --- a/prober/grpc.go +++ b/prober/grpc.go @@ -108,6 +108,14 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr }, []string{"version"}, ) + + probeSSLLastInformation = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "probe_ssl_last_chain_info", + Help: "Contains SSL leaf certificate information", + }, + []string{"fingerprint_sha256", "subject", "issuer", "subjectalternative"}, + ) ) for _, lv := range []string{"resolve"} { @@ -120,6 +128,7 @@ func ProbeGRPC(ctx context.Context, target string, module config.Module, registr registry.MustRegister(healthCheckResponseGaugeVec) registry.MustRegister(probeSSLEarliestCertExpiryGauge) registry.MustRegister(probeTLSVersion) + registry.MustRegister(probeSSLLastInformation) if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") { target = "http://" + target @@ -202,6 +211,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) + probeSSLLastInformation.WithLabelValues(getFingerprint(&tlsInfo.State), 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 82ef734..ec54bd7 100644 --- a/prober/http.go +++ b/prober/http.go @@ -281,7 +281,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr Name: "probe_ssl_last_chain_info", Help: "Contains SSL leaf certificate information", }, - []string{"fingerprint_sha256"}, + []string{"fingerprint_sha256", "subject", "issuer", "subjectalternative"}, ) probeTLSVersion = prometheus.NewGaugeVec( @@ -651,7 +651,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr probeSSLEarliestCertExpiryGauge.Set(float64(getEarliestCertExpiry(resp.TLS).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(resp.TLS)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(resp.TLS).Unix())) - probeSSLLastInformation.WithLabelValues(getFingerprint(resp.TLS)).Set(1) + probeSSLLastInformation.WithLabelValues(getFingerprint(resp.TLS), getSubject(resp.TLS), getIssuer(resp.TLS), getDNSNames(resp.TLS)).Set(1) if httpConfig.FailIfSSL { level.Error(logger).Log("msg", "Final request was over SSL") success = false diff --git a/prober/tcp.go b/prober/tcp.go index 1923cdb..8f2db40 100644 --- a/prober/tcp.go +++ b/prober/tcp.go @@ -102,7 +102,7 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry Name: "probe_ssl_last_chain_info", Help: "Contains SSL leaf certificate information", }, - []string{"fingerprint_sha256"}, + []string{"fingerprint_sha256", "subject", "issuer", "subjectalternative"}, ) probeTLSVersion := prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -139,7 +139,7 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry probeSSLEarliestCertExpiry.Set(float64(getEarliestCertExpiry(&state).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(&state)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(&state).Unix())) - probeSSLLastInformation.WithLabelValues(getFingerprint(&state)).Set(1) + probeSSLLastInformation.WithLabelValues(getFingerprint(&state), getSubject(&state), getIssuer(&state), getDNSNames(&state)).Set(1) } scanner := bufio.NewScanner(conn) for i, qr := range module.TCP.QueryResponse { @@ -205,7 +205,7 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry probeSSLEarliestCertExpiry.Set(float64(getEarliestCertExpiry(&state).Unix())) probeTLSVersion.WithLabelValues(getTLSVersion(&state)).Set(1) probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(&state).Unix())) - probeSSLLastInformation.WithLabelValues(getFingerprint(&state)).Set(1) + probeSSLLastInformation.WithLabelValues(getFingerprint(&state), getSubject(&state), getIssuer(&state), getDNSNames(&state)).Set(1) } } return true diff --git a/prober/tls.go b/prober/tls.go index 38d5533..7df8e57 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.String() +} + +func getIssuer(state *tls.ConnectionState) string { + cert := state.PeerCertificates[0] + return cert.Issuer.String() +} + +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 def607a..1b1c41d 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(),