// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package healthcheck import ( "fmt" "strings" "github.com/hashicorp/go-secure-stdlib/parseutil" ) type AllowIfModifiedSince struct { Enabled bool UnsupportedVersion bool TuneData map[string]interface{} Fetcher *PathFetch } func NewAllowIfModifiedSinceCheck() Check { return &AllowIfModifiedSince{} } func (h *AllowIfModifiedSince) Name() string { return "allow_if_modified_since" } func (h *AllowIfModifiedSince) IsEnabled() bool { return h.Enabled } func (h *AllowIfModifiedSince) DefaultConfig() map[string]interface{} { return map[string]interface{}{} } func (h *AllowIfModifiedSince) LoadConfig(config map[string]interface{}) error { var err error 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 *AllowIfModifiedSince) FetchResources(e *Executor) error { var exit bool var err error exit, h.Fetcher, h.TuneData, err = fetchMountTune(e, func() { h.UnsupportedVersion = true }) if exit || err != nil { return err } return nil } func (h *AllowIfModifiedSince) Evaluate(e *Executor) (results []*Result, err error) { if h.UnsupportedVersion { ret := Result{ Status: ResultInvalidVersion, Endpoint: "/sys/mounts/{{mount}}/tune", 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.Fetcher.IsSecretPermissionsError() { ret := Result{ Status: ResultInsufficientPermissions, Endpoint: "/sys/mounts/{{mount}}/tune", Message: "Without this information, this health check is unable to function.", } if e.Client.Token() == "" { ret.Message = "No token available so unable read the tune endpoint for this mount. " + ret.Message } else { ret.Message = "This token lacks permission to read the tune endpoint for this mount. " + ret.Message } results = append(results, &ret) return } req, err := StringList(h.TuneData["passthrough_request_headers"]) if err != nil { return nil, fmt.Errorf("unable to parse value from server for passthrough_request_headers: %w", err) } resp, err := StringList(h.TuneData["allowed_response_headers"]) if err != nil { return nil, fmt.Errorf("unable to parse value from server for allowed_response_headers: %w", err) } foundIMS := false for _, param := range req { if strings.EqualFold(param, "If-Modified-Since") { foundIMS = true break } } foundLM := false for _, param := range resp { if strings.EqualFold(param, "Last-Modified") { foundLM = true break } } if !foundIMS || !foundLM { ret := Result{ Status: ResultInformational, Endpoint: "/sys/mounts/{{mount}}/tune", Message: "Mount hasn't enabled If-Modified-Since Request or Last-Modified Response headers; consider enabling these headers to allow clients to fetch CAs and CRLs only when they've changed, reducing total bandwidth.", } results = append(results, &ret) } else { ret := Result{ Status: ResultOK, Endpoint: "/sys/mounts/{{mount}}/tune", Message: "Mount allows the If-Modified-Since request header and Last-Modified response header.", } results = append(results, &ret) } return }