From c784d3ab76e872dc28c1ea62137e9f95106e6c58 Mon Sep 17 00:00:00 2001 From: Hugo Geoffroy Date: Wed, 20 May 2020 09:29:27 +0200 Subject: nixos/haproxy: add reloading support, use upstream service hardening Refactor the systemd service definition for the haproxy reverse proxy, using the upstream systemd service definition. This allows the service to be reloaded on changes, preserving existing server state, and adds some hardening options. --- nixos/modules/services/networking/haproxy.nix | 32 +++++++++++++++++++++++---- nixos/tests/haproxy.nix | 8 +++++++ 2 files changed, 36 insertions(+), 4 deletions(-) (limited to 'nixos') diff --git a/nixos/modules/services/networking/haproxy.nix b/nixos/modules/services/networking/haproxy.nix index 4678829986c6..e9d72b35499d 100644 --- a/nixos/modules/services/networking/haproxy.nix +++ b/nixos/modules/services/networking/haproxy.nix @@ -56,6 +56,9 @@ with lib; message = "You must provide services.haproxy.config."; }]; + # configuration file indirection is needed to support reloading + environment.etc."haproxy.cfg".source = haproxyCfg; + systemd.services.haproxy = { description = "HAProxy"; after = [ "network.target" ]; @@ -64,11 +67,32 @@ with lib; User = cfg.user; Group = cfg.group; Type = "notify"; - # when running the config test, don't be quiet so we can see what goes wrong - ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}"; - ExecStart = "${pkgs.haproxy}/sbin/haproxy -Ws -f ${haproxyCfg}"; - Restart = "on-failure"; + ExecStartPre = [ + # when the master process receives USR2, it reloads itself using exec(argv[0]), + # so we create a symlink there and update it before reloading + "${pkgs.coreutils}/bin/ln -sf ${pkgs.haproxy}/sbin/haproxy /run/haproxy/haproxy" + # when running the config test, don't be quiet so we can see what goes wrong + "/run/haproxy/haproxy -c -f ${haproxyCfg}" + ]; + ExecStart = "/run/haproxy/haproxy -Ws -f /etc/haproxy.cfg -p /run/haproxy/haproxy.pid"; + # support reloading + ExecReload = [ + "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}" + "${pkgs.coreutils}/bin/ln -sf ${pkgs.haproxy}/sbin/haproxy /run/haproxy/haproxy" + "${pkgs.coreutils}/bin/kill -USR2 $MAINPID" + ]; + KillMode = "mixed"; + SuccessExitStatus = "143"; + Restart = "always"; RuntimeDirectory = "haproxy"; + # upstream hardening options + NoNewPrivileges = true; + ProtectHome = true; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + SystemCallFilter= "~@cpu-emulation @keyring @module @obsolete @raw-io @reboot @swap @sync"; # needed in case we bind to port < 1024 AmbientCapabilities = "CAP_NET_BIND_SERVICE"; }; diff --git a/nixos/tests/haproxy.nix b/nixos/tests/haproxy.nix index 79f34b07faf4..ffb77c052a24 100644 --- a/nixos/tests/haproxy.nix +++ b/nixos/tests/haproxy.nix @@ -43,5 +43,13 @@ import ./make-test-python.nix ({ pkgs, ...}: { assert "haproxy_process_pool_allocated_bytes" in machine.succeed( "curl -k http://localhost:80/metrics" ) + + with subtest("reload"): + machine.succeed("systemctl reload haproxy") + # wait some time to ensure the following request hits the reloaded haproxy + machine.sleep(5) + assert "We are all good!" in machine.succeed( + "curl -k http://localhost:80/index.txt" + ) ''; }) -- cgit 1.4.1