Files
vault/internalshared/configutil/listener.go
Marc Boudreau 01cd9d37bb Add Ability to Disable Replication Status Endpoints in Listener Configuration (#23547)
* CI: Pre-emptively delete logs dir after cache restore in test-collect-reports (#23600)

* Fix OktaNumberChallenge (#23565)

* remove arg

* changelog

* exclude changelog in verifying doc/ui PRs (#23601)

* Audit: eventlogger sink node reopen on SIGHUP (#23598)

* ensure nodes are asked to reload audit files on SIGHUP

* added changelog

* Capture errors emitted from all nodes during proccessing of audit pipelines (#23582)

* Update security-scan.yml

* Listeners: Redaction only for TCP (#23592)

* redaction should only work for TCP listeners, also fix bug that allowed custom response headers for unix listeners

* fix failing test

* updates from PR feedback

* fix panic when unlocking unlocked user (#23611)

* VAULT-18307: update rotation period for aws static roles on update (#23528)

* add disable_replication_status_endpoints tcp listener config parameter

* add wrapping handler for disabled replication status endpoints setting

* adapt disable_replication_status_endpoints configuration parsing code to refactored parsing code

* refactor configuration parsing code to facilitate testing

* fix a panic when parsing configuration

* update refactored configuration parsing code

* fix merge corruption

* add changelog file

* document new TCP listener configuration parameter

* make sure disable_replication_status_endpoints only has effect on TCP listeners

* use active voice for explanation of disable_replication_status_endpoints

* fix minor merge issue

---------

Co-authored-by: Kuba Wieczorek <kuba.wieczorek@hashicorp.com>
Co-authored-by: Angel Garbarino <Monkeychip@users.noreply.github.com>
Co-authored-by: Hamid Ghaf <83242695+hghaf099@users.noreply.github.com>
Co-authored-by: Peter Wilson <peter.wilson@hashicorp.com>
Co-authored-by: Mark Collao <106274486+mcollao-hc@users.noreply.github.com>
Co-authored-by: davidadeleon <56207066+davidadeleon@users.noreply.github.com>
Co-authored-by: kpcraig <3031348+kpcraig@users.noreply.github.com>
2023-10-11 14:23:21 -04:00

691 lines
24 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package configutil
import (
"errors"
"fmt"
"net/textproto"
"regexp"
"strings"
"time"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-secure-stdlib/tlsutil"
"github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/vault/helper/namespace"
)
const (
TCP ListenerType = "tcp"
Unix ListenerType = "unix"
)
// ListenerType represents the supported types of listener.
type ListenerType string
type ListenerTelemetry struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
UnauthenticatedMetricsAccess bool `hcl:"-"`
UnauthenticatedMetricsAccessRaw interface{} `hcl:"unauthenticated_metrics_access,alias:UnauthenticatedMetricsAccess"`
}
type ListenerProfiling struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
UnauthenticatedPProfAccess bool `hcl:"-"`
UnauthenticatedPProfAccessRaw interface{} `hcl:"unauthenticated_pprof_access,alias:UnauthenticatedPProfAccessRaw"`
}
type ListenerInFlightRequestLogging struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
UnauthenticatedInFlightAccess bool `hcl:"-"`
UnauthenticatedInFlightAccessRaw interface{} `hcl:"unauthenticated_in_flight_requests_access,alias:unauthenticatedInFlightAccessRaw"`
}
// Listener is the listener configuration for the server.
type Listener struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
RawConfig map[string]interface{}
Type ListenerType
Purpose []string `hcl:"-"`
PurposeRaw interface{} `hcl:"purpose"`
Role string `hcl:"role"`
Address string `hcl:"address"`
ClusterAddress string `hcl:"cluster_address"`
MaxRequestSize int64 `hcl:"-"`
MaxRequestSizeRaw interface{} `hcl:"max_request_size"`
MaxRequestDuration time.Duration `hcl:"-"`
MaxRequestDurationRaw interface{} `hcl:"max_request_duration"`
RequireRequestHeader bool `hcl:"-"`
RequireRequestHeaderRaw interface{} `hcl:"require_request_header"`
TLSDisable bool `hcl:"-"`
TLSDisableRaw interface{} `hcl:"tls_disable"`
TLSCertFile string `hcl:"tls_cert_file"`
TLSKeyFile string `hcl:"tls_key_file"`
TLSMinVersion string `hcl:"tls_min_version"`
TLSMaxVersion string `hcl:"tls_max_version"`
TLSCipherSuites []uint16 `hcl:"-"`
TLSCipherSuitesRaw string `hcl:"tls_cipher_suites"`
TLSRequireAndVerifyClientCert bool `hcl:"-"`
TLSRequireAndVerifyClientCertRaw interface{} `hcl:"tls_require_and_verify_client_cert"`
TLSClientCAFile string `hcl:"tls_client_ca_file"`
TLSDisableClientCerts bool `hcl:"-"`
TLSDisableClientCertsRaw interface{} `hcl:"tls_disable_client_certs"`
HTTPReadTimeout time.Duration `hcl:"-"`
HTTPReadTimeoutRaw interface{} `hcl:"http_read_timeout"`
HTTPReadHeaderTimeout time.Duration `hcl:"-"`
HTTPReadHeaderTimeoutRaw interface{} `hcl:"http_read_header_timeout"`
HTTPWriteTimeout time.Duration `hcl:"-"`
HTTPWriteTimeoutRaw interface{} `hcl:"http_write_timeout"`
HTTPIdleTimeout time.Duration `hcl:"-"`
HTTPIdleTimeoutRaw interface{} `hcl:"http_idle_timeout"`
ProxyProtocolBehavior string `hcl:"proxy_protocol_behavior"`
ProxyProtocolAuthorizedAddrs []*sockaddr.SockAddrMarshaler `hcl:"-"`
ProxyProtocolAuthorizedAddrsRaw interface{} `hcl:"proxy_protocol_authorized_addrs,alias:ProxyProtocolAuthorizedAddrs"`
XForwardedForAuthorizedAddrs []*sockaddr.SockAddrMarshaler `hcl:"-"`
XForwardedForAuthorizedAddrsRaw interface{} `hcl:"x_forwarded_for_authorized_addrs,alias:XForwardedForAuthorizedAddrs"`
XForwardedForHopSkips int64 `hcl:"-"`
XForwardedForHopSkipsRaw interface{} `hcl:"x_forwarded_for_hop_skips,alias:XForwardedForHopSkips"`
XForwardedForRejectNotPresent bool `hcl:"-"`
XForwardedForRejectNotPresentRaw interface{} `hcl:"x_forwarded_for_reject_not_present,alias:XForwardedForRejectNotPresent"`
XForwardedForRejectNotAuthorized bool `hcl:"-"`
XForwardedForRejectNotAuthorizedRaw interface{} `hcl:"x_forwarded_for_reject_not_authorized,alias:XForwardedForRejectNotAuthorized"`
SocketMode string `hcl:"socket_mode"`
SocketUser string `hcl:"socket_user"`
SocketGroup string `hcl:"socket_group"`
AgentAPI *AgentAPI `hcl:"agent_api"`
ProxyAPI *ProxyAPI `hcl:"proxy_api"`
Telemetry ListenerTelemetry `hcl:"telemetry"`
Profiling ListenerProfiling `hcl:"profiling"`
InFlightRequestLogging ListenerInFlightRequestLogging `hcl:"inflight_requests_logging"`
// RandomPort is used only for some testing purposes
RandomPort bool `hcl:"-"`
CorsEnabledRaw interface{} `hcl:"cors_enabled"`
CorsEnabled bool `hcl:"-"`
CorsAllowedOrigins []string `hcl:"cors_allowed_origins"`
CorsAllowedHeaders []string `hcl:"-"`
CorsAllowedHeadersRaw []string `hcl:"cors_allowed_headers,alias:cors_allowed_headers"`
// Custom Http response headers
CustomResponseHeaders map[string]map[string]string `hcl:"-"`
CustomResponseHeadersRaw interface{} `hcl:"custom_response_headers"`
// ChrootNamespace will prepend the specified namespace to requests
ChrootNamespaceRaw interface{} `hcl:"chroot_namespace"`
ChrootNamespace string `hcl:"-"`
// Per-listener redaction configuration
RedactAddressesRaw any `hcl:"redact_addresses"`
RedactAddresses bool `hcl:"-"`
RedactClusterNameRaw any `hcl:"redact_cluster_name"`
RedactClusterName bool `hcl:"-"`
RedactVersionRaw any `hcl:"redact_version"`
RedactVersion bool `hcl:"-"`
// DisableReplicationStatusEndpoint disables the unauthenticated replication status endpoints
DisableReplicationStatusEndpointsRaw interface{} `hcl:"disable_replication_status_endpoints"`
DisableReplicationStatusEndpoints bool `hcl:"-"`
}
// AgentAPI allows users to select which parts of the Agent API they want enabled.
type AgentAPI struct {
EnableQuit bool `hcl:"enable_quit"`
}
// ProxyAPI allows users to select which parts of the Vault Proxy API they want enabled.
type ProxyAPI struct {
EnableQuit bool `hcl:"enable_quit"`
}
func (l *Listener) GoString() string {
return fmt.Sprintf("*%#v", *l)
}
func (l *Listener) Validate(path string) []ConfigError {
results := append(ValidateUnusedFields(l.UnusedKeys, path), ValidateUnusedFields(l.Telemetry.UnusedKeys, path)...)
return append(results, ValidateUnusedFields(l.Profiling.UnusedKeys, path)...)
}
// ParseSingleIPTemplate is used as a helper function to parse out a single IP
// address from a config parameter.
// If the input doesn't appear to contain the 'template' format,
// it will return the specified input unchanged.
func ParseSingleIPTemplate(ipTmpl string) (string, error) {
r := regexp.MustCompile("{{.*?}}")
if !r.MatchString(ipTmpl) {
return ipTmpl, nil
}
out, err := template.Parse(ipTmpl)
if err != nil {
return "", fmt.Errorf("unable to parse address template %q: %v", ipTmpl, err)
}
ips := strings.Split(out, " ")
switch len(ips) {
case 0:
return "", errors.New("no addresses found, please configure one")
case 1:
return strings.TrimSpace(ips[0]), nil
default:
return "", fmt.Errorf("multiple addresses found (%q), please configure one", out)
}
}
// ParseListeners attempts to parse the AST list of objects into listeners.
func ParseListeners(list *ast.ObjectList) ([]*Listener, error) {
listeners := make([]*Listener, len(list.Items))
for i, item := range list.Items {
l, err := parseListener(item)
if err != nil {
return nil, multierror.Prefix(err, fmt.Sprintf("listeners.%d:", i))
}
listeners[i] = l
}
return listeners, nil
}
// parseListener attempts to parse the AST object into a listener.
func parseListener(item *ast.ObjectItem) (*Listener, error) {
var l *Listener
var err error
// Decode the current item
if err = hcl.DecodeObject(&l, item.Val); err != nil {
return nil, err
}
// Parse and update address if required.
if l.Address, err = ParseSingleIPTemplate(l.Address); err != nil {
return nil, err
}
// Parse and update cluster address if required.
if l.ClusterAddress, err = ParseSingleIPTemplate(l.ClusterAddress); err != nil {
return nil, err
}
// Get the values for sanitizing
var m map[string]interface{}
if err := hcl.DecodeObject(&m, item.Val); err != nil {
return nil, err
}
l.RawConfig = m
// Parse type, but supply a fallback if type wasn't set.
var fallbackType string
if len(item.Keys) == 1 {
fallbackType = strings.ToLower(item.Keys[0].Token.Value().(string))
}
if err = l.parseType(fallbackType); err != nil {
return nil, err
}
// Parse out each set off settings for the listener.
for _, parser := range []func() error{
l.parseRequestSettings,
l.parseTLSSettings,
l.parseHTTPTimeoutSettings,
l.parseProxySettings,
l.parseForwardedForSettings,
l.parseTelemetrySettings,
l.parseProfilingSettings,
l.parseInFlightRequestSettings,
l.parseCORSSettings,
l.parseHTTPHeaderSettings,
l.parseChrootNamespaceSettings,
l.parseRedactionSettings,
l.parseDisableReplicationStatusEndpointSettings,
} {
err := parser()
if err != nil {
return nil, err
}
}
return l, nil
}
// Normalize returns the lower case string version of a listener type.
func (t ListenerType) Normalize() ListenerType {
return ListenerType(strings.ToLower(string(t)))
}
// String returns the string version of a listener type.
func (t ListenerType) String() string {
return string(t.Normalize())
}
// parseAndClearBool parses a raw setting as a bool configuration parameter. If
// the raw value is successfully parsed, the parsedSetting argument is set to it
// and the rawSetting argument is cleared. Otherwise, the rawSetting argument is
// left unchanged and an error is returned.
func parseAndClearBool(rawSetting *interface{}, parsedSetting *bool) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseBool(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearString parses a raw setting as a string configuration parameter.
// If the raw value is successfully parsed, the parsedSetting argument is set to
// it and the rawSetting argument is cleared. Otherwise, the rawSetting argument
// is left unchanged and an error is returned.
func parseAndClearString(rawSetting *interface{}, parsedSetting *string) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseString(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearInt parses a raw setting as an integer configuration parameter.
// If the raw value is successfully parsed, the parsedSetting argument is set to
// it and the rawSetting argument is cleared. Otherwise, the rawSetting argument
// is left unchanged and an error is returned.
func parseAndClearInt(rawSetting *interface{}, parsedSetting *int64) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseInt(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearDurationSecond parses a raw setting as a time duration
// configuration parameter. If the raw value is successfully parsed, the
// parsedSetting argument is set to it and the rawSetting argument is cleared.
// Otherwise, the rawSetting argument is left unchanged and an error is
// returned.
func parseAndClearDurationSecond(rawSetting *interface{}, parsedSetting *time.Duration) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseDurationSecond(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseDisableReplicationStatusEndpointSettings attempts to parse the raw
// disable_replication_status_endpoints setting. The receiving Listener's
// DisableReplicationStatusEndpoints field will be set with the successfully
// parsed value.
func (l *Listener) parseDisableReplicationStatusEndpointSettings() error {
if l.Type != TCP {
return nil
}
if err := parseAndClearBool(&l.DisableReplicationStatusEndpointsRaw, &l.DisableReplicationStatusEndpoints); err != nil {
return fmt.Errorf("invalid value for disable_replication_status_endpoints: %w", err)
}
return nil
}
// parseChrootNamespace attempts to parse the raw listener chroot namespace settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseChrootNamespaceSettings() error {
var (
err error
setting string
)
err = parseAndClearString(&l.ChrootNamespaceRaw, &setting)
if err != nil {
return fmt.Errorf("invalid value for chroot_namespace: %w", err)
}
l.ChrootNamespace = namespace.Canonicalize(setting)
return nil
}
// parseType attempts to sanitize and validate the type set on the listener.
// If the listener has no type set, the fallback value will be used.
// The state of the listener will be modified.
func (l *Listener) parseType(fallback string) error {
switch {
case l.Type != "":
case fallback != "":
default:
return errors.New("listener type must be specified")
}
// Use type if available, otherwise fall back.
rawType := l.Type
if rawType == "" {
rawType = ListenerType(fallback)
}
parsedType := rawType.Normalize()
// Sanity check the values
switch parsedType {
case TCP, Unix:
default:
return fmt.Errorf("unsupported listener type %q", parsedType)
}
l.Type = parsedType
return nil
}
// parseRequestSettings attempts to parse the raw listener request settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseRequestSettings() error {
if err := parseAndClearInt(&l.MaxRequestSizeRaw, &l.MaxRequestSize); err != nil {
return fmt.Errorf("error parsing max_request_size: %w", err)
}
if l.MaxRequestDurationRaw != nil {
maxRequestDuration, err := parseutil.ParseDurationSecond(l.MaxRequestDurationRaw)
if err != nil {
return fmt.Errorf("error parsing max_request_duration: %w", err)
}
if maxRequestDuration < 0 {
return errors.New("max_request_duration cannot be negative")
}
l.MaxRequestDuration = maxRequestDuration
l.MaxRequestDurationRaw = nil
}
if err := parseAndClearBool(&l.RequireRequestHeaderRaw, &l.RequireRequestHeader); err != nil {
return fmt.Errorf("invalid value for require_request_header: %w", err)
}
return nil
}
// parseTLSSettings attempts to parse the raw listener TLS settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseTLSSettings() error {
if err := parseAndClearBool(&l.TLSDisableRaw, &l.TLSDisable); err != nil {
return fmt.Errorf("invalid value for tls_disable: %w", err)
}
if l.TLSCipherSuitesRaw != "" {
tlsCipherSuites, err := tlsutil.ParseCiphers(l.TLSCipherSuitesRaw)
if err != nil {
return fmt.Errorf("invalid value for tls_cipher_suites: %w", err)
}
l.TLSCipherSuites = tlsCipherSuites
}
if err := parseAndClearBool(&l.TLSRequireAndVerifyClientCertRaw, &l.TLSRequireAndVerifyClientCert); err != nil {
return fmt.Errorf("invalid value for tls_require_and_verify_client_cert: %w", err)
}
if err := parseAndClearBool(&l.TLSDisableClientCertsRaw, &l.TLSDisableClientCerts); err != nil {
return fmt.Errorf("invalid value for tls_disable_client_certs: %w", err)
}
// Clear raw values after successful parsing.
l.TLSCipherSuitesRaw = ""
return nil
}
// parseHTTPHeaderSettings attempts to parse the raw listener HTTP header settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseHTTPHeaderSettings() error {
// Custom response headers are only supported by TCP listeners.
// Clear raw data and return early if it was something else.
if l.Type != TCP {
l.CustomResponseHeadersRaw = nil
return nil
}
// if CustomResponseHeadersRaw is nil, we still need to set the default headers
customHeadersMap, err := ParseCustomResponseHeaders(l.CustomResponseHeadersRaw)
if err != nil {
return fmt.Errorf("failed to parse custom_response_headers: %w", err)
}
l.CustomResponseHeaders = customHeadersMap
l.CustomResponseHeadersRaw = nil
return nil
}
// parseHTTPTimeoutSettings attempts to parse the raw listener HTTP timeout settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseHTTPTimeoutSettings() error {
if err := parseAndClearDurationSecond(&l.HTTPReadTimeoutRaw, &l.HTTPReadTimeout); err != nil {
return fmt.Errorf("error parsing http_read_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPReadHeaderTimeoutRaw, &l.HTTPReadHeaderTimeout); err != nil {
return fmt.Errorf("error parsing http_read_header_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPWriteTimeoutRaw, &l.HTTPWriteTimeout); err != nil {
return fmt.Errorf("error parsing http_write_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPIdleTimeoutRaw, &l.HTTPIdleTimeout); err != nil {
return fmt.Errorf("error parsing http_idle_timeout: %w", err)
}
return nil
}
// parseProxySettings attempts to parse the raw listener proxy settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseProxySettings() error {
var err error
if l.ProxyProtocolAuthorizedAddrsRaw != nil {
l.ProxyProtocolAuthorizedAddrs, err = parseutil.ParseAddrs(l.ProxyProtocolAuthorizedAddrsRaw)
if err != nil {
return fmt.Errorf("error parsing proxy_protocol_authorized_addrs: %w", err)
}
}
// Validation/sanity check on allowed settings for behavior.
switch l.ProxyProtocolBehavior {
case "allow_authorized", "deny_authorized", "use_always", "":
// Ignore these cases, they're all valid values.
// In the case of 'allow_authorized' and 'deny_authorized', we don't need
// to check how many addresses we have in ProxyProtocolAuthorizedAddrs
// as parseutil.ParseAddrs returns "one or more addresses" (or an error)
// so we'd have returned earlier.
default:
return fmt.Errorf("unsupported value supplied for proxy_protocol_behavior: %q", l.ProxyProtocolBehavior)
}
// Clear raw values after successful parsing.
l.ProxyProtocolAuthorizedAddrsRaw = nil
return nil
}
// parseForwardedForSettings attempts to parse the raw listener x-forwarded-for settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseForwardedForSettings() error {
var err error
if l.XForwardedForAuthorizedAddrsRaw != nil {
if l.XForwardedForAuthorizedAddrs, err = parseutil.ParseAddrs(l.XForwardedForAuthorizedAddrsRaw); err != nil {
return fmt.Errorf("error parsing x_forwarded_for_authorized_addrs: %w", err)
}
}
if l.XForwardedForHopSkipsRaw != nil {
if l.XForwardedForHopSkips, err = parseutil.ParseInt(l.XForwardedForHopSkipsRaw); err != nil {
return fmt.Errorf("error parsing x_forwarded_for_hop_skips: %w", err)
}
if l.XForwardedForHopSkips < 0 {
return fmt.Errorf("x_forwarded_for_hop_skips cannot be negative but set to %d", l.XForwardedForHopSkips)
}
l.XForwardedForHopSkipsRaw = nil
}
if err := parseAndClearBool(&l.XForwardedForRejectNotAuthorizedRaw, &l.XForwardedForRejectNotAuthorized); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_authorized: %w", err)
}
if err := parseAndClearBool(&l.XForwardedForRejectNotPresentRaw, &l.XForwardedForRejectNotPresent); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_present: %w", err)
}
// Clear raw values after successful parsing.
l.XForwardedForAuthorizedAddrsRaw = nil
return nil
}
// parseTelemetrySettings attempts to parse the raw listener telemetry settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseTelemetrySettings() error {
if err := parseAndClearBool(&l.Telemetry.UnauthenticatedMetricsAccessRaw, &l.Telemetry.UnauthenticatedMetricsAccess); err != nil {
return fmt.Errorf("invalid value for telemetry.unauthenticated_metrics_access: %w", err)
}
return nil
}
// parseProfilingSettings attempts to parse the raw listener profiling settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseProfilingSettings() error {
if err := parseAndClearBool(&l.Profiling.UnauthenticatedPProfAccessRaw, &l.Profiling.UnauthenticatedPProfAccess); err != nil {
return fmt.Errorf("invalid value for profiling.unauthenticated_pprof_access: %w", err)
}
return nil
}
// parseProfilingSettings attempts to parse the raw listener in-flight request logging settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseInFlightRequestSettings() error {
if err := parseAndClearBool(&l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw, &l.InFlightRequestLogging.UnauthenticatedInFlightAccess); err != nil {
return fmt.Errorf("invalid value for inflight_requests_logging.unauthenticated_in_flight_requests_access: %w", err)
}
return nil
}
// parseCORSSettings attempts to parse the raw listener CORS settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseCORSSettings() error {
if err := parseAndClearBool(&l.CorsEnabledRaw, &l.CorsEnabled); err != nil {
return fmt.Errorf("invalid value for cors_enabled: %w", err)
}
if strutil.StrListContains(l.CorsAllowedOrigins, "*") && len(l.CorsAllowedOrigins) > 1 {
return errors.New("cors_allowed_origins must only contain a wildcard or only non-wildcard values")
}
if len(l.CorsAllowedHeadersRaw) > 0 {
for _, header := range l.CorsAllowedHeadersRaw {
l.CorsAllowedHeaders = append(l.CorsAllowedHeaders, textproto.CanonicalMIMEHeaderKey(header))
}
}
l.CorsAllowedHeadersRaw = nil
return nil
}
// parseRedactionSettings attempts to parse the raw listener redaction settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseRedactionSettings() error {
// Redaction is only supported on TCP listeners.
// Clear raw data and return early if it was something else.
if l.Type != TCP {
l.RedactAddressesRaw = nil
l.RedactClusterNameRaw = nil
l.RedactVersionRaw = nil
return nil
}
var err error
if l.RedactAddressesRaw != nil {
if l.RedactAddresses, err = parseutil.ParseBool(l.RedactAddressesRaw); err != nil {
return fmt.Errorf("invalid value for redact_addresses: %w", err)
}
}
if l.RedactClusterNameRaw != nil {
if l.RedactClusterName, err = parseutil.ParseBool(l.RedactClusterNameRaw); err != nil {
return fmt.Errorf("invalid value for redact_cluster_name: %w", err)
}
}
if l.RedactVersionRaw != nil {
if l.RedactVersion, err = parseutil.ParseBool(l.RedactVersionRaw); err != nil {
return fmt.Errorf("invalid value for redact_version: %w", err)
}
}
l.RedactAddressesRaw = nil
l.RedactClusterNameRaw = nil
l.RedactVersionRaw = nil
return nil
}