{#- SlapOS Master (but not slapproxy!) merges slave's instance and connection parameters, so the slave information passed to nodes have to be limited only to instance related keys #}
{#- SlapOS Master (but not slapproxy!) merges slave's instance and connection parameters, so the slave information passed to nodes have to be limited only to instance related keys #}
{#- Note: As a result, this feature is very hard to be tested with slapproxy, as it does not pollute the slave information, this kind of whitelist is implemented #}
{#- Note: As a result, this feature is very hard to be tested with slapproxy, as it does not pollute the slave information, this kind of whitelist is implemented #}
{%- set FRONTEND_NODE_SLAVE_PASSED_KEY_LIST_SCHEMA = [
{%- set FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST_SCHEMA = [
'authenticate-to-backend',
'authenticate-to-backend',
'backend-connect-retries',
'backend-connect-retries',
'backend-connect-timeout',
'backend-connect-timeout',
...
@@ -94,11 +94,11 @@
...
@@ -94,11 +94,11 @@
'websocket-transparent',
'websocket-transparent',
]
]
%}
%}
{%- set FRONTEND_NODE_SLAVE_PASSED_KEY_LIST_INTERNAL = [
{%- set FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST_INTERNAL = [
'slave_reference',
'slave_reference',
]
]
%}
%}
{%- set FRONTEND_NODE_SLAVE_PASSED_KEY_LIST = FRONTEND_NODE_SLAVE_PASSED_KEY_LIST_SCHEMA + FRONTEND_NODE_SLAVE_PASSED_KEY_LIST_INTERNAL %}
{%- set FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST = FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST_SCHEMA + FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST_INTERNAL %}
{% set aikc_enabled = instance_parameter_dict['configuration'].get('automatic-internal-kedifa-caucase-csr', 'true').lower() in TRUE_VALUES %}
{% set aikc_enabled = instance_parameter_dict['configuration'].get('automatic-internal-kedifa-caucase-csr', 'true').lower() in TRUE_VALUES %}
{% set aibcc_enabled = instance_parameter_dict['configuration'].get('automatic-internal-backend-client-caucase-csr', 'true').lower() in TRUE_VALUES %}
{% set aibcc_enabled = instance_parameter_dict['configuration'].get('automatic-internal-backend-client-caucase-csr', 'true').lower() in TRUE_VALUES %}
{# Ports 8401, 8402 and 8410+1..N are reserved for monitor ports on various partitions #}
{# Ports 8401, 8402 and 8410+1..N are reserved for monitor ports on various partitions #}
...
@@ -148,7 +148,7 @@ context =
...
@@ -148,7 +148,7 @@ context =
'port': '4443',
'port': '4443',
'ram-cache-size': '1G',
'ram-cache-size': '1G',
'request-timeout': '600',
'request-timeout': '600',
'slave-introspection-https-port': '22443',
'frontend-introspection-https-port': '22443',
} %}
} %}
{% for i in range(1, frontend_quantity + 1) %}
{% for i in range(1, frontend_quantity + 1) %}
{% set frontend_name = "%s-%s" % (NAME_BASE, i) %}
{% set frontend_name = "%s-%s" % (NAME_BASE, i) %}
...
@@ -198,188 +198,187 @@ context =
...
@@ -198,188 +198,187 @@ context =
{% do request_dict.__setitem__(request_section_title, request_content_dict) %}
{% do request_dict.__setitem__(request_section_title, request_content_dict) %}
{% endfor %}
{% endfor %}
{% set authorized_slave_string_list = [] %}
{% set authorized_frontend_list = [] %}
{% set authorized_slave_list = [] %}
{% set rejected_frontend_dict = {} %}
{% set rejected_slave_dict = {} %}
{% set critical_rejected_frontend_dict = {} %}
{% set critical_rejected_slave_dict = {} %}
{% set warning_frontend_dict = {} %}
{% set warning_slave_dict = {} %}
{% set used_host_list = [] %}
{% set used_host_list = [] %}
{% for slave in sorted(instance_parameter_dict['slave-instance-list'], key=operator_module.itemgetter('slave_reference')) %}
{% for frontend in sorted(instance_parameter_dict['slave-instance-list'], key=operator_module.itemgetter('slave_reference')) %}
{% set slave_error_list = [] %}
{% set frontend_error_list = [] %}
{% set slave_critical_error_list = [] %}
{% set frontend_critical_error_list = [] %}
{% set slave_warning_list = [] %}
{% set frontend_warning_list = [] %}
{% set slave_server_alias_unclashed = [] %}
{% set frontend_server_alias_unclashed = [] %}
{% set slave_type = slave.get('type') %}
{% set frontend_type = frontend.get('type') %}
{% if slave_type not in [None, '', 'default', 'zope', 'redirect', 'notebook', 'websocket'] %}
{% if frontend_type not in [None, '', 'default', 'zope', 'redirect', 'notebook', 'websocket'] %}
{% do slave_error_list.append('type:%s is not supported' % (slave_type,)) %}
{% do frontend_error_list.append('type:%s is not supported' % (frontend_type,)) %}
{% endif %}
{% endif %}
{# Check health-check-* #}
{# Check health-check-* #}
{% set health_check = (str(slave.get('health-check', False)) or 'false').lower() %}
{% set health_check = (str(frontend.get('health-check', False)) or 'false').lower() %}
{% if health_check in TRUE_VALUES %}
{% if health_check in TRUE_VALUES %}
{% set health_check_http_method = slave.get('health-check-http-method') or 'GET' %}
{% set health_check_http_method = frontend.get('health-check-http-method') or 'GET' %}
{% if health_check_http_method not in ['GET', 'OPTIONS', 'CONNECT', 'POST'] %}
{% if health_check_http_method not in ['GET', 'OPTIONS', 'CONNECT', 'POST'] %}
{% do slave_error_list.append('Wrong health-check-http-method %s' % (health_check_http_method,)) %}
{% do frontend_error_list.append('Wrong health-check-http-method %s' % (health_check_http_method,)) %}
{% endif %}
{% endif %}
{% set health_check_http_path = slave.get('health-check-http-path') or '/' %}
{% set health_check_http_path = frontend.get('health-check-http-path') or '/' %}
{% set health_check_http_version = slave.get('health-check-http-version') or 'HTTP/1.1' %}
{% set health_check_http_version = frontend.get('health-check-http-version') or 'HTTP/1.1' %}
{% if health_check_http_version not in ['HTTP/1.1', 'HTTP/1.0'] %}
{% if health_check_http_version not in ['HTTP/1.1', 'HTTP/1.0'] %}
{% do slave_error_list.append('Wrong health-check-http-version %s' % (health_check_http_version,)) %}
{% do frontend_error_list.append('Wrong health-check-http-version %s' % (health_check_http_version,)) %}
{% endif %}
{% endif %}
{% set health_check_timeout = (slave.get('health-check-timeout') or '2') | int(false) %}
{% set health_check_timeout = (frontend.get('health-check-timeout') or '2') | int(false) %}
{% if health_check_timeout is false or health_check_timeout <= 0 %}
{% if health_check_timeout is false or health_check_timeout <= 0 %}
{% do slave_error_list.append('Wrong health-check-timeout %s' % (slave.get('health-check-timeout'),)) %}
{% do frontend_error_list.append('Wrong health-check-timeout %s' % (frontend.get('health-check-timeout'),)) %}
{% endif %}
{% endif %}
{% set health_check_interval = (slave.get('health-check-interval') or '5') | int(false) %}
{% set health_check_interval = (frontend.get('health-check-interval') or '5') | int(false) %}
{% if health_check_interval is false or health_check_interval <= 0 %}
{% if health_check_interval is false or health_check_interval <= 0 %}
{% do slave_error_list.append('Wrong health-check-interval %s' % (slave.get('health-check-interval'),)) %}
{% do frontend_error_list.append('Wrong health-check-interval %s' % (frontend.get('health-check-interval'),)) %}
{% endif %}
{% endif %}
{% set health_check_rise = (slave.get('health-check-rise') or '1') | int(false) %}
{% set health_check_rise = (frontend.get('health-check-rise') or '1') | int(false) %}
{% if health_check_rise is false or health_check_rise <= 0 %}
{% if health_check_rise is false or health_check_rise <= 0 %}
{% do slave_error_list.append('Wrong health-check-rise %s' % (slave.get('health-check-rise'),)) %}
{% do frontend_error_list.append('Wrong health-check-rise %s' % (frontend.get('health-check-rise'),)) %}
{% endif %}
{% endif %}
{% set health_check_fall = (slave.get('health-check-fall') or '1') | int(false) %}
{% set health_check_fall = (frontend.get('health-check-fall') or '1') | int(false) %}
{% if health_check_fall is false or health_check_fall <= 0 %}
{% if health_check_fall is false or health_check_fall <= 0 %}
{% do slave_error_list.append('Wrong health-check-fall %s' % (slave.get('health-check-fall'),)) %}
{% do frontend_error_list.append('Wrong health-check-fall %s' % (frontend.get('health-check-fall'),)) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{# Check virtualhostroot-http-port and virtualhostroot-https-port #}
{# Check virtualhostroot-http-port and virtualhostroot-https-port #}
{% for key in ['virtualhostroot-http-port', 'virtualhostroot-https-port'] %}
{% for key in ['virtualhostroot-http-port', 'virtualhostroot-https-port'] %}
{% set value = (slave.get(key) or '1') | int(false) %}
{% set value = (frontend.get(key) or '1') | int(false) %}
{% if value is false or value < 0 %}
{% if value is false or value < 0 %}
{% do slave_error_list.append('Wrong %s %r' % (key, slave.get(key))) %}
{% do frontend_error_list.append('Wrong %s %r' % (key, frontend.get(key))) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{# Check ciphers #}
{# Check ciphers #}
{% set slave_cipher_list = slave.get('ciphers', '').strip().split() %}
{% set frontend_cipher_list = frontend.get('ciphers', '').strip().split() %}
{% if slave_cipher_list %}
{% if frontend_cipher_list %}
{% for cipher in slave_cipher_list %}
{% for cipher in frontend_cipher_list %}
{% if cipher not in GOOD_CIPHER_LIST %}
{% if cipher not in GOOD_CIPHER_LIST %}
{% if cipher in CIPHER_TRANSLATION_DICT %}
{% if cipher in CIPHER_TRANSLATION_DICT %}
{# Real translation happens in instance-slave-list.cfg.in #}
{# Real translation happens in instance-frontend-list.cfg.in #}
{% do slave_warning_list.append('Cipher %r translated to %r' % (cipher, CIPHER_TRANSLATION_DICT[cipher])) %}
{% do frontend_warning_list.append('Cipher %r translated to %r' % (cipher, CIPHER_TRANSLATION_DICT[cipher])) %}
{% else %}
{% else %}
{% do slave_error_list.append('Cipher %r is not supported.' % (cipher,)) %}
{% do frontend_error_list.append('Cipher %r is not supported.' % (cipher,)) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{# Check strict-transport-security #}
{# Check strict-transport-security #}
{% set strict_transport_security = (slave.get('strict-transport-security') or '0') | int(false) %}
{% set strict_transport_security = (frontend.get('strict-transport-security') or '0') | int(false) %}
{% if strict_transport_security is false or strict_transport_security < 0 %}
{% if strict_transport_security is false or strict_transport_security < 0 %}
{% do slave_error_list.append('Wrong strict-transport-security %s' % (slave.get('strict-transport-security'),)) %}
{% do frontend_error_list.append('Wrong strict-transport-security %s' % (frontend.get('strict-transport-security'),)) %}
{% endif %}
{% endif %}
{% set custom_domain = slave.get('custom_domain') %}
{% set custom_domain = frontend.get('custom_domain') %}
{% if custom_domain and custom_domain in used_host_list %}
{% if custom_domain and custom_domain in used_host_list %}
{% set message = 'custom_domain %r clashes' % (custom_domain,) %}
{% set message = 'custom_domain %r clashes' % (custom_domain,) %}
{% do slave_error_list.append(message) %}
{% do frontend_error_list.append(message) %}
{% do slave_critical_error_list.append(message) %}
{% do frontend_critical_error_list.append(message) %}
{% else %}
{% else %}
{% do used_host_list.append(custom_domain) %}
{% do used_host_list.append(custom_domain) %}
{% endif %}
{% endif %}
{% if slave.get('server-alias') %}
{% if frontend.get('server-alias') %}
{% for slave_alias in ('' ~ slave['server-alias']).split() %}
{% for frontend_alias in ('' ~ frontend['server-alias']).split() %}
{% if slave_alias.startswith('*.') %}
{% if frontend_alias.startswith('*.') %}
{% set clean_slave_alias = slave_alias[2:] %}
{% set clean_frontend_alias = frontend_alias[2:] %}
{% else %}
{% else %}
{% set clean_slave_alias = slave_alias %}
{% set clean_frontend_alias = frontend_alias %}
{% endif %}
{% endif %}
{% if not validators.domain(clean_slave_alias) %}
{% if not validators.domain(clean_frontend_alias) %}
{% do slave_error_list.append('server-alias \'%s\' not valid' % (slave_alias,)) %}
{% do frontend_error_list.append('server-alias \'%s\' not valid' % (frontend_alias,)) %}
{% else %}
{% else %}
{% if slave_alias in slave_server_alias_unclashed or slave_alias == custom_domain %}
{% if frontend_alias in frontend_server_alias_unclashed or frontend_alias == custom_domain %}
{# optionally do something about reporting back that server-alias has been unclashed #}
{# optionally do something about reporting back that server-alias has been unclashed #}
{% elif slave_alias in used_host_list %}
{% elif frontend_alias in used_host_list %}
{% set message = 'server-alias \'%s\' clashes' % (slave_alias,) %}
{% set message = 'server-alias \'%s\' clashes' % (frontend_alias,) %}
{% do slave_error_list.append(message) %}
{% do frontend_error_list.append(message) %}
{% do slave_critical_error_list.append(message) %}
{% do frontend_critical_error_list.append(message) %}
{% else %}
{% else %}
{% do slave_server_alias_unclashed.append(slave_alias) %}
{% do frontend_server_alias_unclashed.append(frontend_alias) %}
{% do used_host_list.append(slave_alias) %}
{% do used_host_list.append(frontend_alias) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% do slave.__setitem__('server-alias', ' '.join(slave_server_alias_unclashed)) %}
{% do frontend.__setitem__('server-alias', ' '.join(frontend_server_alias_unclashed)) %}
{% endif %}
{% endif %}
{% for url_key in ['url', 'https-url', 'health-check-failover-url', 'health-check-failover-https-url'] %}
{% for url_key in ['url', 'https-url', 'health-check-failover-url', 'health-check-failover-https-url'] %}
{% if url_key in slave %}
{% if url_key in frontend %}
{% set url = (slave[url_key] or '').strip() %}
{% set url = (frontend[url_key] or '').strip() %}
{% if not validators.url(url) %}
{% if not validators.url(url) %}
{% do slave_error_list.append('slave %s %r invalid' % (url_key, url)) %}
{% do frontend_error_list.append('frontend %s %r invalid' % (url_key, url)) %}
{% elif url != slave[url_key] %}
{% elif url != frontend[url_key] %}
{% do slave_warning_list.append('slave %s %r has been converted to %r' % (url_key, slave[url_key], url)) %}
{% do frontend_warning_list.append('frontend %s %r has been converted to %r' % (url_key, frontend[url_key], url)) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% for url_key in ['url-netloc-list', 'https-url-netloc-list', 'health-check-failover-url-netloc-list'] %}
{% for url_key in ['url-netloc-list', 'https-url-netloc-list', 'health-check-failover-url-netloc-list'] %}
{% if url_key in slave %}
{% if url_key in frontend %}
{% for netloc in slave[url_key].split() %}
{% for netloc in frontend[url_key].split() %}
{% if not software.validate_netloc(netloc) %}
{% if not software.validate_netloc(netloc) %}
{% do slave_error_list.append('slave %s %r invalid' % (url_key, netloc)) %}
{% do frontend_error_list.append('frontend %s %r invalid' % (url_key, netloc)) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% for k in ['ssl_proxy_ca_crt', 'health-check-failover-ssl-proxy-ca-crt'] %}
{% for k in ['ssl_proxy_ca_crt', 'health-check-failover-ssl-proxy-ca-crt'] %}
{% if k in slave %}
{% if k in frontend %}
{% set crt = slave.get(k, '') %}
{% set crt = frontend.get(k, '') %}
{% set check_popen = popen([software_parameter_dict['openssl'], 'x509', '-noout']) %}
{% set check_popen = popen([software_parameter_dict['openssl'], 'x509', '-noout']) %}
{% do check_popen.communicate(crt.encode()) %}
{% do check_popen.communicate(crt.encode()) %}
{% if check_popen.returncode != 0 %}
{% if check_popen.returncode != 0 %}
{% do slave_error_list.append('%s is invalid' % (k,)) %}
{% do frontend_error_list.append('%s is invalid' % (k,)) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{# BBB: SlapOS Master non-zero knowledge BEGIN #}
{# BBB: SlapOS Master non-zero knowledge BEGIN #}
{% for key in ['ssl_key', 'ssl_crt', 'ssl_ca_crt'] %}
{% for key in ['ssl_key', 'ssl_crt', 'ssl_ca_crt'] %}
{% if key in slave %}
{% if key in frontend %}
{% do slave_warning_list.append('%s is obsolete, please use key-upload-url' % (key,)) %}
{% do frontend_warning_list.append('%s is obsolete, please use key-upload-url' % (key,)) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% if slave.get('ssl_ca_crt') and not (slave.get('ssl_crt') and slave.get('ssl_key')) %}
{% if frontend.get('ssl_ca_crt') and not (frontend.get('ssl_crt') and frontend.get('ssl_key')) %}
{% do slave_error_list.append('ssl_ca_crt is present, so ssl_crt and ssl_key are required') %}
{% do frontend_error_list.append('ssl_ca_crt is present, so ssl_crt and ssl_key are required') %}
{% endif %}
{% endif %}
{% if slave.get('ssl_key') and slave.get('ssl_crt') %}
{% if frontend.get('ssl_key') and frontend.get('ssl_crt') %}
{% set key_popen = popen([software_parameter_dict['openssl'], 'rsa', '-noout', '-modulus']) %}
{% set key_popen = popen([software_parameter_dict['openssl'], 'rsa', '-noout', '-modulus']) %}
{% set crt_popen = popen([software_parameter_dict['openssl'], 'x509', '-noout', '-modulus']) %}
{% set crt_popen = popen([software_parameter_dict['openssl'], 'x509', '-noout', '-modulus']) %}
{% set key_modulus = key_popen.communicate(slave['ssl_key'].encode())[0] | trim %}
{% set key_modulus = key_popen.communicate(frontend['ssl_key'].encode())[0] | trim %}
{% set crt_modulus = crt_popen.communicate(slave['ssl_crt'].encode())[0] | trim %}
{% set crt_modulus = crt_popen.communicate(frontend['ssl_crt'].encode())[0] | trim %}
{% if not key_modulus or key_modulus != crt_modulus %}
{% if not key_modulus or key_modulus != crt_modulus %}
{% do slave_error_list.append('slave ssl_key and ssl_crt does not match') %}
{% do frontend_error_list.append('frontend ssl_key and ssl_crt does not match') %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{# BBB: SlapOS Master non-zero knowledge END #}
{# BBB: SlapOS Master non-zero knowledge END #}
{% if slave.get('custom_domain') %}
{% if frontend.get('custom_domain') %}
{% set slave_custom_domain = '' ~ slave['custom_domain'] %}
{% set frontend_custom_domain = '' ~ frontend['custom_domain'] %}
{% if slave_custom_domain.startswith('*.') %}
{% if frontend_custom_domain.startswith('*.') %}
{% set clean_custom_domain = slave_custom_domain[2:] %}
{% set clean_custom_domain = frontend_custom_domain[2:] %}
{% else %}
{% else %}
{% set clean_custom_domain = slave_custom_domain %}
{% set clean_custom_domain = frontend_custom_domain %}
{% endif %}
{% endif %}
{% if not validators.domain(clean_custom_domain) %}
{% if not validators.domain(clean_custom_domain) %}
{% do slave_error_list.append('custom_domain %r invalid' % (slave['custom_domain'],)) %}
{% do frontend_error_list.append('custom_domain %r invalid' % (frontend['custom_domain'],)) %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% if len(slave_error_list) == 0 %}
{% if len(frontend_error_list) == 0 %}
{# Cleanup slave from not needed keys which come from implementation of SlapOS Master #}
{# Cleanup frontend from not needed keys which come from implementation of SlapOS Master #}
{# Send only controlled information about the slave to node #}
{# Send only controlled information about the frontend to node #}
{% set authorized_slave = {} %}
{% set authorized_frontend = {} %}
{% for key in FRONTEND_NODE_SLAVE_PASSED_KEY_LIST %}
{% for key in FRONTEND_NODE_FRONTEND_PASSED_KEY_LIST %}
{% if key in slave %}
{% if key in frontend %}
{% do authorized_slave.__setitem__(key, slave[key]) %}
{% do authorized_frontend.__setitem__(key, frontend[key]) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% do authorized_slave_list.append(authorized_slave) %}
{% do authorized_frontend_list.append(authorized_frontend) %}
{% else %}
{% else %}
{% do rejected_slave_dict.__setitem__(slave.get('slave_reference'), sorted(slave_error_list)) %}
{% do rejected_frontend_dict.__setitem__(frontend.get('slave_reference'), sorted(frontend_error_list)) %}
{% endif %}
{% endif %}
{% if len(slave_critical_error_list) > 0 %}
{% if len(frontend_critical_error_list) > 0 %}
{% do critical_rejected_slave_dict.__setitem__(slave.get('slave_reference'), sorted(slave_critical_error_list)) %}
{% do critical_rejected_frontend_dict.__setitem__(frontend.get('slave_reference'), sorted(frontend_critical_error_list)) %}
{% endif %}
{% endif %}
{% if len(slave_warning_list) > 0 %}
{% if len(frontend_warning_list) > 0 %}
{% do warning_slave_dict.__setitem__(slave.get('slave_reference'), sorted(slave_warning_list)) %}
{% do warning_frontend_dict.__setitem__(frontend.get('slave_reference'), sorted(frontend_warning_list)) %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% do authorized_slave_list.sort(key=operator_module.itemgetter('slave_reference')) %}
{% do authorized_frontend_list.sort(key=operator_module.itemgetter('slave_reference')) %}