blob: 59722ab2eff016ec0b4111bef3b78c2f0c289de6 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package healthcheck
import (
"fmt"
"github.com/hashicorp/go-secure-stdlib/parseutil"
)
type TooManyCerts struct {
Enabled bool
UnsupportedVersion bool
CountCritical int
CountWarning int
CertCounts int
FetchIssue *PathFetch
}
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 {
exit, leavesRet, _, err := pkiFetchLeavesList(e, func() {
h.UnsupportedVersion = true
})
h.FetchIssue = leavesRet
if exit || err != nil {
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
}
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
}
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
}