From fa8a4f73f8ec1514202e8a88319f77dc4705370d Mon Sep 17 00:00:00 2001
From: Lukasz Nowak <luke@nexedi.com>
Date: Fri, 23 Nov 2018 16:10:12 +0100
Subject: [PATCH] caddy-frontend: Implement non-zero knowledge backward
 compatible behaviour

---
 software/caddy-frontend/buildout.hash.cfg     | 18 +++---
 .../instance-apache-frontend.cfg.in           | 47 ++++++++++++++--
 .../instance-apache-replicate.cfg.in          | 42 ++++++++++++++
 software/caddy-frontend/instance.cfg.in       |  2 +
 .../caddy-frontend/templates/Caddyfile.in     | 14 ++++-
 .../templates/apache-custom-slave-list.cfg.in | 55 +++++++++++++++++++
 .../templates/default-virtualhost.conf.in     | 15 ++++-
 .../templates/nginx-notebook-slave.conf.in    | 15 ++++-
 .../caddy-frontend/templates/nginx.cfg.in     | 15 ++++-
 ...replicate-publish-slave-information.cfg.in |  7 +++
 10 files changed, 209 insertions(+), 21 deletions(-)

diff --git a/software/caddy-frontend/buildout.hash.cfg b/software/caddy-frontend/buildout.hash.cfg
index af61748f1..1dc3d427e 100644
--- a/software/caddy-frontend/buildout.hash.cfg
+++ b/software/caddy-frontend/buildout.hash.cfg
@@ -14,7 +14,7 @@
 # not need these here).
 [template]
 filename = instance.cfg.in
-md5sum = ffaf426c68b2f7a35558bf187b5981b7
+md5sum = 9906c7722c4fe7534cb5a397c9692553
 
 [template-common]
 filename = instance-common.cfg.in
@@ -22,15 +22,15 @@ md5sum = c801b7f9f11f0965677c22e6bbe9281b
 
 [template-apache-frontend]
 filename = instance-apache-frontend.cfg.in
-md5sum = b3275d8203b36506ea0f2f9c12f86399
+md5sum = 87558ff8adfebac0e53ebc797b5cdffa
 
 [template-apache-replicate]
 filename = instance-apache-replicate.cfg.in
-md5sum = ab77522560589fc315ddb6c8d28c4015
+md5sum = 3344628355c45a7c38bf6c74878f80a5
 
 [template-slave-list]
 filename = templates/apache-custom-slave-list.cfg.in
-md5sum = ed9743c1a5c1564c7083113ab54b78e3
+md5sum = 8bed2dcba7904a765c29cf8349b7d5cc
 
 [template-slave-configuration]
 filename = templates/custom-virtualhost.conf.in
@@ -38,11 +38,11 @@ md5sum = 54ae95597a126ae552c3a913ddf29e5e
 
 [template-replicate-publish-slave-information]
 filename = templates/replicate-publish-slave-information.cfg.in
-md5sum = 125181ce0065b2acddb0e3ee38f81864
+md5sum = 38e9994be01ea1b8a379f8ff7aa05438
 
 [template-caddy-frontend-configuration]
 filename = templates/Caddyfile.in
-md5sum = 1814950fe926b4a5f730d81d52cc827f
+md5sum = d1f22ffd1567f86091e857e53afc0959
 
 [caddy-backend-url-validator]
 filename = templates/caddy-backend-url-validator.in
@@ -58,7 +58,7 @@ md5sum = f20d6c3d2d94fb685f8d26dfca1e822b
 
 [template-default-slave-virtualhost]
 filename = templates/default-virtualhost.conf.in
-md5sum = ce86264b0c4cc1d447edf40db34e01c4
+md5sum = add17b5d1848bee6569c028bc1aea74c
 
 [template-cached-slave-virtualhost]
 filename = templates/cached-virtualhost.conf.in
@@ -86,7 +86,7 @@ md5sum = 117238225b3fc3c5b5be381815f44c67
 
 [template-nginx-configuration]
 filename = templates/nginx.cfg.in
