From 6b4ed1fd8915d5d991f1f786b7d297972cb84288 Mon Sep 17 00:00:00 2001
From: Devesh Kumar
Date: Wed, 26 Jul 2023 01:27:29 +0200
Subject: [PATCH] internal/contour: Add Support for custom headers on HTTPProxy
level
Introduces support for request and repsonse headers on http proxy level
Fixes: #5576
Signed-off-by: Devesh Kumar
---
apis/projectcontour/v1/httpproxy.go | 38 ++++++
.../v1/zz_generated.deepcopy.go | 10 ++
changelogs/unreleased/5586-deveshk0-minor.md | 27 ++++
examples/contour/01-crds.yaml | 115 +++++++++++++++++-
examples/render/contour-deployment.yaml | 115 +++++++++++++++++-
.../render/contour-gateway-provisioner.yaml | 115 +++++++++++++++++-
examples/render/contour-gateway.yaml | 115 +++++++++++++++++-
examples/render/contour.yaml | 115 +++++++++++++++++-
internal/dag/builder_test.go | 84 ++++++++++++-
internal/dag/dag.go | 7 ++
internal/dag/httpproxy_processor.go | 22 ++++
internal/envoy/v3/route.go | 9 ++
internal/envoy/v3/route_test.go | 79 +++++++++++-
.../docs/main/config/api-reference.html | 70 ++++++++++-
.../docs/main/config/request-rewriting.md | 36 +++++-
15 files changed, 927 insertions(+), 30 deletions(-)
create mode 100644 changelogs/unreleased/5586-deveshk0-minor.md
diff --git a/apis/projectcontour/v1/httpproxy.go b/apis/projectcontour/v1/httpproxy.go
index 976795d6903..47f7b5037a3 100644
--- a/apis/projectcontour/v1/httpproxy.go
+++ b/apis/projectcontour/v1/httpproxy.go
@@ -348,6 +348,24 @@ type VirtualHost struct {
// +optional
JWTProviders []JWTProvider `json:"jwtProviders,omitempty"`
+ // The policy for managing request headers during proxying.
+ // Headers are appended to requests in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
+ // +optional
+ RequestHeadersPolicy *HeadersPolicy `json:"requestHeadersPolicy,omitempty"`
+ // The policy for managing response headers during proxying.
+ // Rewriting the 'Host' header is not supported.
+ // Headers are appended to responses in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
+ // +optional
+ ResponseHeadersPolicy *HeadersPolicy `json:"responseHeadersPolicy,omitempty"`
+
// IPAllowFilterPolicy is a list of ipv4/6 filter rules for which matching
// requests should be allowed. All other requests will be denied.
// Only one of IPAllowFilterPolicy and IPDenyFilterPolicy can be defined.
@@ -584,10 +602,20 @@ type Route struct {
// **NOTE: The header rewrite is only done while forwarding and has no bearing
// on the routing decision.
//
+ // Headers are appended to requests in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
// +optional
RequestHeadersPolicy *HeadersPolicy `json:"requestHeadersPolicy,omitempty"`
// The policy for managing response headers during proxying.
// Rewriting the 'Host' header is not supported.
+ // Headers are appended to responses in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
// +optional
ResponseHeadersPolicy *HeadersPolicy `json:"responseHeadersPolicy,omitempty"`
// The policies for rewriting Set-Cookie header attributes. Note that
@@ -1045,10 +1073,20 @@ type Service struct {
// values
Mirror bool `json:"mirror,omitempty"`
// The policy for managing request headers during proxying.
+ // Headers are appended to requests in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
// +optional
RequestHeadersPolicy *HeadersPolicy `json:"requestHeadersPolicy,omitempty"`
// The policy for managing response headers during proxying.
// Rewriting the 'Host' header is not supported.
+ // Headers are appended to responses in the following order,
+ // weighted cluster level headers,
+ // route level headers,
+ // virtual host level headers,
+ // global level headers.
// +optional
ResponseHeadersPolicy *HeadersPolicy `json:"responseHeadersPolicy,omitempty"`
// The policies for rewriting Set-Cookie header attributes.
diff --git a/apis/projectcontour/v1/zz_generated.deepcopy.go b/apis/projectcontour/v1/zz_generated.deepcopy.go
index 3207fef641a..f88785597f8 100644
--- a/apis/projectcontour/v1/zz_generated.deepcopy.go
+++ b/apis/projectcontour/v1/zz_generated.deepcopy.go
@@ -1481,6 +1481,16 @@ func (in *VirtualHost) DeepCopyInto(out *VirtualHost) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.RequestHeadersPolicy != nil {
+ in, out := &in.RequestHeadersPolicy, &out.RequestHeadersPolicy
+ *out = new(HeadersPolicy)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.ResponseHeadersPolicy != nil {
+ in, out := &in.ResponseHeadersPolicy, &out.ResponseHeadersPolicy
+ *out = new(HeadersPolicy)
+ (*in).DeepCopyInto(*out)
+ }
if in.IPAllowFilterPolicy != nil {
in, out := &in.IPAllowFilterPolicy, &out.IPAllowFilterPolicy
*out = make([]IPFilterPolicy, len(*in))
diff --git a/changelogs/unreleased/5586-deveshk0-minor.md b/changelogs/unreleased/5586-deveshk0-minor.md
new file mode 100644
index 00000000000..6c1d7d6ddab
--- /dev/null
+++ b/changelogs/unreleased/5586-deveshk0-minor.md
@@ -0,0 +1,27 @@
+## HTTPProxy: Allow custom host header on HttpProxy level.
+
+This Change allows you set custom host headers on httpProxy level, Please note headers are appended to requests/responses in the following order: weighted cluster level headers, route level headers, virtual host level headers and finally global level headers.
+
+#### Example
+```yaml
+apiVersion: projectcontour.io/v1
+kind: HTTPProxy
+metadata:
+ name: custom-host-header
+spec:
+ fqdn: local.projectcontour.io
+ requestHeadersPolicy:
+ set:
+ - name: x-header
+ value: somevalue
+ responseHeadersPolicy:
+ set:
+ - name: x-powered-by
+ value: contour
+ routes:
+ - conditions:
+ - prefix: /
+ services:
+ - name: s1
+ port: 80
+```
\ No newline at end of file
diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml
index e722f3952f5..5696fca49cc 100644
--- a/examples/contour/01-crds.yaml
+++ b/examples/contour/01-crds.yaml
@@ -6383,6 +6383,11 @@ spec:
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6472,6 +6477,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6673,8 +6683,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -6709,6 +6724,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7081,8 +7101,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7117,6 +7142,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7815,6 +7845,83 @@ spec:
- unit
type: object
type: object
+ requestHeadersPolicy:
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
+ responseHeadersPolicy:
+ description: |-
+ The policy for managing response headers during proxying.
+ Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
tls:
description: |-
If present the fields describes TLS properties of the virtual
diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml
index 8e55222cf8b..8a72debd56f 100644
--- a/examples/render/contour-deployment.yaml
+++ b/examples/render/contour-deployment.yaml
@@ -6603,6 +6603,11 @@ spec:
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6692,6 +6697,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6893,8 +6903,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -6929,6 +6944,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7301,8 +7321,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7337,6 +7362,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -8035,6 +8065,83 @@ spec:
- unit
type: object
type: object
+ requestHeadersPolicy:
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
+ responseHeadersPolicy:
+ description: |-
+ The policy for managing response headers during proxying.
+ Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
tls:
description: |-
If present the fields describes TLS properties of the virtual
diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml
index 46a3eea4987..c048e4f984d 100644
--- a/examples/render/contour-gateway-provisioner.yaml
+++ b/examples/render/contour-gateway-provisioner.yaml
@@ -6394,6 +6394,11 @@ spec:
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6483,6 +6488,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6684,8 +6694,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -6720,6 +6735,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7092,8 +7112,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7128,6 +7153,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7826,6 +7856,83 @@ spec:
- unit
type: object
type: object
+ requestHeadersPolicy:
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
+ responseHeadersPolicy:
+ description: |-
+ The policy for managing response headers during proxying.
+ Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
tls:
description: |-
If present the fields describes TLS properties of the virtual
diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml
index 2489a481d34..1ccf9b45bef 100644
--- a/examples/render/contour-gateway.yaml
+++ b/examples/render/contour-gateway.yaml
@@ -6419,6 +6419,11 @@ spec:
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6508,6 +6513,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6709,8 +6719,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -6745,6 +6760,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7117,8 +7137,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7153,6 +7178,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7851,6 +7881,83 @@ spec:
- unit
type: object
type: object
+ requestHeadersPolicy:
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
+ responseHeadersPolicy:
+ description: |-
+ The policy for managing response headers during proxying.
+ Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
tls:
description: |-
If present the fields describes TLS properties of the virtual
diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml
index aa7c4c33bbe..036e111f957 100644
--- a/examples/render/contour.yaml
+++ b/examples/render/contour.yaml
@@ -6603,6 +6603,11 @@ spec:
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6692,6 +6697,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header names
@@ -6893,8 +6903,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -6929,6 +6944,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7301,8 +7321,13 @@ spec:
- tls
type: string
requestHeadersPolicy:
- description: The policy for managing request headers during
- proxying.
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -7337,6 +7362,11 @@ spec:
description: |-
The policy for managing response headers during proxying.
Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
properties:
remove:
description: Remove specifies a list of HTTP header
@@ -8035,6 +8065,83 @@ spec:
- unit
type: object
type: object
+ requestHeadersPolicy:
+ description: |-
+ The policy for managing request headers during proxying.
+ Headers are appended to requests in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
+ responseHeadersPolicy:
+ description: |-
+ The policy for managing response headers during proxying.
+ Rewriting the 'Host' header is not supported.
+ Headers are appended to responses in the following order,
+ weighted cluster level headers,
+ route level headers,
+ virtual host level headers,
+ global level headers.
+ properties:
+ remove:
+ description: Remove specifies a list of HTTP header names
+ to remove.
+ items:
+ type: string
+ type: array
+ set:
+ description: |-
+ Set specifies a list of HTTP header values that will be set in the HTTP header.
+ If the header does not exist it will be added, otherwise it will be overwritten with the new value.
+ items:
+ description: HeaderValue represents a header name/value
+ pair
+ properties:
+ name:
+ description: Name represents a key of a header
+ minLength: 1
+ type: string
+ value:
+ description: Value represents the value of a header
+ specified by a key
+ minLength: 1
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ type: object
tls:
description: |-
If present the fields describes TLS properties of the virtual
diff --git a/internal/dag/builder_test.go b/internal/dag/builder_test.go
index ffeced315ff..f4bc841fd4c 100644
--- a/internal/dag/builder_test.go
+++ b/internal/dag/builder_test.go
@@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/assert"
core_v1 "k8s.io/api/core/v1"
+ v1 "k8s.io/api/core/v1"
networking_v1 "k8s.io/api/networking/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -8851,6 +8852,47 @@ func TestDAGInsert(t *testing.T) {
}},
},
}
+
+ // proxyWithVhostHeader has a vhost level header rewrites.
+ proxyWithVhostHeader := &contour_api_v1.HTTPProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-com",
+ Namespace: "default",
+ },
+ Spec: contour_api_v1.HTTPProxySpec{
+ VirtualHost: &contour_api_v1.VirtualHost{
+ Fqdn: "example.com",
+ RequestHeadersPolicy: &contour_api_v1.HeadersPolicy{
+ Set: []contour_api_v1.HeaderValue{{
+ Name: "In-Foo",
+ Value: "bar",
+ }},
+ Remove: []string{
+ "In-Baz",
+ },
+ },
+ ResponseHeadersPolicy: &contour_api_v1.HeadersPolicy{
+ Set: []contour_api_v1.HeaderValue{{
+ Name: "Out-Foo",
+ Value: "bar",
+ }},
+ Remove: []string{
+ "Out-Baz",
+ },
+ },
+ },
+ Routes: []contour_api_v1.Route{{
+ Conditions: []contour_api_v1.MatchCondition{{
+ Prefix: "/",
+ }},
+ Services: []contour_api_v1.Service{{
+ Name: "kuard",
+ Port: 8080,
+ }},
+ }},
+ },
+ }
+
// proxy111 has a route that rewrites headers.
proxy111 := &contour_v1.HTTPProxy{
ObjectMeta: meta_v1.ObjectMeta{
@@ -12072,6 +12114,31 @@ func TestDAGInsert(t *testing.T) {
),
},
+ "insert httpproxy with vhost-level header manipulation": {
+ objs: []any{
+ proxyWithVhostHeader, s1,
+ },
+ want: listeners(
+ &Listener{
+ Name: HTTP_LISTENER_NAME,
+ Port: 8080,
+ VirtualHosts: virtualhosts(
+ virtualhostWithHeader("example.com", map[string]string{
+ "In-Foo": "bar",
+ }, []string{"In-Baz"}, map[string]string{
+ "Out-Foo": "bar",
+ }, []string{"Out-Baz"}, &Route{
+ PathMatchCondition: prefixString("/"),
+ Clusters: []*Cluster{{
+ Upstream: service(s1),
+ SNI: "",
+ }},
+ }),
+ ),
+ },
+ ),
+ },
+
// issue 1399
"service shared across ingress and httpproxy tcpproxy": {
objs: []any{
@@ -15926,7 +15993,22 @@ func virtualhost(name string, first *Route, rest ...*Route) *VirtualHost {
}
}
-func securevirtualhost(name string, sec *core_v1.Secret, first *Route, rest ...*Route) *SecureVirtualHost {
+func virtualhostWithHeader(name string, requestSet map[string]string, requestRemove []string, responseSet map[string]string, responseRemove []string, first *Route, rest ...*Route) *VirtualHost {
+ return &VirtualHost{
+ Name: name,
+ RequestHeadersPolicy: &HeadersPolicy{
+ Set: requestSet,
+ Remove: requestRemove,
+ },
+ ResponseHeadersPolicy: &HeadersPolicy{
+ Set: responseSet,
+ Remove: responseRemove,
+ },
+ Routes: routes(append([]*Route{first}, rest...)...),
+ }
+}
+
+func securevirtualhost(name string, sec *v1.Secret, first *Route, rest ...*Route) *SecureVirtualHost {
return &SecureVirtualHost{
VirtualHost: VirtualHost{
Name: name,
diff --git a/internal/dag/dag.go b/internal/dag/dag.go
index 85fb54a6a34..4df956e577e 100644
--- a/internal/dag/dag.go
+++ b/internal/dag/dag.go
@@ -734,6 +734,13 @@ type VirtualHost struct {
// CORSPolicy is the cross-origin policy to apply to the VirtualHost.
CORSPolicy *CORSPolicy
+ // The policy for managing request headers during proxying.
+ RequestHeadersPolicy *HeadersPolicy
+
+ // The policy for managing response headers during proxying.
+ // Rewriting the 'Host' header is not supported.
+ ResponseHeadersPolicy *HeadersPolicy
+
// RateLimitPolicy defines if/how requests for the virtual host
// are rate limited.
RateLimitPolicy *RateLimitPolicy
diff --git a/internal/dag/httpproxy_processor.go b/internal/dag/httpproxy_processor.go
index 7dac1510315..48ba45843ce 100644
--- a/internal/dag/httpproxy_processor.go
+++ b/internal/dag/httpproxy_processor.go
@@ -536,6 +536,25 @@ func (p *HTTPProxyProcessor) computeHTTPProxy(proxy *contour_v1.HTTPProxy) {
return
}
insecure.CORSPolicy = cp
+ dynamicHeaders := map[string]string{
+ "CONTOUR_NAMESPACE": proxy.Namespace,
+ }
+
+ requestHeadersPolicy, err := headersPolicyRoute(proxy.Spec.VirtualHost.RequestHeadersPolicy, false, dynamicHeaders)
+ if err != nil {
+ validCond.AddErrorf(contour_api_v1.ConditionTypeRouteError, "RequestHeadersPolicyInvalid",
+ "%s on response headers", err)
+ return
+ }
+ responseHeadersPolicy, err := headersPolicyRoute(proxy.Spec.VirtualHost.ResponseHeadersPolicy, false, dynamicHeaders)
+ if err != nil {
+ validCond.AddErrorf(contour_api_v1.ConditionTypeRouteError, "ResponseHeaderPolicyInvalid",
+ "%s on response headers", err)
+ return
+ }
+
+ insecure.RequestHeadersPolicy = requestHeadersPolicy
+ insecure.ResponseHeadersPolicy = responseHeadersPolicy
var isValidRLP bool
insecure.RateLimitPolicy, isValidRLP = computeVirtualHostRateLimitPolicy(proxy, p.GlobalRateLimitService, validCond)
@@ -580,6 +599,9 @@ func (p *HTTPProxyProcessor) computeHTTPProxy(proxy *contour_v1.HTTPProxy) {
return
}
+ secure.RequestHeadersPolicy = requestHeadersPolicy
+ secure.ResponseHeadersPolicy = responseHeadersPolicy
+
addRoutes(secure, routes)
// Process JWT verification requirements.
diff --git a/internal/envoy/v3/route.go b/internal/envoy/v3/route.go
index ecc2a4934fa..517c69d5311 100644
--- a/internal/envoy/v3/route.go
+++ b/internal/envoy/v3/route.go
@@ -70,6 +70,15 @@ func VirtualHostAndRoutes(vh *dag.VirtualHost, dagRoutes []*dag.Route, secure bo
evh.RateLimits = GlobalRateLimits(vh.RateLimitPolicy.Global.Descriptors)
}
+ if vh.RequestHeadersPolicy != nil {
+ evh.RequestHeadersToAdd = append(headerValueList(vh.RequestHeadersPolicy.Set, false), headerValueList(vh.RequestHeadersPolicy.Add, true)...)
+ evh.RequestHeadersToRemove = vh.RequestHeadersPolicy.Remove
+ }
+ if vh.ResponseHeadersPolicy != nil {
+ evh.ResponseHeadersToAdd = append(headerValueList(vh.ResponseHeadersPolicy.Set, false), headerValueList(vh.ResponseHeadersPolicy.Add, true)...)
+ evh.ResponseHeadersToRemove = vh.ResponseHeadersPolicy.Remove
+ }
+
if len(vh.IPFilterRules) > 0 {
if evh.TypedPerFilterConfig == nil {
evh.TypedPerFilterConfig = map[string]*anypb.Any{}
diff --git a/internal/envoy/v3/route_test.go b/internal/envoy/v3/route_test.go
index 2f91680d7e4..b435aba1a28 100644
--- a/internal/envoy/v3/route_test.go
+++ b/internal/envoy/v3/route_test.go
@@ -19,6 +19,7 @@ import (
"time"
envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
+ envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
envoy_config_rbac_v3 "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
envoy_filter_http_cors_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cors/v3"
@@ -27,6 +28,10 @@ import (
envoy_internal_redirect_safe_cross_scheme_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/safe_cross_scheme/v3"
envoy_matcher_v3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
+ "github.com/projectcontour/contour/internal/dag"
+ "github.com/projectcontour/contour/internal/fixture"
+ "github.com/projectcontour/contour/internal/protobuf"
+ "github.com/projectcontour/contour/internal/timeout"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
@@ -2727,6 +2732,76 @@ func TestRouteRedirect(t *testing.T) {
}
}
-func virtualhosts(v ...*envoy_config_route_v3.VirtualHost) []*envoy_config_route_v3.VirtualHost {
- return v
+func virtualhosts(v ...*envoy_route_v3.VirtualHost) []*envoy_route_v3.VirtualHost { return v }
+
+func TestVirtualHostAndRoutes(t *testing.T) {
+ tests := map[string]struct {
+ vh *dag.VirtualHost
+ route []*dag.Route
+ secure bool
+ want *envoy_route_v3.VirtualHost
+ }{
+ "dag virtual host to envoy virtual host with custom header": {
+ vh: &dag.VirtualHost{
+ Name: "example.com",
+ RequestHeadersPolicy: &dag.HeadersPolicy{
+ Set: map[string]string{
+ "In-Foo": "bar",
+ },
+ Remove: []string{"In-Baz"},
+ },
+ ResponseHeadersPolicy: &dag.HeadersPolicy{
+ Set: map[string]string{
+ "Out-Foo": "bar",
+ },
+ Remove: []string{"Out-Baz"},
+ },
+ },
+ route: []*dag.Route{
+ {
+ PathMatchCondition: &dag.ExactMatchCondition{
+ Path: "/foo",
+ },
+ },
+ },
+ secure: false,
+ want: &envoy_route_v3.VirtualHost{
+ Name: "example.com",
+ Domains: []string{"example.com"},
+ RequestHeadersToAdd: []*envoy_core_v3.HeaderValueOption{{
+ Header: &envoy_core_v3.HeaderValue{
+ Key: "In-Foo",
+ Value: "bar",
+ },
+ AppendAction: envoy_core_v3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
+ }},
+ RequestHeadersToRemove: []string{"In-Baz"},
+ ResponseHeadersToAdd: []*envoy_core_v3.HeaderValueOption{{
+ Header: &envoy_core_v3.HeaderValue{
+ Key: "Out-Foo",
+ Value: "bar",
+ },
+ AppendAction: envoy_core_v3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
+ }},
+ ResponseHeadersToRemove: []string{"Out-Baz"},
+ Routes: []*envoy_route_v3.Route{
+ {
+ Match: &envoy_route_v3.RouteMatch{
+ PathSpecifier: &envoy_route_v3.RouteMatch_Path{Path: "/foo"},
+ },
+ Action: &envoy_route_v3.Route_Route{Route: &envoy_route_v3.RouteAction{
+ ClusterSpecifier: &envoy_route_v3.RouteAction_WeightedClusters{WeightedClusters: nil},
+ }},
+ },
+ },
+ },
+ },
+ }
+
+ for name, tc := range tests {
+ t.Run(name, func(t *testing.T) {
+ got := VirtualHostAndRoutes(tc.vh, tc.route, tc.secure)
+ protobuf.ExpectEqual(t, tc.want, got)
+ })
+ }
}
diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html
index 82e03f685da..4430eb9d922 100644
--- a/site/content/docs/main/config/api-reference.html
+++ b/site/content/docs/main/config/api-reference.html
@@ -2101,7 +2101,8 @@
(Appears on:
Route,
-Service)
+Service,
+VirtualHost)
HeadersPolicy defines how headers are managed during forwarding.
@@ -3742,6 +3743,11 @@
Route
Provided header must come from trusted source.
**NOTE: The header rewrite is only done while forwarding and has no bearing
on the routing decision.
+Headers are appended to requests in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
@@ -3757,7 +3763,12 @@ Route
(Optional)
The policy for managing response headers during proxying.
-Rewriting the ‘Host’ header is not supported.
+Rewriting the ‘Host’ header is not supported.
+Headers are appended to responses in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
|
@@ -4016,7 +4027,12 @@ Service
(Optional)
- The policy for managing request headers during proxying.
+The policy for managing request headers during proxying.
+Headers are appended to requests in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
|
@@ -4032,7 +4048,12 @@ Service
(Optional)
The policy for managing response headers during proxying.
-Rewriting the ‘Host’ header is not supported.
+Rewriting the ‘Host’ header is not supported.
+Headers are appended to responses in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
|
@@ -4872,6 +4893,47 @@ VirtualHost
+requestHeadersPolicy
+
+
+
+HeadersPolicy
+
+
+ |
+
+(Optional)
+ The policy for managing request headers during proxying.
+Headers are appended to requests in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
+ |
+
+
+
+responseHeadersPolicy
+
+
+
+HeadersPolicy
+
+
+ |
+
+(Optional)
+ The policy for managing response headers during proxying.
+Rewriting the ‘Host’ header is not supported.
+Headers are appended to responses in the following order,
+weighted cluster level headers,
+route level headers,
+virtual host level headers,
+global level headers.
+ |
+
+
+
ipAllowPolicy
diff --git a/site/content/docs/main/config/request-rewriting.md b/site/content/docs/main/config/request-rewriting.md
index 88fa3cc2508..3a8501e65a7 100644
--- a/site/content/docs/main/config/request-rewriting.md
+++ b/site/content/docs/main/config/request-rewriting.md
@@ -87,7 +87,7 @@ spec:
- Some-Other-Header
```
-Manipulating headers is also supported per-Service or per-Route. Headers can be set or
+Manipulating headers is also supported per-Service, per-Route, and per-VirtualHost. Headers can be set or
removed from the request or response as follows:
per-Service:
@@ -148,8 +148,38 @@ spec:
- X-Internal-Secret
```
-In these examples we are setting the header `X-Foo` with value `baz` on requests
-and stripping `X-Baz`. We are then setting `X-Service-Name` on the response with
+
+per-VirtualHost:
+
+```yaml
+apiVersion: projectcontour.io/v1
+kind: HTTPProxy
+metadata:
+ name: header-manipulation
+ namespace: default
+spec:
+ virtualhost:
+ fqdn: headers.bar.com
+ requestHeadersPolicy:
+ set:
+ - name: X-Foo
+ value: bar
+ remove:
+ - X-Bar
+ responseHeadersPolicy:
+ set:
+ - name: X-Service-Name
+ value: s1
+ remove:
+ - X-Internal-Secret
+ routes:
+ - services:
+ - name: s1
+ port: 80
+```
+
+In these examples we are setting the header `X-Foo` with value `bar` on requests
+and stripping `X-Bar`. We are then setting `X-Service-Name` on the response with
value `s1`, and removing `X-Internal-Secret`.
### Dynamic Header Values
|