$ oc new-project hello-openshift
A route allows you to host your application at a public URL. It can either be secure or unsecured, depending on the network security configuration of your application. An HTTP-based route is an unsecured route that uses the basic HTTP routing protocol and exposes a service on an unsecured application port.
The following procedure describes how to create a simple HTTP-based route to a web application, using the hello-openshift
application as an example.
You installed the OpenShift CLI (oc
).
You are logged in as an administrator.
You have a web application that exposes a port and a TCP endpoint listening for traffic on the port.
Create a project called hello-openshift
by running the following command:
$ oc new-project hello-openshift
Create a pod in the project by running the following command:
$ oc create -f https://raw.githubusercontent.com/openshift/origin/master/examples/hello-openshift/hello-pod.json
Create a service called hello-openshift
by running the following command:
$ oc expose pod/hello-openshift
Create an unsecured route to the hello-openshift
application by running the following command:
$ oc expose svc hello-openshift
To verify that the route
resource that you created, run the following command:
$ oc get routes -o yaml <name of resource> (1)
1 | In this example, the route is named hello-openshift . |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: hello-openshift
spec:
host: hello-openshift-hello-openshift.<ingress_Domain> (1)
port:
targetPort: 8080 (2)
to:
kind: Service
name: hello-openshift
1 | <ingress_Domain> is the default ingress domain name. The ingresses.config/cluster object is created during the installation and cannot be changed. If you want to specify a different domain, you can specify an alternative cluster domain using the appsDomain option. |
||
2 | targetPort is the target port on pods that is selected by the service that this route points to.
|
You can configure the default timeouts for an existing route when you have services in need of a low timeout, which is required for Service Level Availability (SLA) purposes, or a high timeout, for cases with a slow back end.
You need a deployed ingress Controller on a running cluster.
Using the oc annotate
command, add the timeout to the route:
$ oc annotate route <route_name> \
--overwrite haproxy.router.openshift.io/timeout=<timeout><time_unit> (1)
1 | Supported time units are microseconds (us), milliseconds (ms), seconds (s), minutes (m), hours (h), or days (d). |
The following example sets a timeout of two seconds on a route named myroute
:
$ oc annotate route myroute --overwrite haproxy.router.openshift.io/timeout=2s
HTTP Strict Transport Security (HSTS) policy is a security enhancement, which signals to the browser client that only HTTPS traffic is allowed on the route host. HSTS also optimizes web traffic by signaling HTTPS transport is required, without using HTTP redirects. HSTS is useful for speeding up interactions with websites.
When HSTS policy is enforced, HSTS adds a Strict Transport Security header to HTTP and HTTPS responses from the site. You can use the insecureEdgeTerminationPolicy
value in a route to redirect HTTP to HTTPS. When HSTS is enforced, the client changes all requests from the HTTP URL to HTTPS before the request is sent, eliminating the need for a redirect.
Cluster administrators can configure HSTS to do the following:
Enable HSTS per-route
Disable HSTS per-route
Enforce HSTS per-domain, for a set of domains, or use namespace labels in combination with domains
HSTS works only with secure routes, either edge-terminated or re-encrypt. The configuration is ineffective on HTTP or passthrough routes. |
HTTP strict transport security (HSTS) is implemented in the HAProxy template and applied to edge and re-encrypt routes that have the haproxy.router.openshift.io/hsts_header
annotation.
You are logged in to the cluster with a user with administrator privileges for the project.
You installed the OpenShift CLI (oc
).
To enable HSTS on a route, add the haproxy.router.openshift.io/hsts_header
value to the edge-terminated or re-encrypt route. You can use the oc annotate
tool to do this by running the following command:
$ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000;\ (1)
includeSubDomains;preload"
1 | In this example, the maximum age is set to 31536000 ms, which is approximately 8.5 hours. |
In this example, the equal sign ( |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
annotations:
haproxy.router.openshift.io/hsts_header: max-age=31536000;includeSubDomains;preload (1) (2) (3)
...
spec:
host: def.abc.com
tls:
termination: "reencrypt"
...
wildcardPolicy: "Subdomain"
1 | Required. max-age measures the length of time, in seconds, that the HSTS policy is in effect. If set to 0 , it negates the policy. |
2 | Optional. When included, includeSubDomains tells the client
that all subdomains of the host must have the same HSTS policy as the host. |
3 | Optional. When max-age is greater than 0, you can add preload in haproxy.router.openshift.io/hsts_header to allow external services to include this site in their HSTS preload lists. For example, sites such as Google can construct a list of sites that have preload set. Browsers can then use these lists to determine which sites they can communicate with over HTTPS, even before they have interacted with the site. Without preload set, browsers must have interacted with the site over HTTPS, at least once, to get the header. |
To disable HTTP strict transport security (HSTS) per-route, you can set the max-age
value in the route annotation to 0
.
You are logged in to the cluster with a user with administrator privileges for the project.
You installed the OpenShift CLI (oc
).
To disable HSTS, set the max-age
value in the route annotation to 0
, by entering the following command:
$ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"
You can alternatively apply the following YAML to create the config map: Example of disabling HSTS per-route
|
To disable HSTS for every route in a namespace, enter the following command:
$ oc annotate route --all -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"
To query the annotation for all routes, enter the following command:
$ oc get route --all-namespaces -o go-template='{{range .items}}{{if .metadata.annotations}}{{$a := index .metadata.annotations "haproxy.router.openshift.io/hsts_header"}}{{$n := .metadata.name}}{{with $a}}Name: {{$n}} HSTS: {{$a}}{{"\n"}}{{else}}{{""}}{{end}}{{end}}{{end}}'
Name: routename HSTS: max-age=0
OpenShift Dedicated provides sticky sessions, which enables stateful application traffic by ensuring all traffic hits the same endpoint. However, if the endpoint pod terminates, whether through restart, scaling, or a change in configuration, this statefulness can disappear.
OpenShift Dedicated can use cookies to configure session persistence. The ingress controller selects an endpoint to handle any user requests, and creates a cookie for the session. The cookie is passed back in the response to the request and the user sends the cookie back with the next request in the session. The cookie tells the ingress controller which endpoint is handling the session, ensuring that client requests use the cookie so that they are routed to the same pod.
Cookies cannot be set on passthrough routes, because the HTTP traffic cannot be seen. Instead, a number is calculated based on the source IP address, which determines the backend. If backends change, the traffic can be directed to the wrong server, making it less sticky. If you are using a load balancer, which hides source IP, the same number is set for all connections and traffic is sent to the same pod. |
You can set a cookie name to overwrite the default, auto-generated one for the route. This allows the application receiving route traffic to know the cookie name. Deleting the cookie can force the next request to re-choose an endpoint. The result is that if a server is overloaded, that server tries to remove the requests from the client and redistribute them.
Annotate the route with the specified cookie name:
$ oc annotate route <route_name> router.openshift.io/cookie_name="<cookie_name>"
where:
<route_name>
Specifies the name of the route.
<cookie_name>
Specifies the name for the cookie.
For example, to annotate the route my_route
with the cookie name my_cookie
:
$ oc annotate route my_route router.openshift.io/cookie_name="my_cookie"
Capture the route hostname in a variable:
$ ROUTE_NAME=$(oc get route <route_name> -o jsonpath='{.spec.host}')
where:
<route_name>
Specifies the name of the route.
Save the cookie, and then access the route:
$ curl $ROUTE_NAME -k -c /tmp/cookie_jar
Use the cookie saved by the previous command when connecting to the route:
$ curl $ROUTE_NAME -k -b /tmp/cookie_jar
Path-based routes specify a path component that can be compared against a URL, which requires that the traffic for the route be HTTP based. Thus, multiple routes can be served using the same hostname, each with a different path. Routers should match routes based on the most specific path to the least.
The following table shows example routes and their accessibility:
Route | When Compared to | Accessible |
---|---|---|
www.example.com/test |
www.example.com/test |
Yes |
www.example.com |
No |
|
www.example.com/test and www.example.com |
www.example.com/test |
Yes |
www.example.com |
Yes |
|
www.example.com |
www.example.com/text |
Yes (Matched by the host, not the route) |
www.example.com |
Yes |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: route-unsecured
spec:
host: www.example.com
path: "/test" (1)
to:
kind: Service
name: service-name
1 | The path is the only added attribute for a path-based route. |
Path-based routing is not available when using passthrough TLS, as the router does not terminate TLS in that case and cannot read the contents of the request. |
OpenShift Dedicated 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.
You can only set or delete headers within an |
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:
ingressController
specapiVersion: 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:
Route
specapiVersion: 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 response header, then the value set for this header at the global level in the ingress Controller takes precedence, even if a specific route allows frames. For a request header, the Route
spec value overrides the ingressController
spec value.
This prioritization 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:
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.
The following headers are either prevented entirely from being set or deleted, or allowed under specific circumstances:
Header name | Configurable using ingressController spec |
Configurable using Route spec |
Reason for disallowment | Configurable using another method |
---|---|---|---|---|
|
No |
No |
The |
No |
|
No |
Yes |
When the |
No |
|
No |
No |
The |
Yes: the |
|
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:
|
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.
You have installed the OpenShift CLI (oc
).
You are logged into an OpenShift Dedicated 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.
Create a route definition and save it in a file called app-example-route.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:
$ 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.
The ingress Controller can set the default options for all the routes it exposes. An individual route can override some of these defaults by providing specific configurations in its annotations. Red Hat does not support adding a route annotation to an operator-managed route.
To create a whitelist with multiple source IPs or subnets, use a space-delimited list. Any other delimiter type causes the list to be ignored without a warning or error message. |
Variable | Description | Environment variable used as default |
---|---|---|
|
Sets the load-balancing algorithm. Available options are |
|
|
Disables the use of cookies to track related connections. If set to |
|
|
Specifies an optional cookie to use for this route. The name must consist of any combination of upper and lower case letters, digits, "_", and "-". The default is the hashed internal key name for the route. |
|
|
Sets the maximum number of connections that are allowed to a backing pod from a router. |
|
|
Setting |
|
|
Limits the number of concurrent TCP connections made through the same source IP address. It accepts a numeric value. |
|
|
Limits the rate at which a client with the same source IP address can make HTTP requests. It accepts a numeric value. |
|
|
Limits the rate at which a client with the same source IP address can make TCP connections. It accepts a numeric value. |
|
|
Sets a server-side timeout for the route. (TimeUnits) |
|
|
This timeout applies to a tunnel connection, for example, WebSocket over cleartext, edge, reencrypt, or passthrough routes. With cleartext, edge, or reencrypt route types, this annotation is applied as a timeout tunnel with the existing timeout value. For the passthrough route types, the annotation takes precedence over any existing timeout value set. |
|
|
You can set either an ingressController or the ingress config . This annotation redeploys the router and configures the HA proxy to emit the haproxy |
|
|
Sets the interval for the back-end health checks. (TimeUnits) |
|
|
Sets an allowlist for the route. The allowlist is a space-separated list of IP addresses and CIDR ranges for the approved source addresses. Requests from IP addresses that are not in the allowlist are dropped. The maximum number of IP addresses and CIDR ranges directly visible in the |
|
|
Sets a Strict-Transport-Security header for the edge terminated or re-encrypt route. |
|
|
Sets the rewrite path of the request on the backend. |
|
|
Sets a value to restrict cookies. The values are:
This value is applicable to re-encrypt and edge routes only. For more information, see the SameSite cookies documentation. |
|
|
Sets the policy for handling the
|
|
If the number of IP addresses and CIDR ranges in an allowlist exceeds 61, they are written into a separate file that is then referenced from haproxy.config
. This file is stored in the var/lib/haproxy/router/whitelists
folder.
To ensure that the addresses are written to the allowlist, check that the full list of CIDR ranges are listed in the ingress Controller configuration file. The etcd object size limit restricts how large a route annotation can be. Because of this, it creates a threshold for the maximum number of IP addresses and CIDR ranges that you can include in an allowlist. |
Environment variables cannot be edited. |
TimeUnits
are represented by a number followed by the unit: us
*(microseconds), ms
(milliseconds, default), s
(seconds), m
(minutes), h
*(hours), d
(days).
The regular expression is: [1-9][0-9]*(us
\|ms
\|s
\|m
\|h
\|d
).
Variable | Default | Description |
---|---|---|
|
|
Length of time between subsequent liveness checks on back ends. |
|
|
Controls the TCP FIN timeout period for the client connecting to the route. If the FIN sent to close the connection does not answer within the given time, HAProxy closes the connection. This is harmless if set to a low value and uses fewer resources on the router. |
|
|
Length of time that a client has to acknowledge or send data. |
|
|
The maximum connection time. |
|
|
Controls the TCP FIN timeout from the router to the pod backing the route. |
|
|
Length of time that a server has to acknowledge or send data. |
|
|
Length of time for TCP or WebSocket connections to remain open. This timeout period resets whenever HAProxy reloads. |
|
|
Set the maximum time to wait for a new HTTP request to appear. If this is set too low, it can cause problems with browsers and applications not expecting a small Some effective timeout values can be the sum of certain variables, rather than the specific expected timeout. For example, |
|
|
Length of time the transmission of an HTTP request can take. |
|
|
Allows the minimum frequency for the router to reload and accept new changes. |
|
|
Timeout for the gathering of HAProxy metrics. |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
annotations:
haproxy.router.openshift.io/timeout: 5500ms (1)
...
1 | Specifies the new timeout with HAProxy supported units (us , ms , s , m , h , d ). If the unit is not provided, ms is the default. |
Setting a server-side timeout value for passthrough routes too low can cause WebSocket connections to timeout frequently on that route. |
metadata:
annotations:
haproxy.router.openshift.io/ip_whitelist: 192.168.1.10
metadata:
annotations:
haproxy.router.openshift.io/ip_whitelist: 192.168.1.10 192.168.1.11 192.168.1.12
metadata:
annotations:
haproxy.router.openshift.io/ip_whitelist: 192.168.1.0/24
metadata:
annotations:
haproxy.router.openshift.io/ip_whitelist: 180.5.61.153 192.168.1.0/24 10.0.0.0/8
apiVersion: route.openshift.io/v1
kind: Route
metadata:
annotations:
haproxy.router.openshift.io/rewrite-target: / (1)
...
1 | Sets / as rewrite path of the request on the backend. |
Setting the haproxy.router.openshift.io/rewrite-target
annotation on a route specifies that the ingress Controller should rewrite paths in HTTP requests using this route before forwarding the requests to the backend application.
The part of the request path that matches the path specified in spec.path
is replaced with the rewrite target specified in the annotation.
The following table provides examples of the path rewriting behavior for various combinations of spec.path
, request path, and rewrite target.
Route.spec.path | Request path | Rewrite target | Forwarded request path |
---|---|---|---|
/foo |
/foo |
/ |
/ |
/foo |
/foo/ |
/ |
/ |
/foo |
/foo/bar |
/ |
/bar |
/foo |
/foo/bar/ |
/ |
/bar/ |
/foo |
/foo |
/bar |
/bar |
/foo |
/foo/ |
/bar |
/bar/ |
/foo |
/foo/bar |
/baz |
/baz/bar |
/foo |
/foo/bar/ |
/baz |
/baz/bar/ |
/foo/ |
/foo |
/ |
N/A (request path does not match route path) |
/foo/ |
/foo/ |
/ |
/ |
/foo/ |
/foo/bar |
/ |
/bar |
Certain special characters in haproxy.router.openshift.io/rewrite-target
require special handling because they must be escaped properly. Refer to the following table to understand how these characters are handled.
For character | Use characters | Notes |
---|---|---|
# |
\# |
Avoid # because it terminates the rewrite expression |
% |
% or %% |
Avoid odd sequences such as %%% |
‘ |
\’ |
Avoid ‘ because it is ignored |
All other valid URL characters can be used without escaping.
If you create an ingress object without specifying any TLS configuration, OpenShift Dedicated generates an insecure route. To create an ingress object that generates a secure, edge-terminated route using the default ingress certificate, you can specify an empty TLS configuration as follows.
You have a service that you want to expose.
You have access to the OpenShift CLI (oc
).
Create a YAML file for the ingress object. In this example, the file is called example-ingress.yaml
:
apiVersion: networking.k8s.io/v1
kind: ingress
metadata:
name: frontend
...
spec:
rules:
...
tls:
- {} (1)
1 | Use this exact syntax to specify TLS without specifying a custom certificate. |
Create the ingress object by running the following command:
$ oc create -f example-ingress.yaml
Verify that OpenShift Dedicated has created the expected route for the ingress object by running the following command:
$ oc get routes -o yaml
apiVersion: v1
items:
- apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: frontend-j9sdd (1)
...
spec:
...
tls: (2)
insecureEdgeTerminationPolicy: Redirect
termination: edge (3)
...
1 | The name of the route includes the name of the ingress object followed by a random suffix. |
2 | In order to use the default certificate, the route should not specify spec.certificate . |
3 | The route should specify the edge termination policy. |
The route.openshift.io/destination-ca-certificate-secret
annotation can be used on an ingress object to define a route with a custom destination CA certificate.
You may have a certificate/key pair in PEM-encoded files, where the certificate is valid for the route host.
You may have a separate CA certificate in a PEM-encoded file that completes the certificate chain.
You must have a separate destination CA certificate in a PEM-encoded file.
You must have a service that you want to expose.
Add the route.openshift.io/destination-ca-certificate-secret
to the ingress annotations:
apiVersion: networking.k8s.io/v1
kind: ingress
metadata:
name: frontend
annotations:
route.openshift.io/termination: "reencrypt"
route.openshift.io/destination-ca-certificate-secret: secret-ca-cert (1)
...
1 | The annotation references a kubernetes secret. |
The secret referenced in this annotation will be inserted into the generated route.
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: frontend
annotations:
route.openshift.io/termination: reencrypt
route.openshift.io/destination-ca-certificate-secret: secret-ca-cert
spec:
...
tls:
insecureEdgeTerminationPolicy: Redirect
termination: reencrypt
destinationCACertificate: |
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
...