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

net/haproxy: add SNI support in mapfile-based backend selection #4017

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

cluck
Copy link

@cluck cluck commented Jun 1, 2024

This adds two options to the "Map domains to backend pools using a map file".
One of the options is addressing #3641.

The first option adds all map_dom, map_str, map_beg, map_end and map_reg (regex) support.
2024-06-04_11h33_26

The second option adds SNI support.

2024-06-01_19h38_18

Defaults are chosen such that existing setups don't change behavior.


I am currently testing this in our lab, but the more testing this gets the better.

@cluck cluck changed the title net/haproxy: add SNI support in mapfile-based backend selection WIP: net/haproxy: add SNI support in mapfile-based backend selection Jun 3, 2024
@cluck
Copy link
Author

cluck commented Jun 3, 2024

I'm currently investigating why use_backend %[req.ssl_sni,lower,map(..., default_pool)] is not working as expected. When I log req.ssl_sni it is always undefined, while if I remove the default_pool from the use_backend it gets set. Workaround is either to not support defaults with SNI, or to work with e.g. tcp-request content set-var(...,ifnotset).

Also need to swap map_dom with map_str, and add map_dom as match type option.

@cluck cluck changed the title WIP: net/haproxy: add SNI support in mapfile-based backend selection net/haproxy: add SNI support in mapfile-based backend selection Jun 4, 2024
@fraenki fraenki self-assigned this Jun 5, 2024
@fraenki fraenki added the feature Adding new functionality label Jun 5, 2024
@cluck
Copy link
Author

cluck commented Jul 9, 2024

I found that multiple cascaded use_backend don't work as documented; only the first map ever seems to have any effect.

Other People have documented the issue and a fix/workaround:
https://discourse.haproxy.org/t/multiple-use-backend-with-with-different-map/3839 (May 2019)
https://discourse.haproxy.org/t/using-use-backend-rules-with-map-files/208 (Apr 2016)

I am trying to synthesize matching ACLs, but I totally fail to see where I could properly inject such ACLs from the code.

PS: The currently released Haproxy plugin is also affected.

Copy link
Member

@fraenki fraenki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that multiple cascaded use_backend don't work as documented; only the first map ever seems to have any effect.

This should be reported on the HAProxy issue tracker:
https://github.com/haproxy/haproxy/issues/

@@ -999,6 +1036,7 @@ global
{% if helpers.exists('OPNsense.HAProxy.general.tuning.maxDHSize') %}
tune.ssl.default-dh-param {{OPNsense.HAProxy.general.tuning.maxDHSize}}
{% endif %}
tune.ssl.capture-buffer-size 512
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please make this option configurable?

I'd suggest to add two new options for this:
Enable Capture Buffer (default: disabled)
Capture Buffer Size (default: 512)

These should be added to Services: HAProxy: Settings -> Global Parameters.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but SNI parsing depends on the capture buffer being enabled to work, or it fails silently.
I guess this dependency should be added to the help text in both places then.
Maybe a warning during template generation could also be added.

{% do action_options.append('use_backend %[req.hdr(host),lower,map_dom(' ~ mapfile_path ~ defaultbackend_option ~ ')]') %}
{% set backend_file_hostname_snisupport = action_data.map_use_backend_file_snisupport|default("hostonly") %}
{% if backend_file_hostname_snisupport in ("sniandhost", "snionly") %}
{% set backend_file_global_options = ['# NOTE: Map files SNI support', 'tcp-request inspect-delay 200ms', 'tcp-request content accept if { req.ssl_hello_type 1 }', ''] %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tcp-request inspect-delay would be nice to be either configurable or at least a lot higher than 200ms.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an usecase where this is required? I was led by the impression that SNI comes with the very first packet, thus any delay would indicate a non-SNI connection anyway.
PS: the 500 bytes capture buffer chosen above is below the minimum MTU required by IP/IPv6 for the same reason.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using hardcoded values is always something we should try to avoid. It may work for one use-case, but fail in other scenarios.

However, I don't think this option should silently be added here. Instead it should be documented that this feature relies on it and that the user needs to add it (because it's already available in os-haproxy with a customizable inspection delay).

@cluck
Copy link
Author

cluck commented Aug 29, 2024

I found that multiple cascaded use_backend don't work as documented; only the first map ever seems to have any effect.

This is now reported at haproxy/haproxy#2698

@fraenki
Copy link
Member

fraenki commented Dec 3, 2024

@cluck I'd like to merge this. Would you please have a look at the two review comments? Thanks!

@cluck
Copy link
Author

cluck commented Dec 4, 2024

Meanwhile haproxy/haproxy#2698 was decided to be a wontfix, thus, pairs of multiple use_backend commands really need to be guarded by matching ACLs.

I was looking for advice on where to synthesize the required ACLs in the template. I really can't find my way around there.

@fraenki
Copy link
Member

fraenki commented Dec 4, 2024

pairs of multiple use_backend commands really need to be guarded by matching ACLs

Could you provide a example haproxy.conf to demonstrate how this should be "guarded by ACLs"? Then I may be able to offer advice regarding it's implementation in os-haproxy. 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Adding new functionality
Development

Successfully merging this pull request may close these issues.

3 participants