Add issuer label to ocsp_filter_responses metric (#7546)

Add a new "issuer" label to the ocsp-responder's ocsp_filter_responses
metric. This allows the count of responses served by ocsp-responder to
be broken down by which intermediate issued the certificate (and OCSP
response) in question.

This approach has the benefit of being minimal. The filterSource is the
only place within ocsp-responder that actually has knowledge of which
intermediate issued the certificate/ocsp response. The HTTP-handling
code above filterSource and the other redis and live-signing sources
below filterSource have no knowledge of the set of issuing
intermediates. They operate solely on the serial, because we guarantee
that our serials are unique across all issuers. So adding the metric
label here means that we don't have to make any other ocsp-responder
code aware of the issuers.

However, this approach has the cost of being somewhat surprising. Every
source has a `counter` metric with a "result" label; adding this
"issuer" label makes the filterSource's metric unique.

Fixes https://github.com/letsencrypt/boulder/issues/7538
This commit is contained in:
Aaron Gable 2024-06-14 09:39:32 -07:00 committed by GitHub
parent a69ba99760
commit 0f0c3e1432
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 20 additions and 14 deletions

View File

@ -13,22 +13,26 @@ import (
"strings"
"github.com/jmhodges/clock"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/crypto/ocsp"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/issuance"
blog "github.com/letsencrypt/boulder/log"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/crypto/ocsp"
)
// responderID contains the SHA1 hashes of an issuer certificate's name and key,
// exactly as the issuerNameHash and issuerKeyHash fields of an OCSP request
// should be computed by OCSP clients that are compliant with RFC 5019, the
// Lightweight OCSP Profile for High-Volume Environments. It also contains the
// Subject Common Name of the issuer certificate, for our own observability.
type responderID struct {
nameHash []byte
keyHash []byte
nameHash []byte
keyHash []byte
commonName string
}
// computeLightweightResponderID computes the SHA1 hashes of the certificate's
// name and key, exactly as the issuerNameHash and issuerKeyHash fields should
// be computed by OCSP clients that are compliant with RFC 5019, Lightweight
// OCSP Profile for High-Volume Environments.
// computeLightweightResponderID builds a responderID from an issuer certificate.
func computeLightweightResponderID(ic *issuance.Certificate) (responderID, error) {
// nameHash is the SHA1 hash over the DER encoding of the issuer certificate's
// Subject Distinguished Name.
@ -49,7 +53,7 @@ func computeLightweightResponderID(ic *issuance.Certificate) (responderID, error
}
keyHash := sha1.Sum(spki.PublicKey.RightAlign())
return responderID{nameHash[:], keyHash[:]}, nil
return responderID{nameHash[:], keyHash[:], ic.Subject.CommonName}, nil
}
type filterSource struct {
@ -82,7 +86,7 @@ func NewFilterSource(issuerCerts []*issuance.Certificate, serialPrefixes []strin
counter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "ocsp_filter_responses",
Help: "Count of OCSP requests/responses by action taken by the filter",
}, []string{"result"})
}, []string{"result", "issuer"})
stats.MustRegister(counter)
return &filterSource{
@ -103,24 +107,26 @@ func (src *filterSource) Response(ctx context.Context, req *ocsp.Request) (*Resp
iss, err := src.checkRequest(req)
if err != nil {
src.log.Debugf("Not responding to filtered OCSP request: %s", err.Error())
src.counter.WithLabelValues("request_filtered").Inc()
src.counter.WithLabelValues("request_filtered", "none").Inc()
return nil, err
}
counter := src.counter.MustCurryWith(prometheus.Labels{"issuer": src.issuers[iss].commonName})
resp, err := src.wrapped.Response(ctx, req)
if err != nil {
src.counter.WithLabelValues("wrapped_error").Inc()
counter.WithLabelValues("wrapped_error").Inc()
return nil, err
}
err = src.checkResponse(iss, resp)
if err != nil {
src.log.Warningf("OCSP Response not sent for CA=%s, Serial=%s, err: %s", hex.EncodeToString(req.IssuerKeyHash), core.SerialToString(req.SerialNumber), err)
src.counter.WithLabelValues("response_filtered").Inc()
counter.WithLabelValues("response_filtered").Inc()
return nil, err
}
src.counter.WithLabelValues("success").Inc()
counter.WithLabelValues("success").Inc()
return resp, nil
}