diff options
Diffstat (limited to 'src/conf_mode/load-balancing_reverse-proxy.py')
-rwxr-xr-x | src/conf_mode/load-balancing_reverse-proxy.py | 86 |
1 files changed, 54 insertions, 32 deletions
diff --git a/src/conf_mode/load-balancing_reverse-proxy.py b/src/conf_mode/load-balancing_reverse-proxy.py index 1569d8d71..09c68dadd 100755 --- a/src/conf_mode/load-balancing_reverse-proxy.py +++ b/src/conf_mode/load-balancing_reverse-proxy.py @@ -26,9 +26,13 @@ from vyos.utils.dict import dict_search from vyos.utils.process import call from vyos.utils.network import check_port_availability from vyos.utils.network import is_listen_port_bind_service -from vyos.pki import wrap_certificate -from vyos.pki import wrap_private_key +from vyos.pki import find_chain +from vyos.pki import load_certificate +from vyos.pki import load_private_key +from vyos.pki import encode_certificate +from vyos.pki import encode_private_key from vyos.template import render +from vyos.utils.file import write_file from vyos import ConfigError from vyos import airbag airbag.enable() @@ -75,12 +79,21 @@ def verify(lb): raise ConfigError(f'"TCP" port "{tmp_port}" is used by another service') for back, back_config in lb['backend'].items(): - if 'http-check' in back_config: - http_check = back_config['http-check'] + if 'http_check' in back_config: + http_check = back_config['http_check'] if 'expect' in http_check and 'status' in http_check['expect'] and 'string' in http_check['expect']: raise ConfigError(f'"expect status" and "expect string" can not be configured together!') + + if 'health_check' in back_config: + if 'mode' not in back_config or back_config['mode'] != 'tcp': + raise ConfigError(f'backend "{back}" can only be configured with {back_config["health_check"]} ' + + f'health-check whilst in TCP mode!') + if 'http_check' in back_config: + raise ConfigError(f'backend "{back}" cannot be configured with both http-check and health-check!') + if 'server' not in back_config: raise ConfigError(f'"{back} server" must be configured!') + for bk_server, bk_server_conf in back_config['server'].items(): if 'address' not in bk_server_conf or 'port' not in bk_server_conf: raise ConfigError(f'"backend {back} server {bk_server} address and port" must be configured!') @@ -92,12 +105,18 @@ def verify(lb): 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!') + # 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!') + for front, front_config in lb['service'].items(): for cert in dict_search('ssl.certificate', front_config) or []: verify_pki_certificate(lb, cert) for back, back_config in lb['backend'].items(): - tmp = dict_search('ssl.ca_certificate', front_config) + tmp = dict_search('ssl.ca_certificate', back_config) if tmp: verify_pki_ca_certificate(lb, tmp) @@ -118,51 +137,54 @@ def generate(lb): if not os.path.isdir(load_balancing_dir): os.mkdir(load_balancing_dir) + loaded_ca_certs = {load_certificate(c['certificate']) + for c in lb['pki']['ca'].values()} if 'ca' in lb['pki'] else {} + # SSL Certificates for frontend for front, front_config in lb['service'].items(): - if 'ssl' in front_config: - - if 'certificate' in front_config['ssl']: - cert_names = front_config['ssl']['certificate'] + if 'ssl' not in front_config: + continue - for cert_name in cert_names: - pki_cert = lb['pki']['certificate'][cert_name] - cert_file_path = os.path.join(load_balancing_dir, f'{cert_name}.pem') - cert_key_path = os.path.join(load_balancing_dir, f'{cert_name}.pem.key') + if 'certificate' in front_config['ssl']: + cert_names = front_config['ssl']['certificate'] - with open(cert_file_path, 'w') as f: - f.write(wrap_certificate(pki_cert['certificate'])) + for cert_name in cert_names: + pki_cert = lb['pki']['certificate'][cert_name] + cert_file_path = os.path.join(load_balancing_dir, f'{cert_name}.pem') + cert_key_path = os.path.join(load_balancing_dir, f'{cert_name}.pem.key') - if 'private' in pki_cert and 'key' in pki_cert['private']: - with open(cert_key_path, 'w') as f: - f.write(wrap_private_key(pki_cert['private']['key'])) + loaded_pki_cert = load_certificate(pki_cert['certificate']) + cert_full_chain = find_chain(loaded_pki_cert, loaded_ca_certs) - if 'ca_certificate' in front_config['ssl']: - ca_name = front_config['ssl']['ca_certificate'] - pki_ca_cert = lb['pki']['ca'][ca_name] - ca_cert_file_path = os.path.join(load_balancing_dir, f'{ca_name}.pem') + write_file(cert_file_path, + '\n'.join(encode_certificate(c) for c in cert_full_chain)) - with open(ca_cert_file_path, 'w') as f: - f.write(wrap_certificate(pki_ca_cert['certificate'])) + if 'private' in pki_cert and 'key' in pki_cert['private']: + loaded_key = load_private_key(pki_cert['private']['key'], passphrase=None, wrap_tags=True) + key_pem = encode_private_key(loaded_key, passphrase=None) + write_file(cert_key_path, key_pem) # SSL Certificates for backend for back, back_config in lb['backend'].items(): - if 'ssl' in back_config: + if 'ssl' not in back_config: + continue - if 'ca_certificate' in back_config['ssl']: - ca_name = back_config['ssl']['ca_certificate'] - pki_ca_cert = lb['pki']['ca'][ca_name] - ca_cert_file_path = os.path.join(load_balancing_dir, f'{ca_name}.pem') + if 'ca_certificate' in back_config['ssl']: + ca_name = back_config['ssl']['ca_certificate'] + ca_cert_file_path = os.path.join(load_balancing_dir, f'{ca_name}.pem') + ca_chains = [] - with open(ca_cert_file_path, 'w') as f: - f.write(wrap_certificate(pki_ca_cert['certificate'])) + pki_ca_cert = lb['pki']['ca'][ca_name] + loaded_ca_cert = load_certificate(pki_ca_cert['certificate']) + ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs) + ca_chains.append('\n'.join(encode_certificate(c) for c in ca_full_chain)) + write_file(ca_cert_file_path, '\n'.join(ca_chains)) render(load_balancing_conf_file, 'load-balancing/haproxy.cfg.j2', lb) render(systemd_override, 'load-balancing/override_haproxy.conf.j2', lb) return None - def apply(lb): call('systemctl daemon-reload') if not lb: |