2023-03-15 16:00:52 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2022-11-18 16:04:58 +00:00
package healthcheck
import (
"fmt"
"github.com/hashicorp/go-secure-stdlib/parseutil"
)
type TooManyCerts struct {
Enabled bool
UnsupportedVersion bool
CountCritical int
CountWarning int
CertCounts int
2023-02-24 18:00:09 +00:00
FetchIssue * PathFetch
2022-11-18 16:04:58 +00:00
}
func NewTooManyCertsCheck ( ) Check {
return & TooManyCerts { }
}
func ( h * TooManyCerts ) Name ( ) string {
return "too_many_certs"
}
func ( h * TooManyCerts ) IsEnabled ( ) bool {
return h . Enabled
}
func ( h * TooManyCerts ) DefaultConfig ( ) map [ string ] interface { } {
return map [ string ] interface { } {
"count_critical" : 250000 ,
"count_warning" : 50000 ,
}
}
func ( h * TooManyCerts ) LoadConfig ( config map [ string ] interface { } ) error {
value , err := parseutil . SafeParseIntRange ( config [ "count_critical" ] , 1 , 15000000 )
if err != nil {
return fmt . Errorf ( "error parsing %v.count_critical: %w" , h . Name ( ) , err )
}
h . CountCritical = int ( value )
value , err = parseutil . SafeParseIntRange ( config [ "count_warning" ] , 1 , 15000000 )
if err != nil {
return fmt . Errorf ( "error parsing %v.count_warning: %w" , h . Name ( ) , err )
}
h . CountWarning = int ( value )
h . Enabled , err = parseutil . ParseBool ( config [ "enabled" ] )
if err != nil {
return fmt . Errorf ( "error parsing %v.enabled: %w" , h . Name ( ) , err )
}
return nil
}
func ( h * TooManyCerts ) FetchResources ( e * Executor ) error {
2022-11-18 18:42:48 +00:00
exit , leavesRet , _ , err := pkiFetchLeavesList ( e , func ( ) {
2022-11-18 16:04:58 +00:00
h . UnsupportedVersion = true
} )
2023-02-24 18:00:09 +00:00
h . FetchIssue = leavesRet
if exit || err != nil {
2022-11-18 16:04:58 +00:00
return err
}
h . CertCounts = leavesRet . ParsedCache [ "count" ] . ( int )
return nil
}
func ( h * TooManyCerts ) Evaluate ( e * Executor ) ( results [ ] * Result , err error ) {
if h . UnsupportedVersion {
// Shouldn't happen; /certs has been around forever.
ret := Result {
Status : ResultInvalidVersion ,
Endpoint : "/{{mount}}/certs" ,
Message : "This health check requires Vault 1.11+ but an earlier version of Vault Server was contacted, preventing this health check from running." ,
}
return [ ] * Result { & ret } , nil
}
2023-02-24 18:00:09 +00:00
if h . FetchIssue != nil && h . FetchIssue . IsSecretPermissionsError ( ) {
ret := Result {
Status : ResultInsufficientPermissions ,
Endpoint : h . FetchIssue . Path ,
Message : "Without this information, this health check is unable to function." ,
}
if e . Client . Token ( ) == "" {
ret . Message = "No token available so unable to list the endpoint for this mount. " + ret . Message
} else {
ret . Message = "This token lacks permission to list the endpoint for this mount. " + ret . Message
}
results = append ( results , & ret )
return
}
2022-11-18 16:04:58 +00:00
ret := Result {
Status : ResultOK ,
Endpoint : "/{{mount}}/certs" ,
Message : "This mount has an OK number of stored certificates." ,
}
baseMsg := "This PKI mount has %v outstanding stored certificates; consider using no_store=false on roles, running tidy operations periodically, and using shorter certificate lifetimes to reduce the storage pressure on this mount."
if h . CertCounts >= h . CountCritical {
ret . Status = ResultCritical
ret . Message = fmt . Sprintf ( baseMsg , h . CertCounts )
} else if h . CertCounts >= h . CountWarning {
ret . Status = ResultWarning
ret . Message = fmt . Sprintf ( baseMsg , h . CertCounts )
}
results = append ( results , & ret )
return
}