Skip to content
Open
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
8 changes: 6 additions & 2 deletions haproxy-operator/templates/haproxy_route.cfg.j2
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ frontend haproxy
{{ ddos_protection_rules() }}

# Redirect HTTP to HTTPS
http-request redirect scheme https unless { ssl_fc } {% for acl in acls_for_allow_http %} || {{ acl }}{% endfor %}
{% for acl in acls_for_allow_http %}
acl is_allow_http {{ acl }}
{% endfor %}
http-request redirect scheme https unless { ssl_fc } {% if acls_for_allow_http %}|| is_allow_http{% endif %}

{% if enable_hsts %}
# Add HSTS header for HTTPS connections (only when HTTP is not allowed)
http-response set-header Strict-Transport-Security "max-age=2592000" if { ssl_fc } {% for acl in acls_for_allow_http %} !{{ acl }}{% endfor %}
http-response set-header Strict-Transport-Security "max-age=2592000" if { ssl_fc } {% if acls_for_allow_http %}!is_allow_http{% endif %}

{% endif %}

{% for spoe_auth_info in spoe_auth_info_list %}
Expand Down
70 changes: 69 additions & 1 deletion haproxy-operator/tests/unit/test_hsts.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,81 @@ def test_hsts_disabled_allow_http(monkeypatch: pytest.MonkeyPatch, certificates_
state,
)
assert render_file_mock.call_count == 1
haproxy_conf_contents = render_file_mock.call_args.args[1]
assert (
"acl is_allow_http { req.hdr(host),field(1,:) -i haproxy.internal }"
in haproxy_conf_contents
)
render_file_mock.assert_any_call(
pathlib.Path("/etc/haproxy/haproxy.cfg"),
RegexMatcher(
re.escape(
'http-response set-header Strict-Transport-Security "max-age=2592000" if { ssl_fc } !{ req.hdr(host),field(1,:) -i haproxy.internal }\n'
'http-response set-header Strict-Transport-Security "max-age=2592000" if { ssl_fc } !is_allow_http\n'
)
),
ANY,
)
assert out.unit_status.name == ops.testing.ActiveStatus.name


@pytest.mark.usefixtures("systemd_mock", "mocks_external_calls")
def test_redirect_without_allow_http_uses_named_acl(
monkeypatch: pytest.MonkeyPatch, certificates_integration
):
"""
arrange: Prepare a haproxy with haproxy_route without allow_http.
act: trigger relation changed.
assert: haproxy.conf uses inline ssl_fc for the redirect rule without is_allow_http ACL.
"""
render_file_mock = MagicMock()
monkeypatch.setattr("haproxy.render_file", render_file_mock)
haproxy_route_relation = build_haproxy_route_relation()

ctx = ops.testing.Context(HAProxyCharm)
state = ops.testing.State(
relations=[certificates_integration, haproxy_route_relation],
)
out = ctx.run(
ctx.on.relation_changed(haproxy_route_relation),
state,
)
assert render_file_mock.call_count == 1
haproxy_conf_contents = render_file_mock.call_args.args[1]
assert "acl is_allow_http" not in haproxy_conf_contents
assert "http-request redirect scheme https unless { ssl_fc }" in haproxy_conf_contents
assert out.unit_status.name == ops.testing.ActiveStatus.name


@pytest.mark.usefixtures("systemd_mock", "mocks_external_calls")
def test_redirect_allow_http_uses_named_acl(
monkeypatch: pytest.MonkeyPatch, certificates_integration
):
"""
arrange: Prepare a haproxy with haproxy_route with allow_http enabled.
act: trigger relation changed.
assert: haproxy.conf uses is_allow_http named ACL for both redirect and HSTS rules.
"""
render_file_mock = MagicMock()
monkeypatch.setattr("haproxy.render_file", render_file_mock)
haproxy_route_relation = build_haproxy_route_relation()
haproxy_route_relation.remote_app_data["allow_http"] = "true"

ctx = ops.testing.Context(HAProxyCharm)
state = ops.testing.State(
relations=[certificates_integration, haproxy_route_relation],
)
out = ctx.run(
ctx.on.relation_changed(haproxy_route_relation),
state,
)
assert render_file_mock.call_count == 1
haproxy_conf_contents = render_file_mock.call_args.args[1]
assert (
"acl is_allow_http { req.hdr(host),field(1,:) -i haproxy.internal }"
in haproxy_conf_contents
)
assert (
"http-request redirect scheme https unless { ssl_fc } || is_allow_http"
in haproxy_conf_contents
)
assert out.unit_status.name == ops.testing.ActiveStatus.name
Loading