summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViacheslav Hletenko <v.gletenko@vyos.io>2023-05-19 09:57:11 +0000
committerViacheslav Hletenko <v.gletenko@vyos.io>2023-05-19 09:57:11 +0000
commite201bd35511e1a000ffa21a4194d234634cfd76c (patch)
treedc5a8d347868a518c0bc35b0c3cee7e1d86c021b
parente164b6e4654eba24d7d4a6aadae69da67661858f (diff)
downloadvyos-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.j222
-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.i131
-rw-r--r--interface-definitions/load-balancing-haproxy.xml.in141
-rwxr-xr-xsrc/conf_mode/load-balancing-haproxy.py13
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')