Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSDOCS-5043: add http header modification feature #56177

Merged
merged 1 commit into from
Oct 18, 2023
Merged
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
122 changes: 122 additions & 0 deletions modules/nw-http-header-configuration.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Module included in the following assemblies:
//
// * networking/ingress-operator.adoc
// * networking/route-configuration.adoc

:_content-type: CONCEPT
[id="nw-http-header-configuration_{context}"]
= HTTP header configuration

{product-title} provides different methods for working with HTTP headers. When setting or deleting headers, you can use specific fields in the Ingress Controller or an individual route to modify request and response headers. You can also set certain headers by using route annotations. The various ways of configuring headers can present challenges when working together.

[NOTE]
====
You can only set or delete headers within an `IngressController` or `Route` CR, you cannot append them. If an HTTP header is set with a value, that value must be complete and not require appending in the future. In situations where it makes sense to append a header, such as the X-Forwarded-For header, use the `spec.httpHeaders.forwardedHeaderPolicy` field, instead of `spec.httpHeaders.actions`.
====

[id="nw-http-header-configuration-order_{context}"]
== Order of precedence
jldohmann marked this conversation as resolved.
Show resolved Hide resolved

When the same HTTP header is modified both in the Ingress Controller and in a route, HAProxy prioritizes the actions in certain ways depending on whether it is a request or response header.

* For HTTP response headers, actions specified in the Ingress Controller are executed after the actions specified in a route. This means that the actions specified in the Ingress Controller take precedence.

* For HTTP request headers, actions specified in a route are executed after the actions specified in the Ingress Controller. This means that the actions specified in the route take precedence.

For example, a cluster administrator sets the X-Frame-Options response header with the value `DENY` in the Ingress Controller using the following configuration:

.Example `IngressController` spec
[source,yaml]
----
apiVersion: operator.openshift.io/v1
kind: IngressController
# ...
spec:
httpHeaders:
actions:
response:
- name: X-Frame-Options
action:
type: Set
set:
value: DENY
----

A route owner sets the same response header that the cluster administrator set in the Ingress Controller, but with the value `SAMEORIGIN` using the following configuration:

.Example `Route` spec
[source,yaml]
----
apiVersion: route.openshift.io/v1
kind: Route
# ...
spec:
httpHeaders:
actions:
response:
- name: X-Frame-Options
action:
type: Set
set:
value: SAMEORIGIN
----

When both the `IngressController` spec and `Route` spec are configuring the X-Frame-Options header, then the value set for this header at the global level in the Ingress Controller will take precedence, even if a specific route allows frames.

This prioritzation occurs because the `haproxy.config` file uses the following logic, where the Ingress Controller is considered the front end and individual routes are considered the back end. The header value `DENY` applied to the front end configurations overrides the same header with the value `SAMEORIGIN` that is set in the back end:

[source,text]
----
frontend public
http-response set-header X-Frame-Options 'DENY'
frontend fe_sni
http-response set-header X-Frame-Options 'DENY'
frontend fe_no_sni
http-response set-header X-Frame-Options 'DENY'
backend be_secure:openshift-monitoring:alertmanager-main
http-response set-header X-Frame-Options 'SAMEORIGIN'
----

Additionally, any actions defined in either the Ingress Controller or a route override values set using route annotations.

[id="nw-http-header-configuration-special-cases_{context}"]
== Special case headers

The following headers are either prevented entirely from being set or deleted, or allowed under specific circumstances:

.Special case header configuration options
[cols="5*a",options="header"]
|===
|Header name |Configurable using `IngressController` spec |Configurable using `Route` spec |Reason for disallowment |Configurable using another method

|`proxy`
|No
|No
|The `proxy` HTTP request header can be used to exploit vulnerable CGI applications by injecting the header value into the `HTTP_PROXY` environment variable. The `proxy` HTTP request header is also non-standard and prone to error during configuration.
|No

