github.com/letsencrypt/boulder@v0.20251208.0/observer/probers/crl/crl.go (about)

     1  package probers
     2  
     3  import (
     4  	"crypto/x509"
     5  	"io"
     6  	"net/http"
     7  	"slices"
     8  	"time"
     9  
    10  	"github.com/prometheus/client_golang/prometheus"
    11  
    12  	"github.com/letsencrypt/boulder/crl/idp"
    13  )
    14  
    15  // CRLProbe is the exported 'Prober' object for monitors configured to
    16  // monitor CRL availability & characteristics.
    17  type CRLProbe struct {
    18  	url         string
    19  	partitioned bool
    20  	cNextUpdate *prometheus.GaugeVec
    21  	cThisUpdate *prometheus.GaugeVec
    22  	cCertCount  *prometheus.GaugeVec
    23  }
    24  
    25  // Name returns a string that uniquely identifies the monitor.
    26  func (p CRLProbe) Name() string {
    27  	return p.url
    28  }
    29  
    30  // Kind returns a name that uniquely identifies the `Kind` of `Prober`.
    31  func (p CRLProbe) Kind() string {
    32  	return "CRL"
    33  }
    34  
    35  // Probe requests the configured CRL and publishes metrics about it if found.
    36  func (p CRLProbe) Probe(timeout time.Duration) (bool, time.Duration) {
    37  	start := time.Now()
    38  	resp, err := http.Get(p.url)
    39  	if err != nil {
    40  		return false, time.Since(start)
    41  	}
    42  
    43  	body, err := io.ReadAll(resp.Body)
    44  	if err != nil {
    45  		return false, time.Since(start)
    46  	}
    47  	dur := time.Since(start)
    48  
    49  	crl, err := x509.ParseRevocationList(body)
    50  	if err != nil {
    51  		return false, dur
    52  	}
    53  
    54  	// Partitioned CRLs MUST contain an issuingDistributionPoint extension, which
    55  	// MUST contain the URL from which they were fetched, to prevent substitution
    56  	// attacks.
    57  	if p.partitioned {
    58  		idps, err := idp.GetIDPURIs(crl.Extensions)
    59  		if err != nil {
    60  			return false, dur
    61  		}
    62  		if !slices.Contains(idps, p.url) {
    63  			return false, dur
    64  		}
    65  	}
    66  
    67  	// Report metrics for this CRL
    68  	p.cThisUpdate.WithLabelValues(p.url).Set(float64(crl.ThisUpdate.Unix()))
    69  	p.cNextUpdate.WithLabelValues(p.url).Set(float64(crl.NextUpdate.Unix()))
    70  	p.cCertCount.WithLabelValues(p.url).Set(float64(len(crl.RevokedCertificateEntries)))
    71  
    72  	return true, dur
    73  }