-md5sum = e5b65b424d01fa539c92f4ba10e847eb
+md5sum = d3a5ffd1020f7c7747ba5d360ecf9e72
 
 [template-nginx-eventsource-slave-virtualhost]
 filename = templates/nginx-eventsource-slave.conf.in
@@ -94,7 +94,7 @@ md5sum = 217a6c801b8330b0b825f7b8b4c77184
 
 [template-nginx-notebook-slave-virtualhost]
 filename = templates/nginx-notebook-slave.conf.in
-md5sum = 3fd1fefaec2d630eee54f75e7a873c27
+md5sum = 82834235d2256bec4b4d62e5ba0d302e
 
 [template-apache-lazy-script-call]
 filename = templates/apache-lazy-script-call.sh.in
diff --git a/software/caddy-frontend/instance-apache-frontend.cfg.in b/software/caddy-frontend/instance-apache-frontend.cfg.in
index d440294e8..4f2fae7e6 100644
--- a/software/caddy-frontend/instance-apache-frontend.cfg.in
+++ b/software/caddy-frontend/instance-apache-frontend.cfg.in
@@ -83,6 +83,9 @@ cron-entries = ${:etc}/cron.d
 crontabs = ${:etc}/crontabs
 cronstamps = ${:etc}/cronstamps
 ca-dir = ${:srv}/ssl
+# BBB: SlapOS Master non-zero knowledge BEGIN
+bbb-ssl-dir = ${:srv}/bbb-ssl
+# BBB: SlapOS Master non-zero knowledge END
 
 varnginx = ${:var}/nginx
 
@@ -135,6 +138,7 @@ command =
 [jinja2-template-base]
 recipe = slapos.recipe.template:jinja2
 rendered = ${buildout:directory}/${:filename}
+extensions = jinja2.ext.do
 extra-context =
 slapparameter_dict = {{ dumps(instance_parameter['configuration']) }}
 slap_software_type = {{ dumps(instance_parameter['slap-software-type']) }}
@@ -202,7 +206,6 @@ stop-on-error = True
 < = jinja2-template-base
 template = {{ parameter_dict['template_slave_list'] }}
 filename = custom-personal-instance-slave-list.cfg
-extensions = jinja2.ext.do
 slave_instance_list = {{ dumps(instance_parameter['slave-instance-list']) }}
 extra_slave_instance_list = {{ dumps(instance_parameter.get('configuration.extra_slave_instance_list')) }}
 master_key_download_url = {{ dumps(slapparameter_dict['master-key-download-url']) }}
@@ -280,12 +283,16 @@ extra-context =
     key service_directory directory:service
     key run_directory directory:etc-run
     key not_found_file caddy-configuration:not-found-file
+# BBB: SlapOS Master non-zero knowledge BEGIN
+    key custom_ssl_directory caddy-directory:custom-ssl-directory
+    key apache_certificate apache-certificate:rendered
+    key apache_key apache-key:rendered
+# BBB: SlapOS Master non-zero knowledge END
 
 [dynamic-virtualhost-template-slave]
 <= jinja2-template-base
 template = {{ parameter_dict['template_slave_configuration'] }}
 rendered = ${directory:template}/slave-virtualhost.conf.in
-extensions = jinja2.ext.do
 # BBB: apache_custom_https and apache_custom_http
 extra-context =
     key https_port configuration:port
@@ -320,6 +327,10 @@ extra-context =
     key not_found_file caddy-configuration:not-found-file
     key username monitor-instance-parameter:username
     key password monitor-htpasswd:passwd
+# BBB: SlapOS Master non-zero knowledge BEGIN
+    key apache_certificate apache-certificate:rendered
+    key apache_key apache-key:rendered
+# BBB: SlapOS Master non-zero knowledge END
 
 [caddy-wrapper]
 recipe = slapos.cookbook:wrapper
