Merge pull request #85567 from Izorkin/nginx-sandbox

This commit is contained in:
Jörg Thalheim 2020-05-13 10:34:02 +01:00 committed by GitHub
commit 6c437ef1bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 1 deletions

View File

@ -235,7 +235,16 @@ php.override {
Be aware that backwards state migrations are not supported by Deluge.
</para>
</listitem>
<listitem>
<para>
Add option <literal>services.nginx.enableSandbox</literal> to starting Nginx web server with additional sandbox/hardening options.
By default, write access to <literal>services.nginx.stateDir</literal> is allowed. To allow writing to other folders,
use <literal>systemd.services.nginx.serviceConfig.ReadWritePaths</literal>
<programlisting>
systemd.services.nginx.serviceConfig.ReadWritePaths = [ "/var/www" ];
</programlisting>
</para>
</listitem>
<listitem>
<para>
The NixOS options <literal>nesting.clone</literal> and

View File

@ -463,6 +463,14 @@ in
'';
};
enableSandbox = mkOption {
default = false;
type = types.bool;
description = ''
Starting Nginx web server with additional sandbox/hardening options.
'';
};
user = mkOption {
type = types.str;
default = "nginx";
@ -710,6 +718,27 @@ in
LogsDirectoryMode = "0750";
# Capabilities
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
# Security
NoNewPrivileges = true;
} // optionalAttrs cfg.enableSandbox {
# Sandboxing
ProtectSystem = "strict";
ProtectHome = mkDefault true;
PrivateTmp = true;
PrivateDevices = true;
ProtectHostname = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
LockPersonality = true;
MemoryDenyWriteExecute = !(builtins.any (mod: (mod.allowMemoryWriteExecute or false)) pkgs.nginx.modules);
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
};
};

View File

@ -225,6 +225,7 @@ in
nginx = handleTest ./nginx.nix {};
nginx-etag = handleTest ./nginx-etag.nix {};
nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
nginx-sandbox = handleTestOn ["x86_64-linux"] ./nginx-sandbox.nix {};
nginx-sso = handleTest ./nginx-sso.nix {};
nix-ssh-serve = handleTest ./nix-ssh-serve.nix {};
nixos-generate-config = handleTest ./nixos-generate-config.nix {};

View File

@ -2,6 +2,7 @@ import ./make-test-python.nix {
name = "nginx-pubhtml";
machine = { pkgs, ... }: {
systemd.services.nginx.serviceConfig.ProtectHome = "read-only";
services.nginx.enable = true;
services.nginx.virtualHosts.localhost = {
locations."~ ^/\\~([a-z0-9_]+)(/.*)?$".alias = "/home/$1/public_html$2";

View File

@ -0,0 +1,66 @@
import ./make-test-python.nix ({ pkgs, ... }: {
name = "nginx-sandbox";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ izorkin ];
};
# This test checks the creation and reading of a file in sandbox mode. Used simple lua script.
machine = { pkgs, ... }: {
nixpkgs.overlays = [
(self: super: {
nginx-lua = super.nginx.override {
modules = [
pkgs.nginxModules.lua
];
};
})
];
services.nginx.enable = true;
services.nginx.package = pkgs.nginx-lua;
services.nginx.enableSandbox = true;
services.nginx.virtualHosts.localhost = {
extraConfig = ''
location /test1-write {
content_by_lua_block {
local create = os.execute('${pkgs.coreutils}/bin/mkdir /tmp/test1-read')
local create = os.execute('${pkgs.coreutils}/bin/touch /tmp/test1-read/foo.txt')
local echo = os.execute('${pkgs.coreutils}/bin/echo worked > /tmp/test1-read/foo.txt')
}
}
location /test1-read {
root /tmp;
}
location /test2-write {
content_by_lua_block {
local create = os.execute('${pkgs.coreutils}/bin/mkdir /var/web/test2-read')
local create = os.execute('${pkgs.coreutils}/bin/touch /var/web/test2-read/bar.txt')
local echo = os.execute('${pkgs.coreutils}/bin/echo error-worked > /var/web/test2-read/bar.txt')
}
}
location /test2-read {
root /var/web;
}
'';
};
users.users.foo.isNormalUser = true;
};
testScript = ''
machine.wait_for_unit("nginx")
machine.wait_for_open_port(80)
# Checking write in temporary folder
machine.succeed("$(curl -vvv http://localhost/test1-write)")
machine.succeed('test "$(curl -fvvv http://localhost/test1-read/foo.txt)" = worked')
# Checking write in protected folder. In sandbox mode for the nginx service, the folder /var/web is mounted
# in read-only mode.
machine.succeed("mkdir -p /var/web")
machine.succeed("chown nginx:nginx /var/web")
machine.succeed("$(curl -vvv http://localhost/test2-write)")
assert "404 Not Found" in machine.succeed(
"curl -vvv -s http://localhost/test2-read/bar.txt"
)
'';
})

View File

@ -140,6 +140,7 @@ in
export LUAJIT_LIB="${pkgs.luajit}/lib"
export LUAJIT_INC="${pkgs.luajit}/include/luajit-2.0"
'';
allowMemoryWriteExecute = true;
};
lua-upstream = {
@ -150,6 +151,7 @@ in
sha256 = "1gqccg8airli3i9103zv1zfwbjm27h235qjabfbfqk503rjamkpk";
};
inputs = [ pkgs.luajit ];
allowMemoryWriteExecute = true;
};
modsecurity = {
@ -246,6 +248,7 @@ in
in {
src = ngx_pagespeed;
inputs = [ pkgs.zlib pkgs.libuuid ]; # psol deps
allowMemoryWriteExecute = true;
};
pam = {