Skip to content

Commit 5005ec7

Browse files
authored
Merge pull request #1 from travelping/cennso-799-ipsec-monitoring
[CENNSO-799] X509 certificate validity support
2 parents 1929fd6 + e346eb7 commit 5005ec7

File tree

3 files changed

+527
-59
lines changed

3 files changed

+527
-59
lines changed

strongswan/collector.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package strongswan
22

33
import (
4+
"crypto/x509"
45
"strings"
6+
"time"
57

68
"github.com/prometheus/client_golang/prometheus"
79
"github.com/strongswan/govici/vici"
@@ -55,6 +57,9 @@ type Collector struct {
5557
saEstablishSecs *prometheus.Desc
5658
saRekeySecs *prometheus.Desc
5759
saLifetimeSecs *prometheus.Desc
60+
61+
crtCnt *prometheus.Desc
62+
crtValid *prometheus.Desc
5863
}
5964

6065
func NewCollector(viciClientFn viciClientFn) *Collector {
@@ -198,6 +203,17 @@ func NewCollector(viciClientFn viciClientFn) *Collector {
198203
"Seconds until the lifetime expires",
199204
[]string{"ike_name", "ike_id", "child_name", "child_id"}, nil,
200205
),
206+
207+
crtCnt: prometheus.NewDesc(
208+
prefix+"crt_count",
209+
"Number of X509 certificates",
210+
nil, nil,
211+
),
212+
crtValid: prometheus.NewDesc(
213+
prefix+"crt_valid",
214+
"X509 certificate validity",
215+
[]string{"serial_number", "subject", "alternate_names", "not_before", "not_after"}, nil,
216+
),
201217
}
202218
}
203219

@@ -230,6 +246,9 @@ func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
230246
ch <- c.saEstablishSecs
231247
ch <- c.saRekeySecs
232248
ch <- c.saLifetimeSecs
249+
250+
ch <- c.crtCnt
251+
ch <- c.crtValid
233252
}
234253

235254
func (c *Collector) Collect(ch chan<- prometheus.Metric) {
@@ -240,6 +259,11 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
240259
prometheus.GaugeValue,
241260
float64(0),
242261
)
262+
ch <- prometheus.MustNewConstMetric(
263+
c.crtCnt,
264+
prometheus.GaugeValue,
265+
float64(0),
266+
)
243267
return
244268
}
245269
ch <- prometheus.MustNewConstMetric(
@@ -253,6 +277,18 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
253277
c.collectIkeChildMetrics(ikeSa.Name, ikeSa.UniqueID, child, ch)
254278
}
255279
}
280+
281+
crts, err := c.listCrts()
282+
if err != nil {
283+
ch <- prometheus.MustNewConstMetric(
284+
c.crtCnt,
285+
prometheus.GaugeValue,
286+
float64(0),
287+
)
288+
return
289+
}
290+
291+
c.collectCrtMetrics(crts, ch)
256292
}
257293

258294
func (c *Collector) collectIkeMetrics(ikeSa IkeSa, ch chan<- prometheus.Metric) {
@@ -475,3 +511,122 @@ func viciStateToInt(v string) connectionStatus {
475511
return unknown
476512
}
477513
}
514+
515+
func alternateNames(cert *x509.Certificate) string {
516+
const AlternateNamesTypes = 4
517+
altNames := make([]string, 0, AlternateNamesTypes)
518+
519+
dnsNames := make([]string, 0, len(cert.DNSNames))
520+
for _, dns := range cert.DNSNames {
521+
dnsNames = append(dnsNames, "DNS="+dns)
522+
}
523+
dnsMerged := strings.Join(dnsNames, "+")
524+
if dnsMerged != "" {
525+
altNames = append(altNames, dnsMerged)
526+
}
527+
528+
emails := make([]string, 0, len(cert.EmailAddresses))
529+
for _, dns := range cert.EmailAddresses {
530+
emails = append(emails, "EM="+dns)
531+
}
532+
emailsMerged := strings.Join(emails, "+")
533+
if emailsMerged != "" {
534+
altNames = append(altNames, emailsMerged)
535+
}
536+
537+
ips := make([]string, 0, len(cert.IPAddresses))
538+
for _, ip := range cert.IPAddresses {
539+
ips = append(ips, "IP="+ip.String())
540+
}
541+
ipsMerged := strings.Join(ips, "+")
542+
if ipsMerged != "" {
543+
altNames = append(altNames, ipsMerged)
544+
}
545+
546+
uris := make([]string, 0, len(cert.URIs))
547+
for _, uri := range cert.URIs {
548+
uris = append(uris, "URI="+uri.String())
549+
}
550+
urisMerged := strings.Join(uris, "+")
551+
if urisMerged != "" {
552+
altNames = append(altNames, urisMerged)
553+
}
554+
555+
return strings.Join(altNames, ",")
556+
}
557+
558+
func (c *Collector) collectCrtMetrics(crts []Crt, ch chan<- prometheus.Metric) {
559+
var x509Crts uint
560+
561+
for _, crt := range crts {
562+
if crt.Type != "X509" {
563+
continue
564+
}
565+
566+
cert, err := x509.ParseCertificate([]byte(crt.Data))
567+
if err != nil {
568+
log.Logger.Warnf("Certificate parse error: %v", err)
569+
continue
570+
}
571+
572+
now := time.Now()
573+
valid := 0
574+
if now.After(cert.NotBefore) && now.Before(cert.NotAfter) {
575+
valid = 1
576+
}
577+
578+
ch <- prometheus.MustNewConstMetric(
579+
c.crtValid,
580+
prometheus.GaugeValue,
581+
float64(valid),
582+
cert.SerialNumber.String(),
583+
cert.Subject.String(),
584+
alternateNames(cert),
585+
cert.NotBefore.Format(time.RFC3339),
586+
cert.NotAfter.Format(time.RFC3339),
587+
)
588+
589+
x509Crts++
590+
}
591+
592+
ch <- prometheus.MustNewConstMetric(
593+
c.crtCnt,
594+
prometheus.GaugeValue,
595+
float64(x509Crts),
596+
)
597+
}
598+
599+
func (c *Collector) listCrts() ([]Crt, error) {
600+
s, err := c.viciClientFn()
601+
if err != nil {
602+
return nil, err
603+
}
604+
defer s.Close()
605+
606+
req := vici.NewMessage()
607+
req.Set("type", "X509")
608+
req.Set("flag", "ANY")
609+
610+
msgs, err := s.StreamedCommandRequest("list-certs", "list-cert", req)
611+
if err != nil {
612+
return nil, err
613+
}
614+
615+
res := []Crt{}
616+
for _, m := range msgs {
617+
if err = m.Err(); err != nil {
618+
log.Logger.Warnf("Message error: %v", err)
619+
return nil, err
620+
}
621+
622+
var crt Crt
623+
if e := vici.UnmarshalMessage(m, &crt); e != nil {
624+
log.Logger.Warnf("Message unmarshal error: %v", e)
625+
return nil, err
626+
}
627+
628+
res = append(res, crt)
629+
}
630+
631+
return res, nil
632+
}

0 commit comments

Comments
 (0)