@@ -364,6 +375,9 @@ slave-log = ${directory:log}/httpd
 nginx-slave-configuration = ${directory:etc}/nginx-slave-conf.d/
 autocert = ${directory:srv}/autocert
 master-autocert-dir = ${:autocert}/master-autocert
+# BBB: SlapOS Master non-zero knowledge BEGIN
+custom-ssl-directory = ${:slave-configuration}/ssl
+# BBB: SlapOS Master non-zero knowledge END
 
 [caddy-configuration]
 frontend-configuration = ${directory:etc}/Caddyfile
@@ -384,6 +398,24 @@ recipe = slapos.cookbook:wrapper
 command-line = ${frontend-caddy-validate:rendered}
 wrapper-path = ${directory:bin}/caddy-configtest
 
+# BBB: SlapOS Master non-zero knowledge BEGIN
+[apache-key]
+< = jinja2-template-base
+template = {{ parameter_dict['template_empty'] }}
+rendered = ${directory:bbb-ssl-dir}/frontend.key
+content = ${configuration:apache-key}
+extra-context =
+    key content :content
+
+[apache-certificate]
+< = jinja2-template-base
+template = {{ parameter_dict['template_empty'] }}
+rendered = ${directory:bbb-ssl-dir}/frontend.crt
+content = ${configuration:apache-certificate}
+extra-context =
+    key content :content
+# BBB: SlapOS Master non-zero knowledge END
+
 [cron]
 recipe = slapos.cookbook:cron
 dcrond-binary = {{ parameter_dict['dcron'] }}/sbin/crond
@@ -561,8 +593,8 @@ config-wrapper-path = ${trafficserver-line:wrapper-path}
 template = {{ parameter_dict['template_graceful_script'] }}
 rendered = ${directory:etc-run}/frontend-caddy-safe-graceful
 mode = 0700
