diff --git a/bench/commands/config.py b/bench/commands/config.py index 056b60cd..eae11dc9 100644 --- a/bench/commands/config.py +++ b/bench/commands/config.py @@ -55,6 +55,14 @@ def config_http_timeout(seconds): update_config({"http_timeout": seconds}) +@click.command( + "ssl_client_certificate", help="Set certificate path to nginx use on mtls" +) +@click.argument("path", type=str) +def config_ssl_client_certificate(path): + update_config({"ssl_client_certificate": path}) + + @click.command("set-common-config", help="Set value in common config") @click.option("configs", "-c", "--config", multiple=True, type=(str, str)) def set_common_config(configs): @@ -95,5 +103,6 @@ config.add_command(config_dns_multitenant) config.add_command(config_rebase_on_pull) config.add_command(config_serve_default_site) config.add_command(config_http_timeout) +config.add_command(config_ssl_client_certificate) config.add_command(set_common_config) config.add_command(remove_common_config) diff --git a/bench/config/templates/bench_manager_nginx.conf b/bench/config/templates/bench_manager_nginx.conf index bab26e88..155296ca 100644 --- a/bench/config/templates/bench_manager_nginx.conf +++ b/bench/config/templates/bench_manager_nginx.conf @@ -12,7 +12,18 @@ server { ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; ssl_prefer_server_ciphers on; + {% if ssl_client_certificate %} + ssl_client_certificate {{ ssl_client_certificate }}; + ssl_verify_client optional; {% endif %} + {% endif %} + + location /api/secure/ { + if ($ssl_client_verify != SUCCESS) { + return 403; + } + try_files $uri @webserver; + } location /assets { try_files $uri =404; @@ -44,6 +55,7 @@ server { proxy_set_header X-Frappe-Site-Name {{ bench_manager_site_name }}; proxy_set_header Host {{ bench_manager_site_name }}; proxy_set_header X-Use-X-Accel-Redirect True; + proxy_set_header SSL_CLIENT_CERT $ssl_client_cert; proxy_read_timeout {{ http_timeout or 120 }}; proxy_redirect off; diff --git a/bench/config/templates/nginx.conf b/bench/config/templates/nginx.conf index cd6a6701..95004022 100644 --- a/bench/config/templates/nginx.conf +++ b/bench/config/templates/nginx.conf @@ -10,7 +10,7 @@ map {{ from_variable }} {{ to_variable }} { } {%- endmacro %} -{%- macro server_block(bench_name, port, server_names, site_name, sites_path, ssl_certificate, ssl_certificate_key) %} +{%- macro server_block(bench_name, port, server_names, site_name, sites_path, ssl_certificate, ssl_certificate_key, ssl_client_certificate) %} server { {% if ssl_certificate and ssl_certificate_key %} listen {{ port }} ssl; @@ -48,6 +48,10 @@ server { ssl_ciphers EECDH+AESGCM:EDH+AESGCM; ssl_ecdh_curve secp384r1; ssl_prefer_server_ciphers on; + {% if ssl_client_certificate %} + ssl_client_certificate {{ ssl_client_certificate }}; + ssl_verify_client optional; + {% endif %} {% endif %} add_header X-Frame-Options "SAMEORIGIN"; @@ -56,6 +60,13 @@ server { add_header X-XSS-Protection "1; mode=block"; add_header Referrer-Policy "same-origin, strict-origin-when-cross-origin"; + location /api/secure/ { + if ($ssl_client_verify != SUCCESS) { + return 403; + } + try_files $uri @webserver; + } + location /assets { try_files $uri =404; add_header Cache-Control "max-age=31536000"; @@ -98,6 +109,7 @@ server { proxy_set_header X-Frappe-Site-Name {{ site_name }}; proxy_set_header Host $host; proxy_set_header X-Use-X-Accel-Redirect True; + proxy_set_header SSL_CLIENT_CERT $ssl_client_cert; proxy_read_timeout {{ http_timeout or 120 }}; proxy_redirect off; @@ -214,7 +226,8 @@ limit_conn_zone $host zone=per_host_{{ bench_name_hash }}:{{ limit_conn_shared_m {{ server_block(bench_name, port=443, server_names=sites.that_use_wildcard_ssl, site_name=site_name_variable, sites_path=sites_path, ssl_certificate=sites.wildcard_ssl_certificate, - ssl_certificate_key=sites.wildcard_ssl_certificate_key) }} + ssl_certificate_key=sites.wildcard_ssl_certificate_key, + ssl_client_certificate=ssl_client_certificate) }} {%- endif %} @@ -223,7 +236,8 @@ limit_conn_zone $host zone=per_host_{{ bench_name_hash }}:{{ limit_conn_shared_m {{ server_block(bench_name, port=443, server_names=[site.domain or site.name], site_name=site_name_variable, sites_path=sites_path, - ssl_certificate=site.ssl_certificate, ssl_certificate_key=site.ssl_certificate_key) }} + ssl_certificate=site.ssl_certificate, ssl_certificate_key=site.ssl_certificate_key, + ssl_client_certificate=ssl_client_certificate) }} {% endfor %} {%- endif %} diff --git a/docs/bench_usage.md b/docs/bench_usage.md index 07b7e080..f2f86eef 100644 --- a/docs/bench_usage.md +++ b/docs/bench_usage.md @@ -178,7 +178,7 @@ The config group commands are used for manipulating configurations in the curren - **dns_multitenant**: Enable/Disable bench multitenancy on running bench update - **serve_default_site**: Configure nginx to serve the default site on port 80 - **http_timeout**: Set HTTP timeout - + - **ssl_client_certificate**: set certificate path to nginx use on mtls (unique file with many certificates inside) ## Install commands