How to control haproxy-route relation data with the policy charm¶
This guide will show you how to use the haproxy-route-policy charm to control which backends are allowed to be routed through haproxy. When integrated, all haproxy-route backends are blocked by default until explicitly approved through the policy API.
Prerequisites¶
This guide assumes that you are working in a Juju model named haproxy-route-guide. You will need:
A Juju controller bootstrapped on a machine cloud (e.g. LXD)
The
haproxycharm deployed with TLS certificatesA backend requirer (e.g.
ingress-configurator) integrated withhaproxy
If you have already completed the Getting started tutorial, you can reuse that setup. Otherwise, follow the steps below to set up the required environment.
Set up the model¶
juju add-model haproxy-route-guide
Deploy HAProxy and a backend requirer¶
Deploy the haproxy charm with TLS and an ingress-configurator as the backend requirer:
juju deploy haproxy --channel=2.8/edge
juju deploy self-signed-certificates cert
juju integrate haproxy:certificates cert
juju deploy ingress-configurator requirer --channel=latest/edge
juju integrate ingress-configurator:haproxy-route haproxy
Configure the backend requirer¶
Install a web server on the requirer unit and configure the external hostname on the haproxy charm:
juju ssh requirer/0 -- sudo apt update; sudo apt install -y apache2
REQUIRER_IP=$(juju status --format json | jq -r '.applications.requirer.units."requirer/0"."public-address"')
juju config haproxy external-hostname=haproxy.internal
juju config requirer backend-addresses=$REQUIRER_IP backend-ports=80
Deploy the policy charm¶
Deploy the haproxy-route-policy charm, then integrate it with postgresql and haproxy:
juju deploy haproxy-route-policy --channel=latest/edge
juju deploy postgresql --channel=16/edge
juju relate haproxy-route-policy postgresql
juju relate haproxy-route-policy haproxy
Verify that the backend is blocked¶
Once the policy charm is integrated, all backends are blocked by default. Verify that the backend is no longer reachable:
HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
curl -H "Host: haproxy.internal" https://$HAPROXY_IP -k
You should see the HAProxy default page instead of the Apache server:
Default page for the haproxy-operator charm.
Access the policy API¶
HAProxy exposes the policy REST API through at a generated subdomain. Query the list of pending backend requests using the IP address of the HAProxy unit and the policy admin password:
HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
POLICY_ADMIN_PASSWORD=$(juju run haproxy-route-policy/0 get-admin-credentials --format json | jq -r '.results.password')
curl -H "Host: tutorial-haproxy-route-policy.haproxy.internal" -u "admin:$POLICY_ADMIN_PASSWORD" https://$HAPROXY_IP/api/v1/requests -k
The response contains a JSON list of backend requests waiting for approval.
Create an allow rule¶
Create a rule to allow backends matching the configured hostname:
HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
POLICY_ADMIN_PASSWORD=$(juju run haproxy-route-policy/0 get-admin-credentials --format json | jq -r '.results.password')
curl -H "Host: tutorial-haproxy-route-policy.haproxy.internal" -u "admin:$POLICY_ADMIN_PASSWORD" https://$HAPROXY_IP/api/v1/rules -k \
-H 'Content-Type: application/json' \
--data '{
"kind": "hostname_and_path_match",
"parameters": {"hostnames": ["haproxy.internal"]},
"action": "allow"
}'
Refresh pending requests¶
Refresh all pending requests so the new rule is evaluated against them:
HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
POLICY_ADMIN_PASSWORD=$(juju run haproxy-route-policy/0 get-admin-credentials --format json | jq -r '.results.password')
curl -H "Host: tutorial-haproxy-route-policy.haproxy.internal" -u "admin:$POLICY_ADMIN_PASSWORD" https://$HAPROXY_IP/api/v1/requests/refresh -k
Propagate approved requests¶
Run the refresh-backend-requests action to propagate the updated approvals back to the haproxy charm:
juju run haproxy-route-policy/0 refresh-backend-requests
Verify that the backend is now routed¶
The approved backend should now be reachable through HAProxy:
HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
curl -H "Host: haproxy.internal" https://$HAPROXY_IP -k
You should now see the Apache default page in the response.