Skip to content

Commit

Permalink
prober/tls: adding metric to expose certificate fingerprint info (#678)
Browse files Browse the repository at this point in the history
this change adds a new metric `probe_ssl_fingerprint_info` to both tcp
and http probes. the metric always returns 1 similar to the tls version
metric and contains the leaf certificates sha256 fingerprint (hex) as a
label value.

this change allows users to validate in prometheus if a particular
certificate is being served.

Signed-off-by: xinau <[email protected]>
  • Loading branch information
Felix Ehrenpfort authored Aug 18, 2020
1 parent 5b7f4ed commit c79355f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 2 deletions.
11 changes: 10 additions & 1 deletion prober/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
Help: "Returns last SSL chain expiry in timestamp seconds",
})

probeSSLLastInformation = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "probe_ssl_last_chain_info",
Help: "Contains SSL leaf certificate information",
},
[]string{"fingerprint_sha256"},
)

probeTLSVersion = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "probe_tls_version_info",
Expand Down Expand Up @@ -549,10 +557,11 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr

if resp.TLS != nil {
isSSLGauge.Set(float64(1))
registry.MustRegister(probeSSLEarliestCertExpiryGauge, probeTLSVersion, probeSSLLastChainExpiryTimestampSeconds)
registry.MustRegister(probeSSLEarliestCertExpiryGauge, probeTLSVersion, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation)
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)
if httpConfig.FailIfSSL {
level.Error(logger).Log("msg", "Final request was over SSL")
success = false
Expand Down
11 changes: 10 additions & 1 deletion prober/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ func ProbeTCP(ctx context.Context, target string, module config.Module, registry
Name: "probe_ssl_last_chain_expiry_timestamp_seconds",
Help: "Returns last SSL chain expiry in unixtime",
})
probeSSLLastInformation := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "probe_ssl_last_chain_info",
Help: "Contains SSL leaf certificate information",
},
[]string{"fingerprint_sha256"},
)
probeTLSVersion := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "probe_tls_version_info",
Expand Down Expand Up @@ -129,10 +136,11 @@ 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)
registry.MustRegister(probeSSLEarliestCertExpiry, probeTLSVersion, probeSSLLastChainExpiryTimestampSeconds, probeSSLLastInformation)
probeSSLEarliestCertExpiry.Set(float64(getEarliestCertExpiry(&state).Unix()))
probeTLSVersion.WithLabelValues(getTLSVersion(&state)).Set(1)
probeSSLLastChainExpiryTimestampSeconds.Set(float64(getLastChainExpiry(&state).Unix()))
probeSSLLastInformation.WithLabelValues(getFingerprint(&state)).Set(1)
}
scanner := bufio.NewScanner(conn)
for i, qr := range module.TCP.QueryResponse {
Expand Down Expand Up @@ -203,6 +211,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)
}
}
return true
Expand Down
2 changes: 2 additions & 0 deletions prober/tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ func TestTCPConnectionWithTLS(t *testing.T) {
// Check values
expectedResults := map[string]float64{
"probe_ssl_earliest_cert_expiry": float64(certExpiry.Unix()),
"probe_ssl_last_chain_info": 1,
"probe_tls_version_info": 1,
}
checkRegistryResults(expectedResults, mfs, t)
Expand Down Expand Up @@ -317,6 +318,7 @@ func TestTCPConnectionWithTLSAndVerifiedCertificateChain(t *testing.T) {
expectedResults := map[string]float64{
"probe_ssl_earliest_cert_expiry": float64(serverCertExpiry.Unix()),
"probe_ssl_last_chain_expiry_timestamp_seconds": float64(serverCertExpiry.Unix()),
"probe_ssl_last_chain_info": 1,
"probe_tls_version_info": 1,
}
checkRegistryResults(expectedResults, mfs, t)
Expand Down
8 changes: 8 additions & 0 deletions prober/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
package prober

import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"time"
)

Expand All @@ -28,6 +30,12 @@ func getEarliestCertExpiry(state *tls.ConnectionState) time.Time {
return earliest
}

func getFingerprint(state *tls.ConnectionState) string {
cert := state.PeerCertificates[0]
fingerprint := sha256.Sum256(cert.Raw)
return hex.EncodeToString(fingerprint[:])
}

func getLastChainExpiry(state *tls.ConnectionState) time.Time {
lastChainExpiry := time.Time{}
for _, chain := range state.VerifiedChains {
Expand Down

0 comments on commit c79355f

Please sign in to comment.