Feature/remove request headers (#822)

* config: add RemoveRequestHeaders

Currently, we have "set_request_headers" config, which reflects envoy
route.Route.RequestHeadersToAdd. This commit add new config
"remove_request_headers", which reflects envoy RequestHeadersToRemove.

This is also a preparation for future PRs to implement disable user
identity in request headers feature.

* integration: add test for remove_request_headers
* docs: add documentation/changelog for remove_request_headers
This commit is contained in:
Cuong Manh Le 2020-06-03 21:46:51 +07:00 committed by GitHub
parent b80a419699
commit 4d5edb0d64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 5 deletions

View file

@ -80,6 +80,11 @@ type Policy struct {
// value of any existing value of a given header key. // value of any existing value of a given header key.
SetRequestHeaders map[string]string `mapstructure:"set_request_headers" yaml:"set_request_headers,omitempty"` SetRequestHeaders map[string]string `mapstructure:"set_request_headers" yaml:"set_request_headers,omitempty"`
// RemoveRequestHeaders removes a collection of headers from a downstream request.
// Note that this has lower priority than `SetRequestHeaders`, if you specify `X-Custom-Header` in both
// `SetRequestHeaders` and `RemoveRequestHeaders`, then the header won't be removed.
RemoveRequestHeaders []string `mapstructure:"remove_request_headers" yaml:"remove_request_headers,omitempty"`
// PreserveHostHeader disables host header rewriting. // PreserveHostHeader disables host header rewriting.
// //
// https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header // https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header

View file

@ -995,6 +995,24 @@ Set Request Headers allows you to set static values for given request headers. T
X-Your-favorite-authenticating-Proxy: "Pomerium" X-Your-favorite-authenticating-Proxy: "Pomerium"
``` ```
### Remove Request Headers
- Config File Key: `removet_request_headers`
- Type: array of `strings`
- Optional
Remove Request Headers allows you to remove given request headers. This can be useful if you want to prevent privacy information from being passed to downstream applications. For example:
```yaml
- from: https://httpbin.corp.example.com
to: https://httpbin.org
allowed_users:
- bdd@pomerium.io
remove_request_headers:
- X-Email
- X-Username
```
### To ### To
- `yaml`/`json` setting: `to` - `yaml`/`json` setting: `to`

View file

@ -1,5 +1,11 @@
# Changelog # Changelog
## v0.10.0
### New
- config: add remove_request_headers @cuonglm [GH-702]
## v0.9.0 ## v0.9.0
### New ### New

View file

@ -119,6 +119,7 @@ local PomeriumPolicy = function() std.flattenArrays(
set_request_headers: { set_request_headers: {
'X-Custom-Request-Header': 'custom-request-header-value', 'X-Custom-Request-Header': 'custom-request-header-value',
}, },
remove_request_headers: ['X-Custom-Request-Header-To-Remove'],
}, },
{ {
from: 'http://restricted-' + domain + '.localhost.pomerium.io', from: 'http://restricted-' + domain + '.localhost.pomerium.io',

View file

@ -147,6 +147,38 @@ func TestSetRequestHeaders(t *testing.T) {
} }
func TestRemoveRequestHeaders(t *testing.T) {
ctx := mainCtx
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
defer clearTimeout()
client := testcluster.NewHTTPClient()
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/", nil)
if err != nil {
t.Fatal(err)
}
req.Header.Add("X-Custom-Request-Header-To-Remove", "foo")
res, err := client.Do(req)
if !assert.NoError(t, err, "unexpected http error") {
return
}
defer res.Body.Close()
var result struct {
Headers map[string]string `json:"headers"`
}
err = json.NewDecoder(res.Body).Decode(&result)
if !assert.NoError(t, err) {
return
}
_, exist := result.Headers["X-Custom-Request-Header-To-Remove"]
assert.False(t, exist, "expected X-Custom-Request-Header-To-Remove not to be present.")
}
func TestWebsocket(t *testing.T) { func TestWebsocket(t *testing.T) {
ctx := mainCtx ctx := mainCtx
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30) ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)

View file

@ -182,7 +182,8 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
Timeout: routeTimeout, Timeout: routeTimeout,
}, },
}, },
RequestHeadersToAdd: requestHeadersToAdd, RequestHeadersToAdd: requestHeadersToAdd,
RequestHeadersToRemove: policy.RemoveRequestHeaders,
}) })
} }
return routes return routes

View file

@ -221,8 +221,15 @@ func Test_buildPolicyRoutes(t *testing.T) {
Source: &config.StringURL{URL: mustParseURL("https://example.com")}, Source: &config.StringURL{URL: mustParseURL("https://example.com")},
Regex: `^/[a]+$`, Regex: `^/[a]+$`,
}, },
{
Source: &config.StringURL{URL: mustParseURL("https://example.com")},
Prefix: "/some/prefix/",
RemoveRequestHeaders: []string{"HEADER-KEY"},
UpstreamTimeout: time.Minute,
},
}, },
}, "example.com") }, "example.com")
testutil.AssertProtoJSONEqual(t, ` testutil.AssertProtoJSONEqual(t, `
[ [
{ {
@ -240,7 +247,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
}, },
"route": { "route": {
"autoHostRewrite": true, "autoHostRewrite": true,
"cluster": "policy-d00072a199d7b614", "cluster": "policy-4e2763e591b22dc8",
"timeout": "3s", "timeout": "3s",
"upgradeConfigs": [{ "upgradeConfigs": [{
"enabled": false, "enabled": false,
@ -263,7 +270,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
}, },
"route": { "route": {
"autoHostRewrite": false, "autoHostRewrite": false,
"cluster": "policy-907a31075a413547", "cluster": "policy-e5d20435224ae9b",
"timeout": "0s", "timeout": "0s",
"upgradeConfigs": [{ "upgradeConfigs": [{
"enabled": true, "enabled": true,
@ -286,7 +293,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
}, },
"route": { "route": {
"autoHostRewrite": true, "autoHostRewrite": true,
"cluster": "policy-f05528f790686bc3", "cluster": "policy-6e7239b3980df01f",
"timeout": "60s", "timeout": "60s",
"upgradeConfigs": [{ "upgradeConfigs": [{
"enabled": false, "enabled": false,
@ -319,13 +326,37 @@ func Test_buildPolicyRoutes(t *testing.T) {
}, },
"route": { "route": {
"autoHostRewrite": true, "autoHostRewrite": true,
"cluster": "policy-e5d3a05ff1f97659", "cluster": "policy-7bf4b11bf99ced85",
"timeout": "3s", "timeout": "3s",
"upgradeConfigs": [{ "upgradeConfigs": [{
"enabled": false, "enabled": false,
"upgradeType": "websocket" "upgradeType": "websocket"
}] }]
} }
},
{
"name": "policy-5",
"match": {
"prefix": "/some/prefix/"
},
"metadata": {
"filterMetadata": {
"envoy.filters.http.lua": {
"remove_pomerium_authorization": true,
"remove_pomerium_cookie": "pomerium"
}
}
},
"route": {
"autoHostRewrite": true,
"cluster": "policy-6b5e934ff586365d",
"timeout": "60s",
"upgradeConfigs": [{
"enabled": false,
"upgradeType": "websocket"
}]
},
"requestHeadersToRemove": ["HEADER-KEY"]
} }
] ]
`, routes) `, routes)