@ -2,18 +2,20 @@ package consul
import (
"context"
"crypto/x509"
"errors"
"fmt"
"strings"
"time"
"github.com/hashicorp/consul/agent/connect/ca"
"github.com/hashicorp/consul/agent/connect"
"github.com/armon/go-metrics"
"github.com/armon/go-metrics/prometheus"
"github.com/hashicorp/consul/logging"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/connect/ca"
"github.com/hashicorp/consul/logging"
"github.com/hashicorp/consul/tlsutil"
)
var metricsKeyMeshRootCAExpiry = [ ] string { "mesh" , "active-root-ca" , "expiry" }
@ -28,10 +30,14 @@ var CertExpirationGauges = []prometheus.GaugeDefinition{
Name : metricsKeyMeshActiveSigningCAExpiry ,
Help : "Seconds until the service mesh signing certificate expires. Updated every hour" ,
} ,
{
Name : metricsKeyAgentTLSCertExpiry ,
Help : "Seconds until the agent tls certificate expires. Updated every hour" ,
} ,
}
func rootCAExpiryMonitor ( s * Server ) certExpirationMonitor {
return certExpirationMonitor {
func rootCAExpiryMonitor ( s * Server ) C ertExpirationMonitor {
return C ertExpirationMonitor{
Key : metricsKeyMeshRootCAExpiry ,
Labels : [ ] metrics . Label {
{ Name : "datacenter" , Value : s . config . Datacenter } ,
@ -56,10 +62,10 @@ func getRootCAExpiry(s *Server) (time.Duration, error) {
return time . Until ( root . NotAfter ) , nil
}
func signingCAExpiryMonitor ( s * Server ) c ertExpirationMonitor {
func signingCAExpiryMonitor ( s * Server ) C ertExpirationMonitor {
isPrimary := s . config . Datacenter == s . config . PrimaryDatacenter
if isPrimary {
return c ertExpirationMonitor{
return C ertExpirationMonitor{
Key : metricsKeyMeshActiveSigningCAExpiry ,
Labels : [ ] metrics . Label {
{ Name : "datacenter" , Value : s . config . Datacenter } ,
@ -68,26 +74,24 @@ func signingCAExpiryMonitor(s *Server) certExpirationMonitor {
Query : func ( ) ( time . Duration , error ) {
provider , _ := s . caManager . getCAProvider ( )
if _ , ok := provider . ( ca . PrimaryUsesIntermediate ) ; ! ok {
if _ , ok := provider . ( ca . PrimaryUsesIntermediate ) ; ok {
return getActiveIntermediateExpiry ( s )
}
return getRootCAExpiry ( s )
} ,
}
} else {
return certExpirationMonitor {
Key : metricsKeyMeshActiveSigningCAExpiry ,
Labels : [ ] metrics . Label {
{ Name : "datacenter" , Value : s . config . Datacenter } ,
} ,
Logger : s . logger . Named ( logging . Connect ) ,
Query : func ( ) ( time . Duration , error ) {
return getActiveIntermediateExpiry ( s )
} ,
}
}
return CertExpirationMonitor {
Key : metricsKeyMeshActiveSigningCAExpiry ,
Labels : [ ] metrics . Label {
{ Name : "datacenter" , Value : s . config . Datacenter } ,
} ,
Logger : s . logger . Named ( logging . Connect ) ,
Query : func ( ) ( time . Duration , error ) {
return getActiveIntermediateExpiry ( s )
} ,
}
}
func getActiveIntermediateExpiry ( s * Server ) ( time . Duration , error ) {
@ -109,7 +113,7 @@ func getActiveIntermediateExpiry(s *Server) (time.Duration, error) {
return time . Until ( cert . NotAfter ) , nil
}
type c ertExpirationMonitor struct {
type C ertExpirationMonitor struct {
Key [ ] string
Labels [ ] metrics . Label
Logger hclog . Logger
@ -120,10 +124,12 @@ type certExpirationMonitor struct {
const certExpirationMonitorInterval = time . Hour
func ( m certExpirationMonitor ) m onitor( ctx context . Context ) error {
func ( m CertExpirationMonitor ) M onitor( ctx context . Context ) error {
ticker := time . NewTicker ( certExpirationMonitorInterval )
defer ticker . Stop ( )
logger := m . Logger . With ( "metric" , strings . Join ( m . Key , "." ) )
for {
select {
case <- ctx . Done ( ) :
@ -131,10 +137,38 @@ func (m certExpirationMonitor) monitor(ctx context.Context) error {
case <- ticker . C :
d , err := m . Query ( )
if err != nil {
m . Logger . Warn ( "failed to emit certificate expiry metric" , "error" , err )
logger . Warn ( "failed to emit certificate expiry metric" , "error" , err )
continue
}
expiry := d / time . Second
metrics . SetGaugeWithLabels ( m . Key , float32 ( expiry ) , m . Labels )
}
}
}
var metricsKeyAgentTLSCertExpiry = [ ] string { "agent" , "tls" , "cert" , "expiry" }
// AgentTLSCertExpirationMonitor returns a CertExpirationMonitor which will
// monitor the expiration of the certificate used for agent TLS.
func AgentTLSCertExpirationMonitor ( c * tlsutil . Configurator , logger hclog . Logger , dc string ) CertExpirationMonitor {
return CertExpirationMonitor {
Key : metricsKeyAgentTLSCertExpiry ,
Labels : [ ] metrics . Label {
{ Name : "node" , Value : c . Base ( ) . NodeName } ,
{ Name : "datacenter" , Value : dc } ,
} ,
Logger : logger ,
Query : func ( ) ( time . Duration , error ) {
raw := c . Cert ( )
if raw == nil {
return 0 , fmt . Errorf ( "tls not enabled" )
}
cert , err := x509 . ParseCertificate ( raw . Certificate [ 0 ] )
if err != nil {
return 0 , fmt . Errorf ( "failed to parse agent tls cert: %w" , err )
}
return time . Until ( cert . NotAfter ) , nil
} ,
}
}