Using layer 7 redirection
Unlike TCP-based load balancers, which may be considered low-level, Layer 7 load balancers follow high-level application logic to redirect client requests to back-end server pools. They take their name from the OSI model, where Layer 7 is also known as the Application Layer. A Layer 7, or simply L7, load balancer decides where to redirect incoming packets based on URI, host, HTTP headers, etc.
One common application of L7 load balancing is HTTP to HTTPS redirection. More specifically, you may have an HTTPS-terminated load balancer that distributes incoming client traffic to one or more back-end services, and you are looking for a way to automatically turn each HΤTP request into an HTTPS one. To have this kind of automatic redirection, you equip your load balancer with a new listener that acknowledges incoming HTTP requests and silently forwards them to the existing HTTPS-based listener.
The HTTP listener will apply a specific L7 policy to accomplish this. In
general, an L7 policy is nothing but a set of one or more L7 rules,
along with a predefined action. That action is fallowed when all L7
rules evaluate to true
, and we should point out that an L7 rule is
a logical test that evaluates to either true
or false
.
In what follows, we show, step by step, how we add such a listener, policy, and set of rules to an existing HTTPS-terminated load balancer.
Prerequisites
The Breqwatr Cloud Management Panel does not support defining L7 policies and rules, so you
will have to work with the OpenStack CLI. Enable
it for the region you
will be working in, and make sure you have the Python octaviaclient
module installed. For that, use either the package manager of your
operating system or pip
:
=== "Debian/Ubuntu"
bash
apt install python3-octaviaclient
=== "Mac OS X with Homebrew"
This particular Python module is unavailable via brew
, but you
can install it via pip
.
=== "Python Package"
bash
pip install python-octaviaclient
Assumptions and scenario
We assume you already have an HTTPS-terminated load
balancer that forwards client
requests to a back-end server pool. In our test scenario, the load
balancer was accepting HTTPS requests for whoogle.example.com
and
forwarding them to a two-member pool, with servers each running a
Docker container for Whoogle
Search.
Creating an HTTP listener
Here is mylb
, the load balancer we used during testing...
$ openstack loadbalancer list
+---------------+------+---------------+--------------+---------------------+------------------+----------+
| id | name | project_id | vip_address | provisioning_status | operating_status | provider |
+---------------+------+---------------+--------------+---------------------+------------------+----------+
| eaf6d4f3- | mylb | dfc7004673964 | 10.15.25.155 | ACTIVE | ONLINE | amphora |
| 8d73-4b77- | | 28bacba4376e7 | | | | |
| 8bc4- | | 2cc3e9 | | | | |
| 788a3b4e3916 | | | | | | |
+---------------+------+---------------+--------------+---------------------+------------------+----------+
...and here is mylb-listener-https
, the HTTPS-terminated listener of
mylb
:
$ openstack loadbalancer listener list
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
| id | default_pool_id | name | project_id | protocol | protocol_port | admin_state_up |
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
| 95414884- | 3a683bfb-6c77- | mylb- | dfc70046739 | TERMINATED_ | 443 | True |
| f9f2-4f76- | 4ffd-befa- | listener- | 6428bacba43 | HTTPS | | |
| 8aa5- | 9f5e0e168538 | https | 76e72cc3e9 | | | |
| 56741f12825 | | | | | | |
| 2 | | | | | | |
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
You may now add mylb-listener-http
, a new HTTP-based listener for
mylb
:
openstack loadbalancer listener create \
--name mylb-listener-http \
--protocol HTTP \
--protocol-port 80 \
mylb
+-----------------------------+--------------------------------------+
| Field | Value |
+-----------------------------+--------------------------------------+
| admin_state_up | True |
| connection_limit | -1 |
| created_at | 2023-01-29T16:12:24 |
| default_pool_id | None |
| default_tls_container_ref | None |
| description | |
| id | 798e9f76-300d-4769-9dc9-2ee111ed2af7 |
| insert_headers | None |
| l7policies | |
| loadbalancers | eaf6d4f3-8d73-4b77-8bc4-788a3b4e3916 |
| name | mylb-listener-http |
| operating_status | OFFLINE |
| project_id | dfc700467396428bacba4376e72cc3e9 |
| protocol | HTTP |
| protocol_port | 80 |
| provisioning_status | PENDING_CREATE |
| sni_container_refs | [] |
| timeout_client_data | 50000 |
| timeout_member_connect | 5000 |
| timeout_member_data | 50000 |
| timeout_tcp_inspect | 0 |
| updated_at | None |
| client_ca_tls_container_ref | None |
| client_authentication | NONE |
| client_crl_container_ref | None |
| allowed_cidrs | None |
| tls_ciphers | None |
| tls_versions | None |
| alpn_protocols | None |
| tags | |
+-----------------------------+--------------------------------------+
To check the provisioning status of mylb-listener-http
, type:
openstack loadbalancer listener show mylb-listener-http -c provisioning_status
+---------------------+--------+
| Field | Value |
+---------------------+--------+
| provisioning_status | ACTIVE |
+---------------------+--------+
Have a look at both listeners of mylb
:
openstack loadbalancer listener list
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
| id | default_pool_id | name | project_id | protocol | protocol_port | admin_state_up |
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
| 95414884- | 3a683bfb-6c77- | mylb- | dfc70046739 | TERMINATED_ | 443 | True |
| f9f2-4f76- | 4ffd-befa- | listener- | 6428bacba43 | HTTPS | | |
| 8aa5- | 9f5e0e168538 | https | 76e72cc3e9 | | | |
| 56741f12825 | | | | | | |
| 2 | | | | | | |
| 798e9f76- | None | mylb- | dfc70046739 | HTTP | 80 | True |
| 300d-4769- | | listener- | 6428bacba43 | | | |
| 9dc9- | | http | 76e72cc3e9 | | | |
| 2ee111ed2af | | | | | | |
| 7 | | | | | | |
+-------------+-----------------+-------------+-------------+-------------+---------------+----------------+
Adding policies and rules
Create mylb-listener-http-policy
, a policy for mylb-listener-http
:
openstack loadbalancer l7policy create \
--action REDIRECT_PREFIX \
--redirect-prefix https://whoogle.example.com \
--name mylb-listener-http-policy \
mylb-listener-http
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| listener_id | 798e9f76-300d-4769-9dc9-2ee111ed2af7 |
| description | |
| admin_state_up | True |
| rules | |
| project_id | dfc700467396428bacba4376e72cc3e9 |
| created_at | 2023-01-29T16:24:26 |
| provisioning_status | PENDING_CREATE |
| updated_at | None |
| redirect_pool_id | None |
| redirect_url | None |
| redirect_prefix | https://whoogle.example.com |
| action | REDIRECT_PREFIX |
| position | 1 |
| id | baafb237-a7fa-4b26-b4f3-a8e5a0e5ec40 |
| operating_status | OFFLINE |
| name | mylb-listener-http-policy |
| redirect_http_code | 302 |
| tags | |
+---------------------+--------------------------------------+
Make sure the policy is active:
openstack loadbalancer l7policy list -c name -c provisioning_status
+---------------------------+---------------------+
| name | provisioning_status |
+---------------------------+---------------------+
| mylb-listener-http-policy | ACTIVE |
+---------------------------+---------------------+
Then, add a single rule to mylb-listener-http-policy
:
openstack loadbalancer l7rule create \
--compare-type EQUAL_TO \
--type HOST_NAME \
--value whoogle.example.com \
mylb-listener-http-policy
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| created_at | 2023-01-29T16:34:21 |
| compare_type | STARTS_WITH |
| provisioning_status | PENDING_CREATE |
| invert | False |
| admin_state_up | True |
| updated_at | None |
| value | whoogle.example.com |
| key | None |
| project_id | dfc700467396428bacba4376e72cc3e9 |
| type | PATH |
| id | 40ebeef4-9ee2-42c9-8119-c2e478b48a21 |
| operating_status | OFFLINE |
| tags | |
+---------------------+--------------------------------------+
Check the provisioning status of the new rule:
openstack loadbalancer l7policy list -c name -c provisioning_status
+---------------------------+---------------------+
| name | provisioning_status |
+---------------------------+---------------------+
| mylb-listener-http-policy | ACTIVE |
+---------------------------+---------------------+
From now on, all client attempts to reach http://whoogle.example.com
will end up at https://whoogle.example.com
. You may confirm this is
the case with any web browser or from your terminal, e.g., using curl
like this:
curl -IL http://whoogle.example.com
HTTP/1.1 302 Found
content-length: 0
location: https://whoogle.example.com/
cache-control: no-cache
HTTP/2 200
content-length: 13154
content-type: text/html; charset=utf-8
date: Tue, 31 Jan 2023 13:50:59 GMT
server: waitress
set-cookie: ...
As you can see in the output, the first thing that happens
when visiting http://whoogle.example.com
is a redirection
(HTTP/1.1 302 Found
) to https://whoogle.example.com
.