cmd: Export prometheus metrics for TLS cert notBefore and notAfter fields (#6836)
Export new prometheus metrics for the `notBefore` and `notAfter` fields to track internal certificate validity periods when calling the `Load()` method for a `*tls.Config`. Each metric is labeled with the `serial` field. ``` tlsconfig_notafter_seconds{serial="2152072875247971686"} 1.664821961e+09 tlsconfig_notbefore_seconds{serial="2152072875247971686"} 1.664821960e+09 ``` Fixes https://github.com/letsencrypt/boulder/issues/6829
This commit is contained in:
parent
914e971f15
commit
17fb1b287f
|
@ -100,7 +100,8 @@ type revoker struct {
|
|||
func newRevoker(c Config) *revoker {
|
||||
logger := cmd.NewLogger(c.Syslog)
|
||||
|
||||
tlsConfig, err := c.Revoker.TLS.Load()
|
||||
// TODO(#6840) Rework admin-revoker to export prometheus metrics.
|
||||
tlsConfig, err := c.Revoker.TLS.Load(metrics.NoopRegisterer)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
clk := cmd.Clock()
|
||||
|
|
|
@ -366,7 +366,7 @@ func manualPurge(purgeClient *akamai.CachePurgeClient, tag, tagFile string) {
|
|||
func daemon(c Config, ap *akamaiPurger, logger blog.Logger, scope prometheus.Registerer) {
|
||||
clk := cmd.Clock()
|
||||
|
||||
tlsConfig, err := c.AkamaiPurger.TLS.Load()
|
||||
tlsConfig, err := c.AkamaiPurger.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "tlsConfig config")
|
||||
|
||||
stop, stopped := make(chan bool, 1), make(chan bool, 1)
|
||||
|
|
|
@ -450,7 +450,7 @@ func main() {
|
|||
dbMap, err := sa.InitWrappedDb(config.BadKeyRevoker.DB, scope, logger)
|
||||
cmd.FailOnError(err, "While initializing dbMap")
|
||||
|
||||
tlsConfig, err := config.BadKeyRevoker.TLS.Load()
|
||||
tlsConfig, err := config.BadKeyRevoker.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
conn, err := bgrpc.ClientSetup(config.BadKeyRevoker.RAService, tlsConfig, scope, clk)
|
||||
|
|
|
@ -214,7 +214,7 @@ func main() {
|
|||
boulderIssuers, err = loadBoulderIssuers(c.CA.Issuance.Profile, c.CA.Issuance.Issuers, c.CA.Issuance.IgnoredLints)
|
||||
cmd.FailOnError(err, "Couldn't load issuers")
|
||||
|
||||
tlsConfig, err := c.CA.TLS.Load()
|
||||
tlsConfig, err := c.CA.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
clk := cmd.Clock()
|
||||
|
|
|
@ -65,7 +65,6 @@ func main() {
|
|||
if c.Publisher.UserAgent == "" {
|
||||
c.Publisher.UserAgent = "certificate-transparency-go/1.0"
|
||||
}
|
||||
|
||||
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.Publisher.DebugAddr)
|
||||
defer oTelShutdown(context.Background())
|
||||
defer logger.AuditPanic()
|
||||
|
@ -88,7 +87,7 @@ func main() {
|
|||
bundles[id] = publisher.GetCTBundleForChain(chain)
|
||||
}
|
||||
|
||||
tlsConfig, err := c.Publisher.TLS.Load()
|
||||
tlsConfig, err := c.Publisher.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
clk := cmd.Clock()
|
||||
|
|
|
@ -140,7 +140,7 @@ func main() {
|
|||
err = pa.SetHostnamePolicyFile(c.RA.HostnamePolicyFile)
|
||||
cmd.FailOnError(err, "Couldn't load hostname policy file")
|
||||
|
||||
tlsConfig, err := c.RA.TLS.Load()
|
||||
tlsConfig, err := c.RA.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
clk := cmd.Clock()
|
||||
|
|
|
@ -84,7 +84,7 @@ func main() {
|
|||
parallel = 1
|
||||
}
|
||||
|
||||
tls, err := c.SA.TLS.Load()
|
||||
tls, err := c.SA.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
saroi, err := sa.NewSQLStorageAuthorityRO(
|
||||
|
|
|
@ -120,7 +120,7 @@ func main() {
|
|||
logger)
|
||||
}
|
||||
|
||||
tlsConfig, err := c.VA.TLS.Load()
|
||||
tlsConfig, err := c.VA.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "tlsConfig config")
|
||||
|
||||
var remotes []va.RemoteVA
|
||||
|
|
|
@ -311,7 +311,7 @@ func loadChain(certFiles []string) (*issuance.Certificate, []byte, error) {
|
|||
}
|
||||
|
||||
func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.RegistrationAuthorityClient, sapb.StorageAuthorityReadOnlyClient, nonce.Getter, map[string]nonce.Redeemer, nonce.Redeemer, string) {
|
||||
tlsConfig, err := c.WFE.TLS.Load()
|
||||
tlsConfig, err := c.WFE.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
raConn, err := bgrpc.ClientSetup(c.WFE.RAService, tlsConfig, scope, clk)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
"github.com/letsencrypt/boulder/config"
|
||||
|
@ -139,8 +140,9 @@ type TLSConfig struct {
|
|||
}
|
||||
|
||||
// Load reads and parses the certificates and key listed in the TLSConfig, and
|
||||
// returns a *tls.Config suitable for either client or server use.
|
||||
func (t *TLSConfig) Load() (*tls.Config, error) {
|
||||
// returns a *tls.Config suitable for either client or server use. Prometheus
|
||||
// metrics for various certificate fields will be exported.
|
||||
func (t *TLSConfig) Load(scope prometheus.Registerer) (*tls.Config, error) {
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("nil TLS section in config")
|
||||
}
|
||||
|
@ -166,6 +168,48 @@ func (t *TLSConfig) Load() (*tls.Config, error) {
|
|||
return nil, fmt.Errorf("loading key pair from %q and %q: %s",
|
||||
*t.CertFile, *t.KeyFile, err)
|
||||
}
|
||||
|
||||
tlsNotBefore := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "tlsconfig_notbefore_seconds",
|
||||
Help: "TLS certificate NotBefore field expressed as Unix epoch time",
|
||||
},
|
||||
[]string{"serial"})
|
||||
err = scope.Register(tlsNotBefore)
|
||||
if err != nil {
|
||||
are := prometheus.AlreadyRegisteredError{}
|
||||
if errors.As(err, &are) {
|
||||
tlsNotBefore = are.ExistingCollector.(*prometheus.GaugeVec)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
tlsNotAfter := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "tlsconfig_notafter_seconds",
|
||||
Help: "TLS certificate NotAfter field expressed as Unix epoch time",
|
||||
},
|
||||
[]string{"serial"})
|
||||
err = scope.Register(tlsNotAfter)
|
||||
if err != nil {
|
||||
are := prometheus.AlreadyRegisteredError{}
|
||||
if errors.As(err, &are) {
|
||||
tlsNotAfter = are.ExistingCollector.(*prometheus.GaugeVec)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
leaf, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serial := leaf.SerialNumber.String()
|
||||
tlsNotBefore.WithLabelValues(serial).Set(float64(leaf.NotBefore.Unix()))
|
||||
tlsNotAfter.WithLabelValues(serial).Set(float64(leaf.NotAfter.Unix()))
|
||||
|
||||
return &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
ClientCAs: rootCAs,
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
|
@ -54,6 +55,7 @@ func TestTLSConfigLoad(t *testing.T) {
|
|||
cert := "testdata/cert.pem"
|
||||
key := "testdata/key.pem"
|
||||
caCert := "testdata/minica.pem"
|
||||
|
||||
testCases := []struct {
|
||||
TLSConfig
|
||||
want string
|
||||
|
@ -86,7 +88,7 @@ func TestTLSConfigLoad(t *testing.T) {
|
|||
title[2] = *tc.CACertFile
|
||||
}
|
||||
t.Run(strings.Join(title[:], "_"), func(t *testing.T) {
|
||||
_, err := tc.TLSConfig.Load()
|
||||
_, err := tc.TLSConfig.Load(metrics.NoopRegisterer)
|
||||
if err == nil {
|
||||
t.Errorf("got no error")
|
||||
}
|
||||
|
|
|
@ -82,15 +82,15 @@ func main() {
|
|||
err = features.Set(c.CRLStorer.Features)
|
||||
cmd.FailOnError(err, "Failed to set feature flags")
|
||||
|
||||
tlsConfig, err := c.CRLStorer.TLS.Load()
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CRLStorer.DebugAddr)
|
||||
defer oTelShutdown(context.Background())
|
||||
defer logger.AuditPanic()
|
||||
logger.Info(cmd.VersionString())
|
||||
clk := cmd.Clock()
|
||||
|
||||
tlsConfig, err := c.CRLStorer.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
issuers := make([]*issuance.Certificate, 0, len(c.CRLStorer.IssuerCerts))
|
||||
for _, filepath := range c.CRLStorer.IssuerCerts {
|
||||
cert, err := issuance.LoadCertificate(filepath)
|
||||
|
|
|
@ -115,15 +115,15 @@ func main() {
|
|||
err = features.Set(c.CRLUpdater.Features)
|
||||
cmd.FailOnError(err, "Failed to set feature flags")
|
||||
|
||||
tlsConfig, err := c.CRLUpdater.TLS.Load()
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CRLUpdater.DebugAddr)
|
||||
defer oTelShutdown(context.Background())
|
||||
defer logger.AuditPanic()
|
||||
logger.Info(cmd.VersionString())
|
||||
clk := cmd.Clock()
|
||||
|
||||
tlsConfig, err := c.CRLUpdater.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
issuers := make([]*issuance.Certificate, 0, len(c.CRLUpdater.IssuerCerts))
|
||||
for _, filepath := range c.CRLUpdater.IssuerCerts {
|
||||
cert, err := issuance.LoadCertificate(filepath)
|
||||
|
|
|
@ -825,7 +825,7 @@ func main() {
|
|||
dbMap, err := sa.InitWrappedDb(c.Mailer.DB, scope, logger)
|
||||
cmd.FailOnError(err, "While initializing dbMap")
|
||||
|
||||
tlsConfig, err := c.Mailer.TLS.Load()
|
||||
tlsConfig, err := c.Mailer.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
clk := cmd.Clock()
|
||||
|
|
|
@ -108,7 +108,7 @@ func main() {
|
|||
ns, err := nonce.NewNonceService(scope, c.NonceService.MaxUsed, c.NonceService.NoncePrefix)
|
||||
cmd.FailOnError(err, "Failed to initialize nonce service")
|
||||
|
||||
tlsConfig, err := c.NonceService.TLS.Load()
|
||||
tlsConfig, err := c.NonceService.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "tlsConfig config")
|
||||
|
||||
nonceServer := nonce.NewServer(ns)
|
||||
|
|
|
@ -163,7 +163,7 @@ as generated by Boulder's ceremony command.
|
|||
liveSigningPeriod = 60 * time.Hour
|
||||
}
|
||||
|
||||
tlsConfig, err := c.OCSPResponder.TLS.Load()
|
||||
tlsConfig, err := c.OCSPResponder.TLS.Load(scope)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
raConn, err := bgrpc.ClientSetup(c.OCSPResponder.RAService, tlsConfig, scope, clk)
|
||||
|
|
|
@ -174,7 +174,8 @@ func newOrphanFinder(configFile string) *orphanFinder {
|
|||
cmd.FailOnError(err, "Failed to set feature flags")
|
||||
logger := cmd.NewLogger(conf.Syslog)
|
||||
|
||||
tlsConfig, err := conf.TLS.Load()
|
||||
// TODO(#6840) Rework orphan-finder to export prometheus metrics.
|
||||
tlsConfig, err := conf.TLS.Load(metrics.NoopRegisterer)
|
||||
cmd.FailOnError(err, "TLS config")
|
||||
|
||||
saConn, err := bgrpc.ClientSetup(conf.SAService, tlsConfig, metrics.NoopRegisterer, cmd.Clock())
|
||||
|
|
|
@ -31,7 +31,7 @@ func makeClient() (*rocsp.RWClient, clock.Clock) {
|
|||
CertFile: &CertFile,
|
||||
KeyFile: &KeyFile,
|
||||
}
|
||||
tlsConfig2, err := tlsConfig.Load()
|
||||
tlsConfig2, err := tlsConfig.Load(metrics.NoopRegisterer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -249,7 +249,7 @@ func helpExit() {
|
|||
}
|
||||
|
||||
func configureOCSPGenerator(tlsConf cmd.TLSConfig, grpcConf cmd.GRPCClientConfig, clk clock.Clock, scope prometheus.Registerer) (capb.OCSPGeneratorClient, error) {
|
||||
tlsConfig, err := tlsConf.Load()
|
||||
tlsConfig, err := tlsConf.Load(scope)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading TLS config: %w", err)
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ func MakeClient(c *RedisConfig, clk clock.Clock, stats prometheus.Registerer) (*
|
|||
return nil, fmt.Errorf("loading password: %w", err)
|
||||
}
|
||||
|
||||
tlsConfig, err := c.TLS.Load()
|
||||
tlsConfig, err := c.TLS.Load(stats)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading TLS config: %w", err)
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func MakeReadClient(c *RedisConfig, clk clock.Clock, stats prometheus.Registerer
|
|||
return nil, fmt.Errorf("loading password: %w", err)
|
||||
}
|
||||
|
||||
tlsConfig, err := c.TLS.Load()
|
||||
tlsConfig, err := c.TLS.Load(stats)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading TLS config: %w", err)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func makeClient() (*RWClient, clock.Clock) {
|
|||
CertFile: &CertFile,
|
||||
KeyFile: &KeyFile,
|
||||
}
|
||||
tlsConfig2, err := tlsConfig.Load()
|
||||
tlsConfig2, err := tlsConfig.Load(metrics.NoopRegisterer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func main() {
|
|||
c.GRPC.ServerAddress = *serverAddr
|
||||
}
|
||||
|
||||
tlsConfig, err := c.TLS.Load()
|
||||
tlsConfig, err := c.TLS.Load(metrics.NoopRegisterer)
|
||||
cmd.FailOnError(err, "failed to load TLS credentials")
|
||||
|
||||
// GRPC connection prerequisites.
|
||||
|
@ -75,7 +75,6 @@ func main() {
|
|||
Service: "",
|
||||
}
|
||||
resp, err := client.Check(ctx2, req)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "got error connecting to health service %s: %s\n", *serverAddr, err)
|
||||
} else if resp.Status == healthpb.HealthCheckResponse_SERVING {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
akamaipb "github.com/letsencrypt/boulder/akamai/proto"
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
bcreds "github.com/letsencrypt/boulder/grpc/creds"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/balancer/roundrobin"
|
||||
|
@ -42,7 +43,7 @@ func setup() (*exec.Cmd, *bytes.Buffer, akamaipb.AkamaiPurgerClient, error) {
|
|||
CACertFile: s("test/grpc-creds/minica.pem"),
|
||||
CertFile: s("test/grpc-creds/ra.boulder/cert.pem"),
|
||||
KeyFile: s("test/grpc-creds/ra.boulder/key.pem"),
|
||||
}).Load()
|
||||
}).Load(metrics.NoopRegisterer)
|
||||
if err != nil {
|
||||
sigterm()
|
||||
return nil, nil, nil, err
|
||||
|
|
Loading…
Reference in New Issue