|`host`
|No
|Yes
|When the `host` HTTP request header is set using the `IngressController` CR, HAProxy can fail when looking up the correct route.
|No

|`strict-transport-security`
|No
|No
|The `strict-transport-security` HTTP response header is already handled using route annotations and does not need a separate implementation.
|Yes: the `haproxy.router.openshift.io/hsts_header` route annotation

|`cookie` and `set-cookie`
|No
|No
|The cookies that HAProxy sets are used for session tracking to map client connections to particular back-end servers. Allowing these headers to be set could interfere with HAProxy's session affinity and restrict HAProxy's ownership of a cookie.
|Yes:

* the `haproxy.router.openshift.io/disable_cookie` route annotation
* the `haproxy.router.openshift.io/cookie_name` route annotation

|===
6 changes: 6 additions & 0 deletions modules/nw-ingress-controller-configuration-parameters.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ These adjustments are only applied to cleartext, edge-terminated, and re-encrypt

For request headers, these adjustments are applied only for routes that have the `haproxy.router.openshift.io/h1-adjust-case=true` annotation. For response headers, these adjustments are applied to all HTTP responses. If this field is empty, no request headers are adjusted.

`actions` specifies options for performing certain actions on headers. Headers cannot be set or deleted for TLS passthrough connections. The `actions` field has additional subfields `spec.httpHeader.actions.response` and `spec.httpHeader.actions.request`:

* The `response` subfield specifies a list of HTTP response headers to set or delete.
* The `request` subfield specifies a list of HTTP request headers to set or delete.
|`httpCompression`
|`httpCompression` defines the policy for HTTP traffic compression.

Expand Down
60 changes: 60 additions & 0 deletions modules/nw-ingress-set-or-delete-http-headers.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Module included in the following assemblies:
//
// * networking/ingress-operator.adoc

:_content-type: PROCEDURE
[id="nw-ingress-set-or-delete-http-headers_{context}"]
= Setting or deleting HTTP request and response headers in an Ingress Controller

You can set or delete certain HTTP request and response headers for compliance purposes or other reasons. You can set or delete these headers either for all routes served by an Ingress Controller or for specific routes.

For example, you might want to migrate an application running on your cluster to use mutual TLS, which requires that your application checks for an X-Forwarded-Client-Cert request header, but the {product-title} default Ingress Controller provides an X-SSL-Client-Der request header.

The following procedure modifies the Ingress Controller to set the X-Forwarded-Client-Cert request header, and delete the X-SSL-Client-Der request header.

.Prerequisites
* You have installed the OpenShift CLI (`oc`).
* You have access to an {product-title} cluster as a user with the `cluster-admin` role.
.Procedure
. Edit the Ingress Controller resource:
+
[source,terminal]
----
$ oc -n openshift-ingress-operator edit ingresscontroller/default
----

. Replace the X-SSL-Client-Der HTTP request header with the X-Forwarded-Client-Cert HTTP request header:
+
[source,yaml]
----
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
name: default
namespace: openshift-ingress-operator
spec:
httpHeaders:
actions: <1>
request: <2>
- name: X-Forwarded-Client-Cert <3>
action:
type: Set <4>
set:
value: "%{+Q}[ssl_c_der,base64]" <5>
- name: X-SSL-Client-Der
action:
type: Delete
----
<1> The list of actions you want to perform on the HTTP headers.
<2> The type of header you want to change. In this case, a request header.
<3> The name of the header you want to change. For a list of available headers you can set or delete, see _HTTP header configuration_.
<4> The type of action being taken on the header. This field can have the value `Set` or `Delete`.
<5> When setting HTTP headers, you must provide a `value`. The value can be a string from a list of available directives for that header, for example `DENY`, or it can be a dynamic value that will be interpreted using HAProxy's dynamic value syntax. In this case, a dynamic value is added.
+
[NOTE]
====
For setting dynamic header values for HTTP responses, allowed sample fetchers are `res.hdr` and `ssl_c_der`. For setting dynamic header values for HTTP requests, allowed sample fetchers are `req.hdr` and `ssl_c_der`. Both request and response dynamic values can use the `lower` and `base64` converters.
====

