open-vault/command/healthcheck/pki_enable_auto_tidy.go

195 lines
5.4 KiB
Go
Raw Normal View History

package healthcheck
import (
"fmt"
"time"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/go-secure-stdlib/parseutil"
)
type EnableAutoTidy struct {
Enabled bool
UnsupportedVersion bool
IntervalDurationCritical time.Duration
IntervalDurationWarning time.Duration
PauseDurationCritical time.Duration
PauseDurationWarning time.Duration
TidyConfig *PathFetch
}
func NewEnableAutoTidyCheck() Check {
return &EnableAutoTidy{}
}
func (h *EnableAutoTidy) Name() string {
return "enable_auto_tidy"
}
func (h *EnableAutoTidy) IsEnabled() bool {
return h.Enabled
}
func (h *EnableAutoTidy) DefaultConfig() map[string]interface{} {
return map[string]interface{}{
"interval_duration_critical": "7d",
"interval_duration_warning": "2d",
"pause_duration_critical": "1s",
"pause_duration_warning": "200ms",
}
}
func (h *EnableAutoTidy) fromConfig(config map[string]interface{}, param string) (time.Duration, error) {
value, err := parseutil.ParseDurationSecond(config[param])
if err != nil {
return time.Duration(0), fmt.Errorf("failed to parse parameter %v.%v=%v: %w", h.Name(), param, config[param], err)
}
return value, nil
}
func (h *EnableAutoTidy) LoadConfig(config map[string]interface{}) error {
var err error
h.IntervalDurationCritical, err = h.fromConfig(config, "interval_duration_critical")
if err != nil {
return err
}
h.IntervalDurationWarning, err = h.fromConfig(config, "interval_duration_warning")
if err != nil {
return err
}
h.PauseDurationCritical, err = h.fromConfig(config, "pause_duration_critical")
if err != nil {
return err
}
h.PauseDurationWarning, err = h.fromConfig(config, "pause_duration_warning")
if err != nil {
return err
}
enabled, err := parseutil.ParseBool(config["enabled"])
if err != nil {
return fmt.Errorf("error parsing %v.enabled: %w", h.Name(), err)
}
h.Enabled = enabled
return nil
}
func (h *EnableAutoTidy) FetchResources(e *Executor) error {
var err error
h.TidyConfig, err = e.FetchIfNotFetched(logical.ReadOperation, "/{{mount}}/config/auto-tidy")
if err != nil {
return err
}
if h.TidyConfig.IsUnsupportedPathError() {
h.UnsupportedVersion = true
}
return nil
}
func (h *EnableAutoTidy) Evaluate(e *Executor) (results []*Result, err error) {
if h.UnsupportedVersion {
ret := Result{
Status: ResultInvalidVersion,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: "This health check requires Vault 1.12+, but an earlier version of Vault Server was contacted, preventing this health check from running.",
}
return []*Result{&ret}, nil
}
if h.TidyConfig == nil {
return
}
if h.TidyConfig.IsSecretPermissionsError() {
ret := Result{
Status: ResultInsufficientPermissions,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: "This prevents the health check from functioning at all, as it cannot .",
}
if e.Client.Token() == "" {
ret.Message = "No token available so unable read authenticated auto-tidy configuration for this mount. " + ret.Message
} else {
ret.Message = "This token lacks permission to read the auto-tidy configuration for this mount. " + ret.Message
}
return []*Result{&ret}, nil
}
isEnabled := h.TidyConfig.Secret.Data["enabled"].(bool)
intervalDuration, err := parseutil.ParseDurationSecond(h.TidyConfig.Secret.Data["interval_duration"])
if err != nil {
return nil, fmt.Errorf("error parsing API response from server for interval_duration: %w", err)
}
pauseDuration, err := parseutil.ParseDurationSecond(h.TidyConfig.Secret.Data["pause_duration"])
if err != nil {
return nil, fmt.Errorf("error parsing API response from server for pause_duration: %w", err)
}
if !isEnabled {
ret := Result{
Status: ResultInformational,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: "Auto-tidy is currently disabled; consider enabling auto-tidy to execute tidy operations periodically. This helps the health and performance of a mount.",
}
results = append(results, &ret)
} else {
baseMsg := "Auto-tidy is configured with too long of a value for %v (%v); this could impact performance as tidies run too infrequently or take too long to execute."
if intervalDuration >= h.IntervalDurationCritical {
ret := Result{
Status: ResultCritical,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: fmt.Sprintf(baseMsg, "interval_duration", intervalDuration),
}
results = append(results, &ret)
} else if intervalDuration >= h.IntervalDurationWarning {
ret := Result{
Status: ResultWarning,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: fmt.Sprintf(baseMsg, "interval_duration", intervalDuration),
}
results = append(results, &ret)
}
if pauseDuration >= h.PauseDurationCritical {
ret := Result{
Status: ResultCritical,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: fmt.Sprintf(baseMsg, "pause_duration", pauseDuration),
}
results = append(results, &ret)
} else if pauseDuration >= h.PauseDurationWarning {
ret := Result{
Status: ResultWarning,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: fmt.Sprintf(baseMsg, "pause_duration", pauseDuration),
}
results = append(results, &ret)
}
Various health check improvements + tests (#18096) * Rename common.go->healthcheck.go Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Push handling of no resources to the health checks This allows us to better run on empty mounts. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Exit when no issuers are found This makes health checks less useful. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add additional test criteria, refactor tests This will allow us to setup more tests. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add more OK statuses when checks are good Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add test cases for all bad results The test for too-many-certs was elided for now due to being too hard to setup in CI. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add test for missing mount Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add expected failure test on empty mount Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add test for only having an issuer in the mount Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * More consistently perform permission checks Also return them to the caller when they're relevant. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add test without token Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Run health check tests in parallel Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Update command/healthcheck/healthcheck.go Co-authored-by: Steven Clark <steven.clark@hashicorp.com> * Update command/healthcheck/healthcheck.go Co-authored-by: Steven Clark <steven.clark@hashicorp.com> Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-11-23 14:42:19 +00:00
if len(results) == 0 {
ret := Result{
Status: ResultOK,
Endpoint: "/{{mount}}/config/auto-tidy",
Message: "Auto-tidy is enabled and configured appropriately.",
}
results = append(results, &ret)
}
}
return
}