diff options
5 files changed, 68 insertions, 0 deletions
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2 index 7917c8257..797bf17e7 100644 --- a/data/templates/load-balancing/haproxy.cfg.j2 +++ b/data/templates/load-balancing/haproxy.cfg.j2 @@ -81,6 +81,11 @@ frontend {{ front }} {% endif %} {% endfor %} {% endif %} +{% if front_config.http_response_headers is vyos_defined %} +{% for header, header_config in front_config.http_response_headers.items() %} + http-response set-header {{ header }} '{{ header_config['value'] }}' +{% endfor %} +{% endif %} {% endif %} {% if front_config.rule is vyos_defined %} {% for rule, rule_config in front_config.rule.items() %} @@ -158,6 +163,11 @@ backend {{ back }} {% endif %} {% if back_config.mode is vyos_defined %} mode {{ back_config.mode }} +{% if back_config.http_response_headers is vyos_defined %} +{% for header, header_config in back_config.http_response_headers.items() %} + http-response set-header {{ header }} '{{ header_config['value'] }}' +{% endfor %} +{% endif %} {% endif %} {% if back_config.rule is vyos_defined %} {% for rule, rule_config in back_config.rule.items() %} diff --git a/interface-definitions/include/haproxy/http-response-headers.xml.i b/interface-definitions/include/haproxy/http-response-headers.xml.i new file mode 100644 index 000000000..9e7ddfd28 --- /dev/null +++ b/interface-definitions/include/haproxy/http-response-headers.xml.i @@ -0,0 +1,29 @@ +<!-- include start from haproxy/http-response-headers.xml.i --> +<tagNode name="http-response-headers"> + <properties> + <help>Headers to include in HTTP response</help> + <valueHelp> + <format>txt</format> + <description>HTTP header name</description> + </valueHelp> + <constraint> + <regex>[-a-zA-Z]+</regex> + </constraint> + <constraintErrorMessage>Header names must only include alphabetical characters and hyphens</constraintErrorMessage> + </properties> + <children> + <leafNode name="value"> + <properties> + <help>HTTP header value</help> + <valueHelp> + <format>txt</format> + <description>HTTP header value</description> + </valueHelp> + <constraint> + <regex>[[:ascii:]]{1,256}</regex> + </constraint> + </properties> + </leafNode> + </children> +</tagNode> +<!-- include end --> diff --git a/interface-definitions/load-balancing_reverse-proxy.xml.in b/interface-definitions/load-balancing_reverse-proxy.xml.in index 6a3b3cef1..011e1b53c 100644 --- a/interface-definitions/load-balancing_reverse-proxy.xml.in +++ b/interface-definitions/load-balancing_reverse-proxy.xml.in @@ -39,6 +39,7 @@ #include <include/port-number.xml.i> #include <include/haproxy/rule-frontend.xml.i> #include <include/haproxy/tcp-request.xml.i> + #include <include/haproxy/http-response-headers.xml.i> <leafNode name="redirect-http-to-https"> <properties> <help>Redirect HTTP to HTTPS</help> @@ -90,6 +91,7 @@ </leafNode> #include <include/generic-description.xml.i> #include <include/haproxy/mode.xml.i> + #include <include/haproxy/http-response-headers.xml.i> <node name="parameters"> <properties> <help>Backend parameters</help> diff --git a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py index c8b17316f..370a9276a 100755 --- a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py +++ b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py @@ -385,5 +385,26 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): self.assertIn(f'mode {mode}', config) self.assertIn(f'server {bk_name} {bk_server}:{bk_server_port}', config) + def test_07_lb_reverse_proxy_http_response_headers(self): + # Setup base + self.configure_pki() + self.base_config() + + # Set example headers in both frontend and backend + self.cli_set(base_path + ['service', 'https_front', 'http-response-headers', 'Cache-Control', 'value', 'max-age=604800']) + self.cli_set(base_path + ['backend', 'bk-01', 'http-response-headers', 'Proxy-Backend-ID', 'value', 'bk-01']) + self.cli_commit() + + # Test headers are present in generated configuration file + config = read_file(HAPROXY_CONF) + self.assertIn('http-response set-header Cache-Control \'max-age=604800\'', config) + self.assertIn('http-response set-header Proxy-Backend-ID \'bk-01\'', config) + + # Test setting alongside modes other than http is blocked by validation conditions + self.cli_set(base_path + ['service', 'https_front', 'mode', 'tcp']) + with self.assertRaises(ConfigSessionError) as e: + self.cli_commit() + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/load-balancing_reverse-proxy.py b/src/conf_mode/load-balancing_reverse-proxy.py index 1569d8d71..a4efb1cd8 100755 --- a/src/conf_mode/load-balancing_reverse-proxy.py +++ b/src/conf_mode/load-balancing_reverse-proxy.py @@ -88,6 +88,12 @@ def verify(lb): if {'send_proxy', 'send_proxy_v2'} <= set(bk_server_conf): raise ConfigError(f'Cannot use both "send-proxy" and "send-proxy-v2" for server "{bk_server}"') + # Check if http-response-headers are configured in any frontend/backend where mode != http + for group in ['service', 'backend']: + for config_name, config in lb[group].items(): + if 'http_response_headers' in config and ('mode' not in config or config['mode'] != 'http'): + raise ConfigError(f'{group} {config_name} must be set to http mode to use http_response_headers!') + if 'ssl' in back_config: if {'no_verify', 'ca_certificate'} <= set(back_config['ssl']): raise ConfigError(f'backend {back} cannot have both ssl options no-verify and ca-certificate set!') |