Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .schema/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,13 @@
"title": "Trust X-Forwarded Headers",
"description": "Trust the X-Forwarded-* headers from the reverse proxy. This is useful when running behind a load balancer or similar. Set this to false if you are not running behind a reverse proxy that prevents Hop-by-Hop attacks."
},
"trust_custom_headers": {
"type": "array",
"items": { "type": "string" },
"default": [],
"title": "Trust Custom Headers",
"description": "A list of custom HTTP header names to forward from the incoming request to the upstream. Unlike trust_forwarded_headers (which controls the standard X-Forwarded-* headers), this allows forwarding arbitrary headers (e.g., X-Source-Port) set by trusted infrastructure."
},
"timeout": {
"$ref": "#/definitions/serverTimeout"
},
Expand Down
1 change: 1 addition & 0 deletions driver/configuration/config_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
ProxyServeAddressHost Key = "serve.proxy.host"
ProxyServeAddressPort Key = "serve.proxy.port"
ProxyTrustForwardedHeaders Key = "serve.proxy.trust_forwarded_headers"
ProxyTrustCustomHeaders Key = "serve.proxy.trust_custom_headers"
APIServeAddressHost Key = "serve.api.host"
APIServeAddressPort Key = "serve.api.port"
APIReadTimeout Key = "serve.api.timeout.read"
Expand Down
1 change: 1 addition & 0 deletions driver/configuration/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Provider interface {
CORS(iface string) (cors.Options, bool)

ProxyTrustForwardedHeaders() bool
ProxyTrustCustomHeaders() []string

ProviderAuthenticators
ProviderErrorHandlers
Expand Down
4 changes: 4 additions & 0 deletions driver/configuration/provider_koanf.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ func (v *KoanfProvider) ProxyTrustForwardedHeaders() bool {
return v.source.Bool(ProxyTrustForwardedHeaders)
}

func (v *KoanfProvider) ProxyTrustCustomHeaders() []string {
return v.source.Strings(ProxyTrustCustomHeaders)
}

func (v *KoanfProvider) AuthenticatorConfig(id string, override json.RawMessage, dest interface{}) error {
return v.PipelineConfig("authenticators", id, override, dest)
}
Expand Down
6 changes: 6 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ func (d *Proxy) Rewrite(r *httputil.ProxyRequest) {
}
}

for _, h := range d.c.ProxyTrustCustomHeaders() {
if v := r.In.Header.Get(h); v != "" {
r.Out.Header.Set(h, v)
}
}

EnrichRequestedURL(r)
rl, err := d.r.RuleMatcher().Match(r.Out.Context(), r.Out.Method, r.Out.URL, rule.ProtocolHTTP)
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,39 @@ func TestProxy(t *testing.T) {
"header X-Forwarded-Host=foobar.com",
},
},
{
d: "should pass and set additional trusted forwarded headers",
prep: func(t *testing.T) {
conf.SetForTest(t, configuration.ProxyTrustCustomHeaders, []string{"X-Source-Port", "X-Custom"})
},
transform: func(r *http.Request) {
r.Header.Set("X-Source-Port", "1234")
r.Header.Set("X-Custom", "abc")
},
url: ts.URL + "/authn-anon/authz-allow/cred-noop/1234",
rulesRegexp: []rule.Rule{{
Match: &rule.Match{Methods: []string{"GET"}, URL: ts.URL + "/authn-anon/authz-allow/cred-noop/<[0-9]+>"},
Authenticators: []rule.Handler{{Handler: "anonymous"}},
Authorizer: rule.Handler{Handler: "allow"},
Mutators: []rule.Handler{{Handler: "noop"}},
Upstream: rule.Upstream{URL: backend.URL},
}},
rulesGlob: []rule.Rule{{
Match: &rule.Match{Methods: []string{"GET"}, URL: ts.URL + "/authn-anon/authz-allow/cred-noop/<[0-9]*>"},
Authenticators: []rule.Handler{{Handler: "anonymous"}},
Authorizer: rule.Handler{Handler: "allow"},
Mutators: []rule.Handler{{Handler: "noop"}},
Upstream: rule.Upstream{URL: backend.URL},
}},
code: http.StatusOK,
messages: []string{
"authorization=",
"url=/authn-anon/authz-allow/cred-noop/1234",
"host=" + x.ParseURLOrPanic(backend.URL).Host,
"header X-Source-Port=1234",
"header X-Custom=abc",
},
},
{
d: "should pass and remove x-forwarded headers",
transform: func(r *http.Request) {
Expand Down
7 changes: 7 additions & 0 deletions spec/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,13 @@
"title": "Trust X-Forwarded Headers",
"description": "Trust the X-Forwarded-* headers from the reverse proxy. This is useful when running behind a load balancer or similar. Set this to false if you are not running behind a reverse proxy that prevents Hop-by-Hop attacks."
},
"trust_custom_headers": {
"type": "array",
"items": { "type": "string" },
"default": [],
"title": "Trust Custom Headers",
"description": "A list of custom HTTP header names to forward from the incoming request to the upstream. Unlike trust_forwarded_headers (which controls the standard X-Forwarded-* headers), this allows forwarding arbitrary headers (e.g., X-Source-Port) set by trusted infrastructure."
},
"timeout": {
"$ref": "#/definitions/serverTimeout"
},
Expand Down
Loading