Add error-logs on invalid x_forwarded_for configuration. (#11823) (#11899)

* Add error-logs on invalid x_forwarded_for configuration.

* Add Error-Logging on Invalid X-Forwarded-For configuration on startup.

* PR Feedback.

* Update changelog/_11823.txt



---------

Co-authored-by: Kit Haines <khaines@mit.edu>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
This commit is contained in:
Vault Automation 2026-04-24 14:03:43 -04:00 committed by GitHub
parent 72fe26b141
commit 40c5f44a6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 79 additions and 0 deletions

3
changelog/_11823.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
config/listener: logs warnings on invalid x-forwarded-for configurations.
```

View File

@ -19,6 +19,7 @@ import (
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/hcl/hcl/token"
"github.com/hashicorp/vault/helper/namespace"
)
@ -203,6 +204,7 @@ func (l *Listener) GoString() string {
func (l *Listener) Validate(path string) []ConfigError {
results := append(ValidateUnusedFields(l.UnusedKeys, path), ValidateUnusedFields(l.Telemetry.UnusedKeys, path)...)
results = append(results, l.validateForwardedForSettings(path)...)
return append(results, ValidateUnusedFields(l.Profiling.UnusedKeys, path)...)
}
@ -663,6 +665,80 @@ func (l *Listener) parseForwardedForSettings() error {
return nil
}
func (l *Listener) validateForwardedForSettings(fileName string) []ConfigError {
configErrors := []ConfigError{}
if len(l.XForwardedForAuthorizedAddrs) == 0 {
if l.XForwardedForRejectNotAuthorizedRaw != nil {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_authorized_addrs is not set, so forwarding is not enabled but x_forwarded_for_reject_not_authorized was set",
token.Pos{
Filename: fileName,
},
})
}
if l.XForwardedForRejectNotPresentRaw != nil {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_authorized_addrs is not set, so forwarding is not enabled but x_forwarded_for_reject_not_present was set",
token.Pos{
Filename: fileName,
},
})
}
if l.XForwardedForHopSkipsRaw != nil {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_authorized_addrs is not set, so forwarding is not enabled but x_forwarded_for_hops_skips was set",
token.Pos{
Filename: fileName,
},
})
}
if l.XForwardedForClientCertHeader != "" {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_authorized_addrs is not set, so forwarding is not enabled but x_forwarded_for_client_cert_header was set",
token.Pos{
Filename: fileName,
},
})
}
if l.XForwardedForClientCertHeaderDecoders != "" {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_authorized_addrs is not set, so forwarding is not enabled but x_forwarded_for_client_cert_header_decoders was set",
token.Pos{
Filename: fileName,
},
})
}
}
if l.XForwardedForClientCertHeader == "" && l.XForwardedForClientCertHeaderDecoders != "" {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_client_cert_header_decoders was set, but not x_forwarded_for_client_cert_header was set to be decoded",
token.Pos{
Filename: fileName,
},
})
}
if l.XForwardedForClientCertHeader != "" && l.XForwardedForClientCertHeaderDecoders == "" {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_client_cert_header was set, but no x_forwarded_for_client_cert_header_decoders were set to decode that header",
token.Pos{
Filename: fileName,
},
})
}
if strings.Contains(l.XForwardedForClientCertHeaderDecoders, "DER") && !strings.HasSuffix(l.XForwardedForClientCertHeaderDecoders, "DER") {
configErrors = append(configErrors, ConfigError{
"x_forwarded_for_client_cert_header_decoders DER decoder actually decodes PEM into DER, and therefore can only function as the final decoder",
token.Pos{
Filename: fileName,
},
})
}
return configErrors
}
// 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.