| // 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 |
| } |