-# XXX: Fix path_list for direct ssl ${caddy-directory:vh-ssl}/*.proxy_ca_crt
-path_list = ${caddy-configuration:frontend-configuration} ${frontend-configuration:log-access-configuration} ${caddy-directory:slave-configuration}/*.conf ${caddy-directory:slave-with-cache-configuration}/*.conf ${caddy-directory:master-autocert-dir}/*.key ${caddy-directory:master-autocert-dir}/*.crt ${caddy-directory:master-autocert-dir}/*.pem ${caddy-directory:autocert}/*/*.pem
+
+path_list = ${caddy-configuration:frontend-configuration} ${frontend-configuration:log-access-configuration} ${caddy-directory:slave-configuration}/*.conf ${caddy-directory:slave-with-cache-configuration}/*.conf ${caddy-directory:master-autocert-dir}/*.key ${caddy-directory:master-autocert-dir}/*.crt ${caddy-directory:master-autocert-dir}/*.pem ${caddy-directory:autocert}/*/*.pem ${caddy-directory:custom-ssl-directory}/*.key ${caddy-directory:custom-ssl-directory}/*.crt ${caddy-directory:custom-ssl-directory}/*.proxy_ca_crt ${directory:bbb-ssl-dir}/*.key ${directory:bbb-ssl-dir}/*.crt
 sha256sum = {{ parameter_dict['sha256sum'] }}
 signature_file = ${directory:run}/caddy_graceful_signature
 extra-context =
@@ -576,8 +608,7 @@ extra-context =
 template = {{ parameter_dict['template_graceful_script'] }}
 rendered = ${directory:etc-run}/frontend-nginx-safe-graceful
 mode = 0700
-# XXX: Fix path_list for direct ssl ${caddy-directory:vh-ssl}/*.proxy_ca_crt
-path_list = ${dynamic-nginx-frontend-template:rendered} ${caddy-directory:nginx-slave-configuration}/*.conf ${caddy-directory:master-autocert-dir}/*.key ${caddy-directory:master-autocert-dir}/*.crt ${caddy-directory:master-autocert-dir}/*.pem ${caddy-directory:autocert}/*/*.pem
+path_list = ${dynamic-nginx-frontend-template:rendered} ${caddy-directory:nginx-slave-configuration}/*.conf ${caddy-directory:master-autocert-dir}/*.key ${caddy-directory:master-autocert-dir}/*.crt ${caddy-directory:master-autocert-dir}/*.pem ${caddy-directory:autocert}/*/*.pem ${caddy-directory:custom-ssl-directory}/*.key ${caddy-directory:custom-ssl-directory}/*.crt ${caddy-directory:custom-ssl-directory}/*.proxy_ca_crt ${directory:bbb-ssl-dir}/*.key ${directory:bbb-ssl-dir}/*.crt
 sha256sum = {{ parameter_dict['sha256sum'] }}
 signature_file = ${directory:run}/nginx_graceful_signature
 extra-context =
@@ -778,6 +809,10 @@ extra-context =
   key access_log nginx-configuration:access_log
   key not_found_file caddy-configuration:not-found-file
   key master_certificate caddy-configuration:master-certificate
+# BBB: SlapOS Master non-zero knowledge BEGIN
+  key apache_certificate apache-certificate:rendered
+  key apache_key apache-key:rendered
+# BBB: SlapOS Master non-zero knowledge END
 
 [nginx-configuration]
 access_log = ${directory:log}/nginx-access.log
diff --git a/software/caddy-frontend/instance-apache-replicate.cfg.in b/software/caddy-frontend/instance-apache-replicate.cfg.in
index 470782a33..950bfa4e0 100644
--- a/software/caddy-frontend/instance-apache-replicate.cfg.in
+++ b/software/caddy-frontend/instance-apache-replicate.cfg.in
@@ -72,10 +72,12 @@ context =
 {% set authorized_slave_string_list = slapparameter_dict.pop('-frontend-authorized-slave-string', '').split() %}
 {% set authorized_slave_list = [] %}
 {% set rejected_slave_dict = {} %}
+{% set warning_slave_dict = {} %}
 {% set used_host_list = [] %}
 {% set unauthorized_message = 'slave not authorized' %}
 {% for slave in slave_instance_list %}
 {%   set slave_error_list = [] %}
+{%   set slave_warning_list = [] %}
 {%   set slave_server_alias_unclashed = [] %}
 {#   BBB: apache_custom_https AND apache_custom_http #}
 {%   set custom_domain = slave.get('custom_domain') %}
@@ -127,6 +129,25 @@ context =
 {%       do slave_error_list.append('slave https-url %r invalid' % (slave['https-url'],)) %}
 {%     endif %}
 {%   endif %}
+{# BBB: SlapOS Master non-zero knowledge BEGIN #}
+{%   for key in ['ssl_key', 'ssl_crt', 'ssl_ca_crt'] %}
+{%     if key in slave %}
+{%       do slave_warning_list.append('%s is obsolete, please use key-upload-url' % (key,)) %}
+{%     endif %}
+{%   endfor %}
+{%   if slave.get('ssl_ca_crt') and not (slave.get('ssl_crt') and slave.get('ssl_key')) %}
+{%     do slave_error_list.append('ssl_ca_crt is present, so ssl_crt and ssl_key are required')  %}
+{%   endif %}
+{%   if slave.get('ssl_key') and slave.get('ssl_crt') %}
+{%     set key_popen = popen([parameter_dict['openssl'], 'rsa', '-noout', '-modulus']) %}
+{%     set crt_popen = popen([parameter_dict['openssl'], 'x509', '-noout', '-modulus']) %}
+{%     set key_modulus = key_popen.communicate(slave['ssl_key'])[0] | trim %}
+{%     set crt_modulus = crt_popen.communicate(slave['ssl_crt'])[0] | trim %}
+{%     if not key_modulus or key_modulus != crt_modulus  %}
+{%       do slave_error_list.append('slave ssl_key and ssl_crt does not match')  %}
+{%     endif %}
+{%   endif %}
+{# BBB: SlapOS Master non-zero knowledge END #}
 {%   if slave.get('custom_domain') %}
 {%     set slave_custom_domain = '' ~ slave['custom_domain'] %}
 {%     if slave_custom_domain.startswith('*.') %}
@@ -143,6 +164,9 @@ context =
 {%   else %}
 {%     do rejected_slave_dict.__setitem__(slave.get('slave_reference'), slave_error_list) %}
 {%   endif %}
+{%   if len(slave_warning_list) > 0 %}
+{%     do warning_slave_dict.__setitem__(slave.get('slave_reference'), slave_warning_list) %}
+{%   endif %}
 {% endfor %}
 
 [monitor-instance-parameter]
@@ -189,6 +213,12 @@ sla-{{ parameter }} = {{ value }}
 {%   endif %}
 {% endfor %}
 
+{%  set warning_list = [] %}
+{%  for key in ['apache-certificate', 'apache-key'] %}
+{%    if key in slapparameter_dict %}
+{%      do warning_list.append('%s is obsolete, please use master-key-upload-url' % (key, )) %}
+{%    endif %}
+{%  endfor %}
 
 [publish-information]
 <= monitor-publish
@@ -201,6 +231,12 @@ rejected-slave-dict = {{ dumps(json_module.dumps(rejected_slave_dict)) }}
 master-key-upload-url = ${request-kedifa:connection-master-key-upload-url}
 master-key-generate-auth-url = ${request-kedifa:connection-master-key-generate-auth-url}
 kedifa-caucase-url = ${request-kedifa:connection-caucase-url}
+{% if len(warning_list) > 0 %}
+warning-list = {{ dumps(json_module.dumps(warning_list)) }}
+{% endif %}
+{% if len(warning_slave_dict) > 0 %}
+warning-slave-dict = {{ dumps(json_module.dumps(warning_slave_dict)) }}
+{% endif %}
 {% if not aikc_enabled %}
 kedifa-csr_id-url = ${request-kedifa:connection-csr_id-url}
 kedifa-csr_id-certificate = ${request-kedifa:connection-csr_id-certificate}
@@ -258,6 +294,11 @@ sla-{{ key[sla_kedifa_key_length:] }} = {{ slapparameter_dict.pop(key) }}
 {{ slave_id }} = {{ dumps(json_module.dumps(rejected_list)) }}
 {% endfor %}
 
+[warning-slave-information]
+{% for slave_id, warning_list in warning_slave_dict.iteritems() %}
+{{ slave_id }} = {{ dumps(json_module.dumps(warning_list)) }}
+{% endfor %}
+
 [slave-information]
 {% for frontend_section in frontend_section_list %}
 {{ frontend_section }} = {{ "${%s:connection-slave-instance-information-list}" % frontend_section }}
@@ -281,6 +322,7 @@ extra-context =
     section slave_information slave-information
     section rejected_slave_information rejected-slave-information
     section active_slave_instance_dict active-slave-instance
+    section warning_slave_information warning-slave-information
     key slave_kedifa_information request-kedifa:connection-slave-kedifa-information
 
 [monitor-conf-parameters]
diff --git a/software/caddy-frontend/instance.cfg.in b/software/caddy-frontend/instance.cfg.in
index 4784fafe1..e8995670d 100644
--- a/software/caddy-frontend/instance.cfg.in
+++ b/software/caddy-frontend/instance.cfg.in
@@ -106,6 +106,8 @@ configuration.apache_custom_https = ""
 configuration.apache_custom_http = ""
 configuration.caddy_custom_https = ""
 configuration.caddy_custom_http = ""
+configuration.apache-key =
+configuration.apache-certificate =
 configuration.open-port = 80 443
 configuration.disk-cache-size = 8G
 configuration.ram-cache-size = 1G
diff --git a/software/caddy-frontend/templates/Caddyfile.in b/software/caddy-frontend/templates/Caddyfile.in
index 5bd11e852..345acb442 100644
--- a/software/caddy-frontend/templates/Caddyfile.in
+++ b/software/caddy-frontend/templates/Caddyfile.in
@@ -4,10 +4,20 @@ import {{frontend_configuration.get('log-access-configuration')}}
 import {{ slave_configuration_directory }}/*.conf
 import {{ slave_with_cache_configuration_directory }}/*.conf
 
+{%- set ssl = {} -%}
+{%- if os_module.path.exists(master_certificate) -%}
+{%-   do ssl.__setitem__('certificate', master_certificate) -%}
+{%-   do ssl.__setitem__('key', master_certificate) -%}
+{#- BBB: SlapOS Master non-zero knowledge BEGIN -#}
+{%- elif os_module.path.getsize(apache_certificate) > 0 and os_module.path.getsize(apache_key) > 0 -%}
+{%-   do ssl.__setitem__('certificate', apache_certificate) -%}
+{%-   do ssl.__setitem__('key', apache_key) -%}
+{%- endif -%}
+{#- BBB: SlapOS Master non-zero knowledge END #}
 # Catch-all and 404 for not configured instances
-{% if os_module.path.exists(master_certificate) %}
+{% if 'key' in ssl %}
 :{{ https_port }} {
-  tls {{ master_certificate }} {{ master_certificate }}
+  tls {{ ssl['certificate'] }} {{ ssl['key'] }}
   bind {{ local_ipv4 }}
   # Compress the output
   gzip
diff --git a/software/caddy-frontend/templates/apache-custom-slave-list.cfg.in b/software/caddy-frontend/templates/apache-custom-slave-list.cfg.in
index 803c5ea97..c978fdffc 100644
--- a/software/caddy-frontend/templates/apache-custom-slave-list.cfg.in
+++ b/software/caddy-frontend/templates/apache-custom-slave-list.cfg.in
@@ -208,6 +208,61 @@ command =
   fi
 update-command = ${:command}
 
+# BBB: SlapOS Master non-zero knowledge BEGIN
+{# Set ssl certificates for each slave #}
+{%   for cert_name in ('ssl_csr', 'ssl_proxy_ca_crt')%}
+{%     if cert_name in slave_instance %}
+{%       set cert_title = '%s-%s' % (slave_reference, cert_name.replace('ssl_', '')) %}
+{%       set cert_file = '/'.join([custom_ssl_directory, cert_title.replace('-','.')]) %}
+{%       do part_list.append(cert_title) %}
+{%       do slave_parameter_dict.__setitem__(cert_name, cert_file) %}
+{%       do slave_instance.__setitem__('path_to_' + cert_name, cert_file) %}
+{# Store certificates on fs #}
+[{{ cert_title }}]
+< = jinja2-template-base
+template = {{ empty_template }}
+rendered = {{ cert_file }}
+extra-context =
+    key content {{ cert_title + '-config:value' }}
+# Store certificate in config
+[{{ cert_title + '-config' }}]
+value = {{ dumps(slave_instance.get(cert_name)) }}
+{%     endif %}
+{%   endfor %}
+
+{#-   Set Up Certs #}
+{%   do slave_instance.__setitem__('apache_certificate', apache_certificate) %}
+{%   do slave_instance.__setitem__('apache_key', apache_key) %}
+{%   if 'ssl_key' in slave_instance and 'ssl_crt' in slave_instance %}
+{%     set cert_title = '%s-crt' % (slave_reference) %}
+{%     set key_title = '%s-key' % (slave_reference) %}
+{%     set cert_file = '/'.join([custom_ssl_directory, cert_title.replace('-','.')]) %}
+{%     set key_file = '/'.join([custom_ssl_directory, key_title.replace('-','.')]) %}
+{%     do part_list.append(cert_title) %}
+{%     do part_list.append(key_title) %}
+{%     do slave_parameter_dict.__setitem__("ssl_crt", cert_file) %}
+{%     do slave_parameter_dict.__setitem__("ssl_key", key_file) %}
+{%     do slave_instance.__setitem__('path_to_ssl_crt', cert_file) %}
+{%     do slave_instance.__setitem__('path_to_ssl_key', key_file) %}
+
+[{{key_title}}]
+< = jinja2-template-base
+template = {{ empty_template }}
+rendered = {{ key_file }}
+key-content = {{ dumps(slave_instance.get('ssl_key')) }}
+extra-context =
+    key content :key-content
+
+[{{cert_title}}]
+< = jinja2-template-base
+template = {{ empty_template }}
+rendered = {{ cert_file }}
+cert-content = {{ dumps(slave_instance.get('ssl_crt') + '\n' + slave_instance.get('ssl_ca_crt', '')) }}
+extra-context =
+    key content :cert-content
+{%     endif %}
+# BBB: SlapOS Master non-zero knowledge END
+
 {# ########################################## #}
 {# Set Slave Configuration                    #}
 [{{ slave_configuration_section_name }}]
diff --git a/software/caddy-frontend/templates/default-virtualhost.conf.in b/software/caddy-frontend/templates/default-virtualhost.conf.in
index 14860a9b1..768149534 100644
--- a/software/caddy-frontend/templates/default-virtualhost.conf.in
+++ b/software/caddy-frontend/templates/default-virtualhost.conf.in
@@ -26,12 +26,25 @@
 {%- set default_path = slave_parameter.get('default-path', '').strip('/') | urlencode %}
 
 # SSL enabled hosts
+{% set ssl = {} %}
 {% if os_module.path.exists(slave_parameter['certificate']) %}
+{%   do ssl.__setitem__('certificate', slave_parameter['certificate']) %}
+{%   do ssl.__setitem__('key', slave_parameter['certificate']) %}
+{#- BBB: SlapOS Master non-zero knowledge BEGIN -#}
+{% elif 'path_to_ssl_crt' in slave_parameter and 'path_to_ssl_key' in slave_parameter %}
+{%   do ssl.__setitem__('certificate', slave_parameter['path_to_ssl_crt']) %}
+{%   do ssl.__setitem__('key', slave_parameter['path_to_ssl_key']) %}
+{% elif os_module.path.getsize(slave_parameter['apache_certificate']) > 0 and os_module.path.getsize(slave_parameter['apache_key']) > 0 %}
+{%   do ssl.__setitem__('certificate', slave_parameter['apache_certificate']) %}
+{%   do ssl.__setitem__('key', slave_parameter['apache_key']) %}
+{% endif %}
+{#- BBB: SlapOS Master non-zero knowledge END -#}
+{% if 'key' in ssl %}
 {{ https_host_list|join(', ') }} {
   bind {{ slave_parameter['local_ipv4'] }}
   # Compress the output
   gzip
-  tls {{ slave_parameter['certificate'] }} {{ slave_parameter['certificate'] }} {
+  tls {{ ssl['certificate'] }} {{ ssl['key'] }} {
 {%- if enable_h2 %}
     # Allow HTTP2
     alpn h2 http/1.1
diff --git a/software/caddy-frontend/templates/nginx-notebook-slave.conf.in b/software/caddy-frontend/templates/nginx-notebook-slave.conf.in
index ac16e6e78..d0a6f4fb9 100644
--- a/software/caddy-frontend/templates/nginx-notebook-slave.conf.in
+++ b/software/caddy-frontend/templates/nginx-notebook-slave.conf.in
@@ -5,7 +5,20 @@
 {%-   set https_upstream = https_url.split("/")[2] %}
 
 # SSL-enabled
+{% set ssl = {} %}
 {% if os_module.path.exists(slave_parameter['certificate']) %}
+{%   do ssl.__setitem__('certificate', slave_parameter['certificate']) %}
+{%   do ssl.__setitem__('key', slave_parameter['certificate']) %}
+{#- BBB: SlapOS Master non-zero knowledge BEGIN -#}
+{% elif 'path_to_ssl_crt' in slave_parameter and 'path_to_ssl_key' in slave_parameter %}
+{%   do ssl.__setitem__('certificate', slave_parameter['path_to_ssl_crt']) %}
+{%   do ssl.__setitem__('key', slave_parameter['path_to_ssl_key']) %}
+{% elif os_module.path.getsize(slave_parameter['apache_certificate']) > 0 and os_module.path.getsize(slave_parameter['apache_key']) > 0 %}
+{%   do ssl.__setitem__('certificate', slave_parameter['apache_certificate']) %}
+{%   do ssl.__setitem__('key', slave_parameter['apache_key']) %}
+{% endif %}
+{#- BBB: SlapOS Master non-zero knowledge END -#}
+{% if 'key' in ssl %}
 https://{{ slave_parameter.get('custom_domain') }}:{{ slave_parameter['nginx_https_port'] }} {
   bind {{ slave_parameter['local_ipv4'] }}
   # Compress the output
@@ -13,7 +26,7 @@ https://{{ slave_parameter.get('custom_domain') }}:{{ slave_parameter['nginx_htt
   log / {{ slave_parameter.get('access_log') }} "{remote} {>REMOTE_USER} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {latency_ms}"
   errors {{ slave_parameter.get('error_log') }}
 
-  tls {{ slave_parameter['certificate'] }} {{ slave_parameter['certificate'] }} {
+  tls {{ ssl['certificate'] }} {{ ssl['key'] }} {
     alpn http/1.1
   }
 
diff --git a/software/caddy-frontend/templates/nginx.cfg.in b/software/caddy-frontend/templates/nginx.cfg.in
index 15aa59965..ff0389946 100644
--- a/software/caddy-frontend/templates/nginx.cfg.in
+++ b/software/caddy-frontend/templates/nginx.cfg.in
@@ -58,9 +58,20 @@
 import {{ slave_configuration_directory }}/*.conf
 
 # Catch-all and 404 for not configured instances
-{% if os_module.path.exists(master_certificate) %}
+{%- set ssl = {} -%}
+{%- if os_module.path.exists(master_certificate) -%}
+{%-   do ssl.__setitem__('certificate', master_certificate) -%}
+{%-   do ssl.__setitem__('key', master_certificate) -%}
+{#- BBB: SlapOS Master non-zero knowledge BEGIN -#}
+{%- elif os_module.path.getsize(apache_certificate) > 0 and os_module.path.getsize(apache_key) > 0 -%}
+{%-   do ssl.__setitem__('certificate', apache_certificate) -%}
+{%-   do ssl.__setitem__('key', apache_key) -%}
+{%- endif -%}
+{#- BBB: SlapOS Master non-zero knowledge END -#}
+# Catch-all and 404 for not configured instances
+{% if 'key' in ssl %}
 :{{ port }} {
-  tls {{ master_certificate }} {{ master_certificate }}
+  tls {{ ssl['certificate'] }} {{ ssl['key'] }}
   bind {{ local_ip }}
   # Serve an error 204 (No Content) for favicon.ico
   status 204 /favicon.ico
diff --git a/software/caddy-frontend/templates/replicate-publish-slave-information.cfg.in b/software/caddy-frontend/templates/replicate-publish-slave-information.cfg.in
index bf99b37f7..7114a22c2 100644
--- a/software/caddy-frontend/templates/replicate-publish-slave-information.cfg.in
+++ b/software/caddy-frontend/templates/replicate-publish-slave-information.cfg.in
@@ -34,6 +34,13 @@
 {%   do slave_information_dict[slave_reference].__setitem__('request-error-list', rejected_info_list) %}
 {% endfor %}
 
+{% for slave_reference, warning_info_list in warning_slave_information.iteritems() %}
+{%   if slave_reference not in slave_information_dict %}
+{%     do slave_information_dict.__setitem__(slave_reference, {}) %}
+{%   endif %}
+{%   do slave_information_dict[slave_reference].__setitem__('warning-list', warning_info_list) %}
+{% endfor %}
+
 {% for slave_reference, kedifa_dict in json_module.loads(slave_kedifa_information).iteritems() %}
 {%   if slave_reference not in rejected_slave_information %}
 {%     if slave_reference not in slave_information_dict %}
-- 
2.30.9