. Save the file to apply the changes.
58 changes: 58 additions & 0 deletions modules/nw-route-set-or-delete-http-headers.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Module included in the following assemblies:
//
// * networking/route-configuration.adoc

:_content-type: PROCEDURE
[id="nw-route-set-or-delete-http-headers_{context}"]
= Setting or deleting HTTP request and response headers in a route

You can set or delete certain HTTP request and response headers for compliance purposes or other reasons. You can set or delete these headers either for all routes served by an Ingress Controller or for specific routes.

For example, you might want to enable a web application to serve content in alternate locations for specific routes if that content is written in multiple languages, even if there is a default global location specified by the Ingress Controller serving the routes.

The following procedure creates a route that sets the Content-Location HTTP request header so that the URL associated with the application, `\https://app.example.com`, directs to the location `\https://app.example.com/lang/en-us`. Directing application traffic to this location means that anyone using that specific route is accessing web content written in American English.

.Prerequisites
* You have installed the OpenShift CLI (`oc`).
* You are logged into an {product-title} cluster as a project administrator.
* You have a web application that exposes a port and an HTTP or TLS endpoint listening for traffic on the port.
.Procedure
. Create a route definition and save it in a file called `app-example-route.yaml`:
+
.YAML definition of the created route with HTTP header directives
[source,yaml]
----
apiVersion: route.openshift.io/v1
kind: Route
# ...
spec:
host: app.example.com
tls:
termination: edge
to:
kind: Service
name: app-example
httpHeaders:
actions: <1>
response: <2>
- name: Content-Location <3>
action:
type: Set <4>
set:
value: /lang/en-us <5>
----
<1> The list of actions you want to perform on the HTTP headers.
<2> The type of header you want to change. In this case, a response header.
<3> The name of the header you want to change. For a list of available headers you can set or delete, see _HTTP header configuration_.
<4> The type of action being taken on the header. This field can have the value `Set` or `Delete`.
<5> When setting HTTP headers, you must provide a `value`. The value can be a string from a list of available directives for that header, for example `DENY`, or it can be a dynamic value that will be interpreted using HAProxy's dynamic value syntax. In this case, the value is set to the relative location of the content.

. Create a route to your existing web application using the newly created route definition:
+
[source,terminal]
----
$ oc -n app-example create -f app-example-route.yaml
----

For HTTP request headers, the actions specified in the route definitions are executed after any actions performed on HTTP request headers in the Ingress Controller. This means that any values set for those request headers in a route will take precedence over the ones set in the Ingress Controller. For more information on the processing order of HTTP headers, see _HTTP header configuration_.
4 changes: 4 additions & 0 deletions networking/ingress-operator.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ include::modules/nw-route-admission-policy.adoc[leveloffset=+2]

include::modules/using-wildcard-routes.adoc[leveloffset=+2]

include::modules/nw-http-header-configuration.adoc[leveloffset=+2]

include::modules/nw-ingress-set-or-delete-http-headers.adoc[leveloffset=+2]

include::modules/nw-using-ingress-forwarded.adoc[leveloffset=+2]

include::modules/nw-http2-haproxy.adoc[leveloffset=+2]
Expand Down
4 changes: 4 additions & 0 deletions networking/routes/route-configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ include::modules/nw-annotating-a-route-with-a-cookie-name.adoc[leveloffset=+2]

include::modules/nw-path-based-routes.adoc[leveloffset=+1]

include::modules/nw-http-header-configuration.adoc[leveloffset=+1]

include::modules/nw-route-set-or-delete-http-headers.adoc[leveloffset=+1]

include::modules/nw-route-specific-annotations.adoc[leveloffset=+1]

ifndef::openshift-rosa,openshift-dedicated[]
Expand Down