Skip to content

Commit fbb660d

Browse files
authoredJul 8, 2020
Merge pull request #275 from mitalirawat/mitali/SECENG-7134
add certificate expiration metrics for client certificates used in handshake
2 parents cdf0b58 + b490db3 commit fbb660d

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed
 

‎certmetrics/metrics.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Package certmetrics will be used to register and emit metrics for certificates in memory
2+
package certmetrics
3+
4+
import (
5+
"crypto/x509"
6+
"sort"
7+
"strings"
8+
9+
"github.com/prometheus/client_golang/prometheus"
10+
"github.com/prometheus/client_golang/prometheus/promauto"
11+
)
12+
13+
var certificateExpirationTimes = promauto.NewGaugeVec(
14+
prometheus.GaugeOpts{
15+
Name: "certificate_expiration_timestamp_seconds",
16+
Help: "Expiration times of gokeyless certs",
17+
},
18+
[]string{"serial_no", "cn", "hostnames", "ca", "server", "client"},
19+
)
20+
21+
// Observe takes in a list of certs and emits its expiration times
22+
func Observe(certs ...*x509.Certificate) {
23+
for _, cert := range certs {
24+
certificateExpirationTimes.With(getPrometheusLabels(cert)).Set(float64(cert.NotAfter.Unix()))
25+
}
26+
}
27+
28+
func getPrometheusLabels(cert *x509.Certificate) prometheus.Labels {
29+
hostnames := append([]string(nil), cert.DNSNames...)
30+
sort.Strings(hostnames)
31+
return prometheus.Labels{
32+
"serial_no": cert.SerialNumber.String(),
33+
"cn": cert.Subject.CommonName,
34+
"hostnames": strings.Join(hostnames, ","),
35+
"ca": boolToBinaryString(cert.IsCA),
36+
"server": hasKeyUsageAsBinaryString(cert.ExtKeyUsage, x509.ExtKeyUsageServerAuth),
37+
"client": hasKeyUsageAsBinaryString(cert.ExtKeyUsage, x509.ExtKeyUsageClientAuth)}
38+
}
39+
40+
func boolToBinaryString(val bool) string {
41+
if val {
42+
return "1"
43+
}
44+
return "0"
45+
}
46+
47+
func hasKeyUsageAsBinaryString(a []x509.ExtKeyUsage, x x509.ExtKeyUsage) string {
48+
for _, e := range a {
49+
if e == x || e == x509.ExtKeyUsageAny {
50+
return "1"
51+
}
52+
}
53+
return "0"
54+
}

‎cmd/gokeyless/gokeyless.go

+36-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"github.com/cloudflare/cfssl/helpers"
2020
"github.com/cloudflare/cfssl/log"
21+
"github.com/cloudflare/gokeyless/certmetrics"
2122
"github.com/cloudflare/gokeyless/server"
2223
)
2324

@@ -272,7 +273,8 @@ func main() {
272273
f.Close()
273274
}
274275
}
275-
276+
certs := gatherCerts()
277+
certmetrics.Observe(certs...)
276278
go func() {
277279
log.Critical(s.MetricsListenAndServe(net.JoinHostPort("", strconv.Itoa(config.MetricsPort))))
278280
}()
@@ -393,3 +395,36 @@ func verifyCSRAndKey() bool {
393395

394396
return true
395397
}
398+
399+
// pemCertsFromFile reads PEM format certificates from a file.
400+
func pemCertsFromFile(path string) []*x509.Certificate {
401+
file, err := os.Open(path)
402+
if err != nil {
403+
log.Fatal(err)
404+
}
405+
pemData, err := ioutil.ReadAll(file)
406+
if err != nil {
407+
log.Fatal(err)
408+
}
409+
certs, err := helpers.ParseCertificatesPEM(pemData)
410+
if err != nil {
411+
log.Fatal(err)
412+
}
413+
return certs
414+
}
415+
416+
func gatherCerts() []*x509.Certificate {
417+
certPaths := []string{
418+
config.CertFile,
419+
config.CACertFile,
420+
}
421+
var allCerts []*x509.Certificate
422+
for _, cPath := range certPaths {
423+
if cPath == "" {
424+
continue
425+
}
426+
pemCerts := pemCertsFromFile(cPath)
427+
allCerts = append(allCerts, pemCerts...)
428+
}
429+
return allCerts
430+
}

‎server/server.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"sync"
2525
"time"
2626

27+
"github.com/cloudflare/gokeyless/certmetrics"
28+
2729
"github.com/cloudflare/cfssl/helpers"
2830
"github.com/cloudflare/cfssl/helpers/derhelpers"
2931
"github.com/cloudflare/cfssl/log"
@@ -644,7 +646,9 @@ func (s *Server) spawn(l net.Listener, c net.Conn) {
644646
tconn.Close()
645647
return
646648
}
647-
limited, err := s.config.isLimited(tconn.ConnectionState())
649+
connState := tconn.ConnectionState()
650+
certmetrics.Observe(connState.PeerCertificates...)
651+
limited, err := s.config.isLimited(connState)
648652
if err != nil {
649653
log.Errorf("connection %v: could not determine if limited: %v", c.RemoteAddr(), err)
650654
tconn.Close()

0 commit comments

Comments
 (0)