From fdbd4e9f8e6d3a2e25c498394252e23357cb78ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 24 Mar 2024 18:14:40 +0100 Subject: [PATCH] nginx: add nginx-base role like module --- modules/defaults/base/sshd.nix | 2 +- modules/defaults/default.nix | 2 +- modules/defaults/nginx.nix | 19 --------- .../nginx/conf.d/connection-upgrade.conf | 6 +++ .../nginx/conf.d/hash-bucket-size.conf | 1 + .../nginx/conf.d/mgit-json-logging.conf | 17 ++++++++ .../defaults/nginx/conf.d/server-tokens.conf | 1 + modules/defaults/nginx/default.nix | 39 +++++++++++++++++++ modules/defaults/nginx/snippets/acmetool.conf | 5 +++ .../nginx/snippets/cf-origin-pull.conf | 3 ++ modules/defaults/nginx/snippets/hsts.conf | 1 + .../nginx/snippets/proxy-forward-headers.conf | 5 +++ .../defaults/nginx/snippets/proxy-nobuff.conf | 4 ++ .../nginx/snippets/security-headers.conf | 6 +++ .../defaults/nginx/snippets/tls-legacy.conf | 9 +++++ modules/defaults/nginx/snippets/tls.conf | 14 +++++++ modules/defaults/nginx/snippets/tls1_2.conf | 11 ++++++ tests/nginx.nix | 23 +++++++++++ 18 files changed, 147 insertions(+), 21 deletions(-) delete mode 100644 modules/defaults/nginx.nix create mode 100644 modules/defaults/nginx/conf.d/connection-upgrade.conf create mode 100644 modules/defaults/nginx/conf.d/hash-bucket-size.conf create mode 100644 modules/defaults/nginx/conf.d/mgit-json-logging.conf create mode 100644 modules/defaults/nginx/conf.d/server-tokens.conf create mode 100644 modules/defaults/nginx/default.nix create mode 100644 modules/defaults/nginx/snippets/acmetool.conf create mode 100644 modules/defaults/nginx/snippets/cf-origin-pull.conf create mode 100644 modules/defaults/nginx/snippets/hsts.conf create mode 100644 modules/defaults/nginx/snippets/proxy-forward-headers.conf create mode 100644 modules/defaults/nginx/snippets/proxy-nobuff.conf create mode 100644 modules/defaults/nginx/snippets/security-headers.conf create mode 100644 modules/defaults/nginx/snippets/tls-legacy.conf create mode 100644 modules/defaults/nginx/snippets/tls.conf create mode 100644 modules/defaults/nginx/snippets/tls1_2.conf create mode 100644 tests/nginx.nix diff --git a/modules/defaults/base/sshd.nix b/modules/defaults/base/sshd.nix index 1242a54..e4870dd 100644 --- a/modules/defaults/base/sshd.nix +++ b/modules/defaults/base/sshd.nix @@ -11,7 +11,7 @@ with lib; HostbasedAuthentication = false; PermitEmptyPasswords = false; UseDns = false; - UsePAM = mkDefault true; + UsePAM = mkDefault false; }; # https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/doc/user/gitlab_com/index.md#ssh-host-keys-fingerprints diff --git a/modules/defaults/default.nix b/modules/defaults/default.nix index 2429be3..87b1df9 100644 --- a/modules/defaults/default.nix +++ b/modules/defaults/default.nix @@ -2,7 +2,7 @@ imports = [ ./base ./misc.nix - ./nginx.nix + ./nginx ./zsh ]; } diff --git a/modules/defaults/nginx.nix b/modules/defaults/nginx.nix deleted file mode 100644 index 51cd0e0..0000000 --- a/modules/defaults/nginx.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ options, config, lib, ... }@args: -import ./_with_unify.nix args config.services.nginx.enable -{ - services.nginx = { - enableReload = true; - recommendedBrotliSettings = true; - recommendedGzipSettings = true; - recommendedOptimisation = true; - recommendedProxySettings = true; - recommendedTlsSettings = true; - recommendedZstdSettings = true; - }; -} -{ - nix-unify = { - modules.shareSystemd.units = [ "nginx.service" ]; - files.etc."nginx" = {}; - }; -} diff --git a/modules/defaults/nginx/conf.d/connection-upgrade.conf b/modules/defaults/nginx/conf.d/connection-upgrade.conf new file mode 100644 index 0000000..4153eff --- /dev/null +++ b/modules/defaults/nginx/conf.d/connection-upgrade.conf @@ -0,0 +1,6 @@ +# used for websockets +# set http_connection to either upgrade or close (as normal) +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} diff --git a/modules/defaults/nginx/conf.d/hash-bucket-size.conf b/modules/defaults/nginx/conf.d/hash-bucket-size.conf new file mode 100644 index 0000000..9fdc6f1 --- /dev/null +++ b/modules/defaults/nginx/conf.d/hash-bucket-size.conf @@ -0,0 +1 @@ +server_names_hash_bucket_size 64; diff --git a/modules/defaults/nginx/conf.d/mgit-json-logging.conf b/modules/defaults/nginx/conf.d/mgit-json-logging.conf new file mode 100644 index 0000000..52d9e83 --- /dev/null +++ b/modules/defaults/nginx/conf.d/mgit-json-logging.conf @@ -0,0 +1,17 @@ +log_format logger-mgit-json escape=json '{' + '"http_host": "$http_host", ' + '"remote_addr": "$remote_addr", ' + '"time_msec": $msec, ' + '"time_local": "$time_local", ' + '"status": $status, ' + '"body_bytes_sent": $body_bytes_sent, ' + '"http_referrer": "$http_referrer", ' + '"request_time": $request_time, ' + '"upstream_response_time": "$upstream_response_time", ' + '"request_length": $request_length, ' + '"request_method": "$request_method", ' + '"request_uri": "$request_uri", ' + '"upstream_addr": "$upstream_addr", ' + '"http_user_agent": "$http_user_agent", ' + '"request": "$request"' + '}'; diff --git a/modules/defaults/nginx/conf.d/server-tokens.conf b/modules/defaults/nginx/conf.d/server-tokens.conf new file mode 100644 index 0000000..b3a5f35 --- /dev/null +++ b/modules/defaults/nginx/conf.d/server-tokens.conf @@ -0,0 +1 @@ +server_tokens off; diff --git a/modules/defaults/nginx/default.nix b/modules/defaults/nginx/default.nix new file mode 100644 index 0000000..a9fdde0 --- /dev/null +++ b/modules/defaults/nginx/default.nix @@ -0,0 +1,39 @@ +{ options, config, lib, ... }@args: +import ../_with_unify.nix args config.services.nginx.enable +{ + services.nginx = { + enableReload = true; + recommendedBrotliSettings = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedZstdSettings = true; + + # Default block returns null for SSL requests with the wrong hostname + # This is to prevent SNI info leak. This configuration only works for nginx 1.19.4 and later. + virtualHosts."default" = { + default = true; + listen = [ + { port = 443; ssl = true; addr = "[::]"; } + { port = 80; addr = "[::]"; } + ]; + extraConfig = '' + ssl_reject_handshake on; + ''; + locations."/".extraConfig = '' + return 404 "This domain is not configured on this server. Please contact your administrator if this seems wrong."; + ''; + }; + + }; + + environment.etc."nginx/conf.d".source = ./conf.d; + environment.etc."nginx/snippets".source = ./snippets; +} +{ + nix-unify = { + modules.shareSystemd.units = [ "nginx.service" ]; + files.etc."nginx" = {}; + }; +} diff --git a/modules/defaults/nginx/snippets/acmetool.conf b/modules/defaults/nginx/snippets/acmetool.conf new file mode 100644 index 0000000..e2f14f1 --- /dev/null +++ b/modules/defaults/nginx/snippets/acmetool.conf @@ -0,0 +1,5 @@ +# snippet from ansible by mgit +location /.well-known/acme-challenge/ { + auth_basic off; + alias /run/acme/acme-challenge/; +} diff --git a/modules/defaults/nginx/snippets/cf-origin-pull.conf b/modules/defaults/nginx/snippets/cf-origin-pull.conf new file mode 100644 index 0000000..da69191 --- /dev/null +++ b/modules/defaults/nginx/snippets/cf-origin-pull.conf @@ -0,0 +1,3 @@ +# cf authenticated only +ssl_client_certificate /etc/ssl/cloudflare/origin_pull.pem; +ssl_verify_client on; diff --git a/modules/defaults/nginx/snippets/hsts.conf b/modules/defaults/nginx/snippets/hsts.conf new file mode 100644 index 0000000..e072350 --- /dev/null +++ b/modules/defaults/nginx/snippets/hsts.conf @@ -0,0 +1 @@ +add_header Strict-Transport-Security max-age=15768000 always; diff --git a/modules/defaults/nginx/snippets/proxy-forward-headers.conf b/modules/defaults/nginx/snippets/proxy-forward-headers.conf new file mode 100644 index 0000000..01ec0d7 --- /dev/null +++ b/modules/defaults/nginx/snippets/proxy-forward-headers.conf @@ -0,0 +1,5 @@ +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-Ssl on; +proxy_set_header X-Forwarded-Port $server_port; diff --git a/modules/defaults/nginx/snippets/proxy-nobuff.conf b/modules/defaults/nginx/snippets/proxy-nobuff.conf new file mode 100644 index 0000000..b08de70 --- /dev/null +++ b/modules/defaults/nginx/snippets/proxy-nobuff.conf @@ -0,0 +1,4 @@ +proxy_buffering off; +proxy_ignore_headers "X-Accel-Buffering"; +proxy_request_buffering off; +proxy_http_version 1.1; diff --git a/modules/defaults/nginx/snippets/security-headers.conf b/modules/defaults/nginx/snippets/security-headers.conf new file mode 100644 index 0000000..1edfe3f --- /dev/null +++ b/modules/defaults/nginx/snippets/security-headers.conf @@ -0,0 +1,6 @@ +add_header X-Frame-Options DENY; +add_header X-Content-Type-Options nosniff; +add_header X-XSS-Protection "1; mode=block"; +# TODO: Test Secruity headers +# This still needs to be tested to see if it breaks anything +# add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'"; diff --git a/modules/defaults/nginx/snippets/tls-legacy.conf b/modules/defaults/nginx/snippets/tls-legacy.conf new file mode 100644 index 0000000..3dc4caf --- /dev/null +++ b/modules/defaults/nginx/snippets/tls-legacy.conf @@ -0,0 +1,9 @@ +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AES:!ADH:!AECDH:!MD5; +ssl_prefer_server_ciphers on; + +ssl_dhparam /etc/ssl/dhparams.pem; + +ssl_session_cache shared:SSL:10m; +ssl_session_timeout 10m; +ssl_session_tickets off; diff --git a/modules/defaults/nginx/snippets/tls.conf b/modules/defaults/nginx/snippets/tls.conf new file mode 100644 index 0000000..a0e3c20 --- /dev/null +++ b/modules/defaults/nginx/snippets/tls.conf @@ -0,0 +1,14 @@ +# ssl security config for tls1.3 by mgit +# 20240219 - intermediate security nginx config https://mozilla.github.io/server-side-tls/ssl-config-generator/ +# generated 2024-02-19, Mozilla Guideline v5.7, nginx 1.14.2, OpenSSL 1.1.1n, intermediate configuration +# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1n&guideline=5.7 +# This version is based on the nginx version and openssl version of Debian 10 Buster, because this the oldest OS +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; + +ssl_dhparam /etc/ssl/dhparams.pem; + +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers 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:DHE-RSA-CHACHA20-POLY1305; +ssl_prefer_server_ciphers off; diff --git a/modules/defaults/nginx/snippets/tls1_2.conf b/modules/defaults/nginx/snippets/tls1_2.conf new file mode 100644 index 0000000..90f27ee --- /dev/null +++ b/modules/defaults/nginx/snippets/tls1_2.conf @@ -0,0 +1,11 @@ +# ssl security config for tls1.2 by mgit +# 20200710 - intermediate security nginx config https://mozilla.github.io/server-side-tls/ssl-config-generator/ +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:50m; +ssl_session_tickets off; + +ssl_dhparam /etc/ssl/dhparams.pem; + +ssl_protocols TLSv1.2; +ssl_ciphers 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; +ssl_prefer_server_ciphers on; diff --git a/tests/nginx.nix b/tests/nginx.nix new file mode 100644 index 0000000..4e72641 --- /dev/null +++ b/tests/nginx.nix @@ -0,0 +1,23 @@ +inputs: mod: { pkgs, lib, ... }: +{ + name = "nginx"; + + node.specialArgs.inputs = inputs; + + nodes = { + server = { lib, pkgs, ... }: { + imports = mod.default; + services.nginx.enable = true; + + environment.systemPackages = with pkgs; [ + curl + ]; + }; + }; + + testScript = '' + start_all() + server.wait_for_unit("nginx") + server.execute("curl localhost | grep 'This domain is not configured on this server. Please contact your administrator if this seems wrong.'") + ''; +}