diff options
| author | Christian Breunig <christian@breunig.cc> | 2023-05-19 12:21:29 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-19 12:21:29 +0200 | 
| commit | a66648596dc126b7bed37d8119ee8faa14909613 (patch) | |
| tree | 4ada4f89dcd395b809b17232846ddf4e557cb5dc | |
| parent | 881e7e5710d5011a837d943dc7ae40a3181a6482 (diff) | |
| parent | e201bd35511e1a000ffa21a4194d234634cfd76c (diff) | |
| download | vyos-1x-a66648596dc126b7bed37d8119ee8faa14909613.tar.gz vyos-1x-a66648596dc126b7bed37d8119ee8faa14909613.zip | |
Merge pull request #2012 from sever-sever/T5222-mod
T5222: Refactoring load-balancing reverse-proxy
| -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') | 
