diff options
author | Viacheslav Hletenko <v.gletenko@vyos.io> | 2023-05-19 09:57:11 +0000 |
---|---|---|
committer | Viacheslav Hletenko <v.gletenko@vyos.io> | 2023-05-19 09:57:11 +0000 |
commit | e201bd35511e1a000ffa21a4194d234634cfd76c (patch) | |
tree | dc5a8d347868a518c0bc35b0c3cee7e1d86c021b | |
parent | e164b6e4654eba24d7d4a6aadae69da67661858f (diff) | |
download | vyos-1x-e201bd35511e1a000ffa21a4194d234634cfd76c.tar.gz vyos-1x-e201bd35511e1a000ffa21a4194d234634cfd76c.zip |
T5222: Refactoring load-balancing reverse-proxy
Improve and refactoring "load-balancing reverse-proxy"
- replace 'reverse-proxy server <tag>'
=> 'reverse-proxy service <tag>'
- replace 'reverse-proxy global-parameters tls <xxx>'
=> 'reverse-proxy global-parameters tls-version-min xxx'
=> 'reverse-proxy global-parameters ssl-bind-ciphers xxx'
- replace 'reverse-proxy service https rule <tag> set server 'xxx'
=> 'reverse-proxy service https rule <tag> set backend 'xxx'
'service https rule <tag> domain-name xxx' set as multinode
-rw-r--r-- | data/templates/load-balancing/haproxy.cfg.j2 | 22 | ||||
-rw-r--r-- | interface-definitions/include/haproxy/rule-backend.xml.i (renamed from interface-definitions/include/haproxy/rule.xml.i) | 1 | ||||
-rw-r--r-- | interface-definitions/include/haproxy/rule-frontend.xml.i | 131 | ||||
-rw-r--r-- | interface-definitions/load-balancing-haproxy.xml.in | 141 | ||||
-rwxr-xr-x | src/conf_mode/load-balancing-haproxy.py | 13 |
5 files changed, 217 insertions, 91 deletions
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2 index 3d98d78b7..1a8ce13f8 100644 --- a/data/templates/load-balancing/haproxy.cfg.j2 +++ b/data/templates/load-balancing/haproxy.cfg.j2 @@ -19,12 +19,12 @@ global ca-base /etc/ssl/certs crt-base /etc/ssl/private -{% if global_parameters.tls.ssl_bind_ciphers is vyos_defined %} +{% if global_parameters.ssl_bind_ciphers is vyos_defined %} # https://ssl-config.mozilla.org/#server=haproxy&version=2.6.12-1&config=intermediate&openssl=3.0.8-1&guideline=5.6 - ssl-default-bind-ciphers {{ global_parameters.tls.ssl_bind_ciphers | join(':') | upper }} + ssl-default-bind-ciphers {{ global_parameters.ssl_bind_ciphers | join(':') | upper }} {% endif %} ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 -{% if global_parameters.tls.tls_version_min is vyos_defined('1.3') %} +{% if global_parameters.tls_version_min is vyos_defined('1.3') %} ssl-default-bind-options force-tlsv13 {% else %} ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets @@ -47,8 +47,8 @@ defaults errorfile 504 /etc/haproxy/errors/504.http # Frontend -{% if server is vyos_defined %} -{% for front, front_config in server.items() %} +{% if service is vyos_defined %} +{% for front, front_config in service.items() %} frontend {{ front }} {% set ssl_front = 'ssl crt /run/haproxy/' ~ front_config.ssl.certificate ~ '.pem' if front_config.ssl.certificate is vyos_defined else '' %} bind {{ front_config.listen_address if front_config.listen_address if vyos_defined else '*' }}:{{ front_config.port }} {{ ssl_front }} @@ -61,14 +61,16 @@ frontend {{ front }} {% if front_config.rule is vyos_defined %} {% for rule, rule_config in front_config.rule.items() %} # rule {{ rule }} -{% if rule_config.domain_name is vyos_defined and rule_config.set.server is vyos_defined %} +{% if rule_config.domain_name is vyos_defined and rule_config.set.backend is vyos_defined %} {% set rule_options = 'hdr(host)' %} {% if rule_config.ssl is vyos_defined %} {% set ssl_rule_translate = {'req-ssl-sni': 'req_ssl_sni', 'ssl-fc-sni': 'ssl_fc_sni', 'ssl-fc-sni-end': 'ssl_fc_sni_end'} %} {% set rule_options = ssl_rule_translate[rule_config.ssl] %} {% endif %} - acl {{ rule }} {{ rule_options }} -i {{ rule_config.domain_name }} - use_backend {{ rule_config.set.server }} if {{ rule }} +{% for domain in rule_config.domain_name %} + acl {{ rule }} {{ rule_options }} -i {{ domain }} +{% endfor %} + use_backend {{ rule_config.set.backend }} if {{ rule }} {% endif %} {# path url #} {% if rule_config.url_path is vyos_defined and rule_config.set.redirect_location is vyos_defined %} @@ -117,7 +119,9 @@ backend {{ back }} {% set ssl_rule_translate = {'req-ssl-sni': 'req_ssl_sni', 'ssl-fc-sni': 'ssl_fc_sni', 'ssl-fc-sni-end': 'ssl_fc_sni_end'} %} {% set rule_options = ssl_rule_translate[rule_config.ssl] %} {% endif %} - acl {{ rule }} {{ rule_options }} -i {{ rule_config.domain_name }} +{% for domain in rule_config.domain_name %} + acl {{ rule }} {{ rule_options }} -i {{ domain }} +{% endfor %} use-server {{ rule_config.set.server }} if {{ rule }} {% endif %} {# path url #} diff --git a/interface-definitions/include/haproxy/rule.xml.i b/interface-definitions/include/haproxy/rule-backend.xml.i index 9d9f63c9c..a6832d693 100644 --- a/interface-definitions/include/haproxy/rule.xml.i +++ b/interface-definitions/include/haproxy/rule-backend.xml.i @@ -22,6 +22,7 @@ <constraint> <validator name="fqdn"/> </constraint> + <multi/> </properties> </leafNode> <node name="set"> diff --git a/interface-definitions/include/haproxy/rule-frontend.xml.i b/interface-definitions/include/haproxy/rule-frontend.xml.i new file mode 100644 index 000000000..001ae2d80 --- /dev/null +++ b/interface-definitions/include/haproxy/rule-frontend.xml.i @@ -0,0 +1,131 @@ +<!-- include start from haproxy/rule.xml.i --> +<tagNode name="rule"> + <properties> + <help>Proxy rule number</help> + <valueHelp> + <format>u32:1-10000</format> + <description>Number for this proxy rule</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-10000"/> + </constraint> + <constraintErrorMessage>Proxy rule number must be between 1 and 10000</constraintErrorMessage> + </properties> + <children> + <leafNode name="domain-name"> + <properties> + <help>Domain name to match</help> + <valueHelp> + <format>txt</format> + <description>Domain address to match</description> + </valueHelp> + <constraint> + <validator name="fqdn"/> + </constraint> + <multi/> + </properties> + </leafNode> + <node name="set"> + <properties> + <help>Proxy modifications</help> + </properties> + <children> + <leafNode name="redirect-location"> + <properties> + <help>Set URL location</help> + <valueHelp> + <format>url</format> + <description>Set URL location</description> + </valueHelp> + <constraint> + <regex>^\/[\w\-.\/]+$</regex> + </constraint> + <constraintErrorMessage>Incorrect URL format</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="backend"> + <properties> + <help>Backend name</help> + <constraint> + <regex>[-_a-zA-Z0-9]+</regex> + </constraint> + <constraintErrorMessage>Server name must be alphanumeric and can contain hyphen and underscores</constraintErrorMessage> + </properties> + </leafNode> + </children> + </node> + <leafNode name="ssl"> + <properties> + <help>SSL match options</help> + <completionHelp> + <list>req-ssl-sni ssl-fc-sni</list> + </completionHelp> + <valueHelp> + <format>req-ssl-sni</format> + <description>SSL Server Name Indication (SNI) request match</description> + </valueHelp> + <valueHelp> + <format>ssl-fc-sni</format> + <description>SSL frontend connection Server Name Indication match</description> + </valueHelp> + <valueHelp> + <format>ssl-fc-sni-end</format> + <description>SSL frontend match end of connection Server Name Indication</description> + </valueHelp> + <constraint> + <regex>(req-ssl-sni|ssl-fc-sni|ssl-fc-sni-end)</regex> + </constraint> + </properties> + </leafNode> + <node name="url-path"> + <properties> + <help>URL path match</help> + </properties> + <children> + <leafNode name="begin"> + <properties> + <help>Begin URL match</help> + <valueHelp> + <format>url</format> + <description>Begin URL</description> + </valueHelp> + <constraint> + <regex>^\/[\w\-.\/]+$</regex> + </constraint> + <constraintErrorMessage>Incorrect URL format</constraintErrorMessage> + <multi/> + </properties> + </leafNode> + <leafNode name="end"> + <properties> + <help>End URL match</help> + <valueHelp> + <format>url</format> + <description>End URL</description> + </valueHelp> + <constraint> + <regex>^\/[\w\-.\/]+$</regex> + </constraint> + <constraintErrorMessage>Incorrect URL format</constraintErrorMessage> + <multi/> + </properties> + </leafNode> + <leafNode name="exact"> + <properties> + <help>Exactly URL match</help> + <valueHelp> + <format>url</format> + <description>Exactly URL</description> + </valueHelp> + <constraint> + <regex>^\/[\w\-.\/]+$</regex> + </constraint> + <constraintErrorMessage>Incorrect URL format</constraintErrorMessage> + <multi/> + </properties> + </leafNode> + </children> + </node> + </children> +</tagNode> +<!-- include end --> diff --git a/interface-definitions/load-balancing-haproxy.xml.in b/interface-definitions/load-balancing-haproxy.xml.in index f0c0ee8ce..e295dcb63 100644 --- a/interface-definitions/load-balancing-haproxy.xml.in +++ b/interface-definitions/load-balancing-haproxy.xml.in @@ -7,9 +7,9 @@ <help>Configure reverse-proxy</help> </properties> <children> - <tagNode name="server"> + <tagNode name="service"> <properties> - <help>Frontend server name</help> + <help>Frontend service name</help> <constraint> #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i> </constraint> @@ -37,7 +37,7 @@ #include <include/listen-address.xml.i> #include <include/haproxy/mode.xml.i> #include <include/port-number.xml.i> - #include <include/haproxy/rule.xml.i> + #include <include/haproxy/rule-frontend.xml.i> <leafNode name="redirect-http-to-https"> <properties> <help>Redirect HTTP to HTTPS</help> @@ -102,7 +102,7 @@ </leafNode> </children> </node> - #include <include/haproxy/rule.xml.i> + #include <include/haproxy/rule-backend.xml.i> <tagNode name="server"> <properties> <help>Backend server name</help> @@ -161,78 +161,71 @@ </constraint> </properties> </leafNode> - <node name="tls"> + <leafNode name="ssl-bind-ciphers"> <properties> - <help>Transport Layer Security (TLS) options</help> + <help>Cipher algorithms ("cipher suite") used during SSL/TLS handshake for all frontend servers</help> + <completionHelp> + <list>ecdhe-ecdsa-aes128-gcm-sha256 ecdhe-rsa-aes128-gcm-sha256 ecdhe-ecdsa-aes256-gcm-sha384 ecdhe-rsa-aes256-gcm-sha384 ecdhe-ecdsa-chacha20-poly1305 ecdhe-rsa-chacha20-poly1305 dhe-rsa-aes128-gcm-sha256 dhe-rsa-aes256-gcm-sha384</list> + </completionHelp> + <valueHelp> + <format>ecdhe-ecdsa-aes128-gcm-sha256</format> + <description>ecdhe-ecdsa-aes128-gcm-sha256</description> + </valueHelp> + <valueHelp> + <format>ecdhe-rsa-aes128-gcm-sha256</format> + <description>ecdhe-rsa-aes128-gcm-sha256</description> + </valueHelp> + <valueHelp> + <format>ecdhe-ecdsa-aes256-gcm-sha384</format> + <description>ecdhe-ecdsa-aes256-gcm-sha384</description> + </valueHelp> + <valueHelp> + <format>ecdhe-rsa-aes256-gcm-sha384</format> + <description>ecdhe-rsa-aes256-gcm-sha384</description> + </valueHelp> + <valueHelp> + <format>ecdhe-ecdsa-chacha20-poly1305</format> + <description>ecdhe-ecdsa-chacha20-poly1305</description> + </valueHelp> + <valueHelp> + <format>ecdhe-rsa-chacha20-poly1305</format> + <description>ecdhe-rsa-chacha20-poly1305</description> + </valueHelp> + <valueHelp> + <format>dhe-rsa-aes128-gcm-sha256</format> + <description>dhe-rsa-aes128-gcm-sha256</description> + </valueHelp> + <valueHelp> + <format>dhe-rsa-aes256-gcm-sha384</format> + <description>dhe-rsa-aes256-gcm-sha384</description> + </valueHelp> + <constraint> + <regex>(ecdhe-ecdsa-aes128-gcm-sha256|ecdhe-rsa-aes128-gcm-sha256|ecdhe-ecdsa-aes256-gcm-sha384|ecdhe-rsa-aes256-gcm-sha384|ecdhe-ecdsa-chacha20-poly1305|ecdhe-rsa-chacha20-poly1305|dhe-rsa-aes128-gcm-sha256|dhe-rsa-aes256-gcm-sha384)</regex> + </constraint> + <multi/> </properties> - <children> - <leafNode name="ssl-bind-ciphers"> - <properties> - <help>Cipher algorithms ("cipher suite") used during SSL/TLS handshake for all frontend servers</help> - <completionHelp> - <list>ecdhe-ecdsa-aes128-gcm-sha256 ecdhe-rsa-aes128-gcm-sha256 ecdhe-ecdsa-aes256-gcm-sha384 ecdhe-rsa-aes256-gcm-sha384 ecdhe-ecdsa-chacha20-poly1305 ecdhe-rsa-chacha20-poly1305 dhe-rsa-aes128-gcm-sha256 dhe-rsa-aes256-gcm-sha384</list> - </completionHelp> - <valueHelp> - <format>ecdhe-ecdsa-aes128-gcm-sha256</format> - <description>ecdhe-ecdsa-aes128-gcm-sha256</description> - </valueHelp> - <valueHelp> - <format>ecdhe-rsa-aes128-gcm-sha256</format> - <description>ecdhe-rsa-aes128-gcm-sha256</description> - </valueHelp> - <valueHelp> - <format>ecdhe-ecdsa-aes256-gcm-sha384</format> - <description>ecdhe-ecdsa-aes256-gcm-sha384</description> - </valueHelp> - <valueHelp> - <format>ecdhe-rsa-aes256-gcm-sha384</format> - <description>ecdhe-rsa-aes256-gcm-sha384</description> - </valueHelp> - <valueHelp> - <format>ecdhe-ecdsa-chacha20-poly1305</format> - <description>ecdhe-ecdsa-chacha20-poly1305</description> - </valueHelp> - <valueHelp> - <format>ecdhe-rsa-chacha20-poly1305</format> - <description>ecdhe-rsa-chacha20-poly1305</description> - </valueHelp> - <valueHelp> - <format>dhe-rsa-aes128-gcm-sha256</format> - <description>dhe-rsa-aes128-gcm-sha256</description> - </valueHelp> - <valueHelp> - <format>dhe-rsa-aes256-gcm-sha384</format> - <description>dhe-rsa-aes256-gcm-sha384</description> - </valueHelp> - <constraint> - <regex>(ecdhe-ecdsa-aes128-gcm-sha256|ecdhe-rsa-aes128-gcm-sha256|ecdhe-ecdsa-aes256-gcm-sha384|ecdhe-rsa-aes256-gcm-sha384|ecdhe-ecdsa-chacha20-poly1305|ecdhe-rsa-chacha20-poly1305|dhe-rsa-aes128-gcm-sha256|dhe-rsa-aes256-gcm-sha384)</regex> - </constraint> - <multi/> - </properties> - <defaultValue>ecdhe-ecdsa-aes128-gcm-sha256 ecdhe-rsa-aes128-gcm-sha256 ecdhe-ecdsa-aes256-gcm-sha384 ecdhe-rsa-aes256-gcm-sha384 ecdhe-ecdsa-chacha20-poly1305 ecdhe-rsa-chacha20-poly1305 dhe-rsa-aes128-gcm-sha256 dhe-rsa-aes256-gcm-sha384</defaultValue> - </leafNode> - <leafNode name="tls-version-min"> - <properties> - <help>Specify the minimum required TLS version</help> - <completionHelp> - <list>1.2 1.3</list> - </completionHelp> - <valueHelp> - <format>1.2</format> - <description>TLS v1.2</description> - </valueHelp> - <valueHelp> - <format>1.3</format> - <description>TLS v1.3</description> - </valueHelp> - <constraint> - <regex>(1.2|1.3)</regex> - </constraint> - </properties> - <defaultValue>1.3</defaultValue> - </leafNode> - </children> - </node> + <defaultValue>ecdhe-ecdsa-aes128-gcm-sha256 ecdhe-rsa-aes128-gcm-sha256 ecdhe-ecdsa-aes256-gcm-sha384 ecdhe-rsa-aes256-gcm-sha384 ecdhe-ecdsa-chacha20-poly1305 ecdhe-rsa-chacha20-poly1305 dhe-rsa-aes128-gcm-sha256 dhe-rsa-aes256-gcm-sha384</defaultValue> + </leafNode> + <leafNode name="tls-version-min"> + <properties> + <help>Specify the minimum required TLS version</help> + <completionHelp> + <list>1.2 1.3</list> + </completionHelp> + <valueHelp> + <format>1.2</format> + <description>TLS v1.2</description> + </valueHelp> + <valueHelp> + <format>1.3</format> + <description>TLS v1.3</description> + </valueHelp> + <constraint> + <regex>(1.2|1.3)</regex> + </constraint> + </properties> + <defaultValue>1.3</defaultValue> + </leafNode> </children> </node> #include <include/interface/vrf.xml.i> diff --git a/src/conf_mode/load-balancing-haproxy.py b/src/conf_mode/load-balancing-haproxy.py index d2b895fbe..938af6cda 100755 --- a/src/conf_mode/load-balancing-haproxy.py +++ b/src/conf_mode/load-balancing-haproxy.py @@ -74,15 +74,12 @@ def verify(lb): if not lb: return None - if 'backend' not in lb or 'server' not in lb: - raise ConfigError(f'"server" and "backend" must be configured!') + if 'backend' not in lb or 'service' not in lb: + raise ConfigError(f'"service" and "backend" must be configured!') - for front, front_config in lb['server'].items(): + for front, front_config in lb['service'].items(): if 'port' not in front_config: - raise ConfigError(f'"{front} server port" must be configured!') - # We can use redirect to HTTPS without backend section - if 'backend' not in front_config and 'redirect_http_to_https' not in front_config: - raise ConfigError(f'"{front} backend" must be configured!') + raise ConfigError(f'"{front} service port" must be configured!') # Check if bind address:port are used by another service tmp_address = front_config.get('address', '0.0.0.0') @@ -117,7 +114,7 @@ def generate(lb): os.mkdir(load_balancing_dir) # SSL Certificates for frontend - for front, front_config in lb['server'].items(): + for front, front_config in lb['service'].items(): if 'ssl' in front_config: cert_file_path = os.path.join(load_balancing_dir, 'cert.pem') cert_key_path = os.path.join(load_balancing_dir, 'cert.pem.key') |