Visitors have accessed this post 3531 times.

Sandboxing Nginx

4
0
3531
13 ноября 2020 9:40
Автор: Rebrain Me
DevOps

Visitors have accessed this post 3531 times.

Автор — Юрий Изоркин

В конце 2018 года мне на глаза попался пул-реквест, который позволял запускать сервис nginx от непривилегированного пользователя — https://github.com/NixOS/nixpkgs/pull/51551 — nginx: do not run anything as root. Это повышает защиту web-сервера nginx.

При каждом запуске сервиса nginx происходит проверка конфигурации на стадии preStart от root пользователя. Лог-файлам присваиваются root права, и запуск nginx от обычного пользователя приводит к ошибке, так как нет прав на запись. Вариант решения путем запуска проверки конфигурации с помощью su-exec не подошел, потому что он сильно усложняет скрипт запуска проверки:

diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index dee877f1c11..2b50c36377d 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -578,7 +578,7 @@ in
         mkdir -p ${cfg.stateDir}/logs
         chmod 700 ${cfg.stateDir}
         chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir}
-        ${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t
+        ${pkgs.su-exec}/bin/su-exec ${cfg.user}:${cfg.group} /run/wrappers/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t
         '';
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir}";
@@ -606,6 +606,14 @@ in
         listToAttrs acmePairs
     );

+    security.wrappers.nginx = {
+      source = "${cfg.package}/bin/nginx";
+      capabilities = "cap_net_bind_service+eip";
+      owner = cfg.user;
+      group = cfg.group;
+      permissions = "u+rx,g+x";
+    };
+
     users.extraUsers = optionalAttrs (cfg.user == "nginx") (singleton
       { name = "nginx";
         group = cfg.group;

Нам потребовалось бы добавить в скрипт запуска ${pkgs.su-exec}/bin/su-exec ${cfg.user}:${cfg.group}, а также для nginx добавить разрешение на открытие 80 порта от непривилегированного пользователя — capabilities = «cap_net_bind_service+eip»;.В последних версиях подсистемы инициализации и управления службами systemd опция PermissionsStartOnly= отмечена как устаревшая. Ее использовали для предварительной подготовки старта службы — создания папок, изменения прав и т.п. Теперь для корректной работы служб стоит использовать утилиту systemd-tmpfiles, она автоматически создает временные директории и присваивает им необходимые права.

Решение нашей задачи

А теперь переходим, собственно, к нашей задаче — запустить сервис nginx от непривилегированного пользователя.

Для этого я сделал несколько пул-реквестов с некоторыми изменениями:

diff --git a/default.nix b/default.nix
index eb90dae..ada7a25 100644
--- a/default.nix
+++ b/default.nix
@@ -47,7 +47,7 @@ let
   ''));

   configFile = pkgs.writers.writeNginxConfig "nginx.conf" ''
-    user ${cfg.user} ${cfg.group};
+    pid /run/nginx/nginx.pid;
     error_log ${cfg.logError};
     daemon off;

@@ -366,12 +366,7 @@ in

       preStart =  mkOption {
         type = types.lines;
-        default = ''
-          test -d ${cfg.stateDir}/logs || mkdir -m 750 -p ${cfg.stateDir}/logs
-          test stat -c %a ${cfg.stateDir} = "750" || chmod 750 ${cfg.stateDir}
-          test stat -c %a ${cfg.stateDir}/logs = "750" || chmod 750 ${cfg.stateDir}/logs
-          chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir}
-        '';
+        default = "";
         description = "
           Shell commands executed before the service's nginx is started.
         ";
@@ -673,23 +668,36 @@ in
       }
     ];

+    systemd.tmpfiles.rules = [
+      "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
+      "d '${cfg.stateDir}/logs' 0750 ${cfg.user} ${cfg.group} - -"
+      "Z '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
+    ];
+
     systemd.services.nginx = {
       description = "Nginx Web Server";
       wantedBy = [ "multi-user.target" ];
       wants = concatLists (map (vhostConfig: ["acme-${vhostConfig.serverName}.service" "acme-selfsigned-${vhostConfig.serverName}.service"]) acmeEnabledVhosts);
       after = [ "network.target" ] ++ map (vhostConfig: "acme-selfsigned-${vhostConfig.serverName}.service") acmeEnabledVhosts;
       stopIfChanged = false;
-      preStart =
-        ''
+      preStart = ''
         ${cfg.preStart}
-        ${cfg.package}/bin/nginx -c ${configPath} -p ${cfg.stateDir} -t
-        '';
+        ${cfg.package}/bin/nginx -c '${configPath}' -p '${cfg.stateDir}' -t
+      '';
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/nginx -c ${configPath} -p ${cfg.stateDir}";
+        ExecStart = "${cfg.package}/bin/nginx -c '${configPath}' -p '${cfg.stateDir}'";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         Restart = "always";
         RestartSec = "10s";
         StartLimitInterval = "1min";
+        # User and group
+        User = cfg.user;
+        Group = cfg.group;
+        # Runtime directory and mode
+        RuntimeDirectory = "nginx";
+        RuntimeDirectoryMode = "0750";
+        # Capabilities
+        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
       };
     };

Собственно, что изменил:

  • Очистил preStart секцию.
  • Добавил systemd-tmpfiles правила для создания папок. Где:
    • d ‘${cfg.stateDir}’ 0750 ${cfg.user} ${cfg.group} — — и d ‘${cfg.stateDir}/logs’ 0750 ${cfg.user} ${cfg.group} — — создают директории с правами 0750 и владельцем nginx по умолчанию.
    • Z ‘${cfg.stateDir}’ — ${cfg.user} ${cfg.group} — — при каждом перезапуске сервиса принудительно меняет пользователя на nginx, если по каким-либо причинам он изменился.
  • Добавил секции User и Group для запуска службы nginx от обычного пользователя nginx по умолчанию.
  • Добавил директорию /run/nginx для размещения pid файла.
  • Добавил привилегию CAP_NET_BIND_SERVICE для сервиса, чтобы можно было запускать сервис nginx от обычного пользователя на 80 порту.
  • Еще я добавил привилегию CAP_SYS_RESOURCE, чтобы в определенной конфигурации сервис nginx мог менять лимиты. Если привилегии нет, вы получите вот такую ошибку:
nginx[13580]: 2019/05/30 21:24:22 [alert] 13582#13582: setrlimit(RLIMIT_NOFILE, 102400) failed (1: Operation not permitted)
  • В конфигурации nginx убрал опцию user ${cfg.user} ${cfg.group};

В одном из следующих пул-реквестов также добавим опцию CapabilityBoundingSet:

          # Capabilities
          AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
+         CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];

А сейчас вернемся немного назад и посмотрим, какие привилегии были у процесса nginx до изменений:

  • У master процесса:
sudo cat /proc/28599/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
  • У worker процесса:
sudo cat /proc/28603/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

Примечание: у nginx есть один главный и несколько рабочих процессов. Основная задача главного процесса — чтение и проверка конфигурации и управление рабочими процессами. Рабочие процессы выполняют фактическую обработку запросов.Процессы nginx имеют следующие привилегии:

  • У master процесса:
capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
  • У worker процесса:
capsh --decode=0000000000000000
0x0000000000000000=

После изменений:

  • У master процесса:
sudo cat /proc/27703/status | grep Cap
CapInh: 0000000001000400
CapPrm: 0000000001000400
CapEff: 0000000001000400
CapBnd: 0000000001000400
CapAmb: 0000000001000400
  • У worker процесса:
sudo cat /proc/27704/status | grep Cap
CapInh: 0000000001000400
CapPrm: 0000000001000400
CapEff: 0000000001000400
CapBnd: 0000000001000400
CapAmb: 0000000001000400

В итоге, master и worker процессам nginx мы ограничили привилегии до минимальных и лишили их root прав:

capsh --decode=0000000001000400
0x0000000001000400=cap_net_bind_service,cap_sys_resource

Так выглядят изменения в конфигурации systemd юнита nginx.service:

diff --git a/nginx.service b/nginx.service
index 17b1727..042a40a 100644
--- a/nginx.service
+++ b/nginx.service
@@ -9,11 +9,16 @@ Environment="TZDIR=/nix/store/8w6g0i881wj5zcqgs235hb6iqzhx8m4n-tzdata-2019c/shar


 X-StopIfChanged=false
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+AmbientCapabilities=CAP_SYS_RESOURCE
 CacheDirectory=nginx
 CacheDirectoryMode=0750
+CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_SYS_RESOURCE
 ExecReload=/nix/store/vssdbs9s059qm5rqpw5q25z3c2d065f7-coreutils-8.31/bin/kill -HUP $MAINPID
-ExecStart=/nix/store/f355cri35wli9ndps5rjnrrc188hj2hc-nginx-1.18.0/bin/nginx -c '/nix/store/zas66gwkjvp48jr4cx3d5jf2cxwhbg9q-nginx.conf'
-ExecStartPre=/nix/store/1qymswvfmji4dwj9q2y4cp6jdyjazl2q-unit-script-nginx-pre-start/bin/nginx-pre-start
+ExecStart=/nix/store/f355cri35wli9ndps5rjnrrc188hj2hc-nginx-1.18.0/bin/nginx -c '/nix/store/1s8jnvkia47ghyg91dli5rpqy90294rb-nginx.conf'
+ExecStartPre=/nix/store/h0daa9zlkvpy1xm61bwmqfy5y61jf76d-unit-script-nginx-pre-start/bin/nginx-pre-start
+Group=nginx
 LogsDirectory=nginx
 LogsDirectoryMode=0750
 NoNewPrivileges=true
@@ -22,4 +27,5 @@ RestartSec=10s
 RuntimeDirectory=nginx
 RuntimeDirectoryMode=0750
 StartLimitInterval=1min
+User=nginx

Systemd также позволяет запускать сервисы в режиме изоляции. В составе systemd есть утилита, при помощи которой можно проанализировать безопасность сервисов. Проверим на сервисе nginx:

sudo systemd-analyze security | grep nginx
nginx.service                                                 9.1 UNSAFE    😨

Больше подробностей можно увидеть командой:

sudo systemd-analyze security nginx

Добавим необходимые параметры изоляции для службы nginx:

diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 1e9cda7e47858..16c56dc745f9e 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -710,6 +710,26 @@ in
         LogsDirectoryMode = "0750";
         # Capabilities
         AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
+        CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
+        # Security
+        NoNewPrivileges = true;
+        # 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 = mkDefault true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        PrivateMounts = true;
+        # System Call Filtering
+        SystemCallArchitectures = "native";
       };
     };

Соответствующий пул-реквест — https://github.com/NixOS/nixpkgs/pull/85567 — nixos/nginx: enable sandboxing.Параметры:

  • NoNewPrivileges = true; — запрещает получение дополнительных привилегий.
  • ProtectSystem = «strict»; — монтирует всю файловую систему в режим чтения, кроме /dev, /proc и /sys.
  • ProtectHome = mkDefault true; — запрещает чтение /home директории, в пользовательской конфигурации можно переопределить параметр.
  • PrivateTmp = true; — перемонтирует директории /tmp and /var/tmp в отдельные приватные директории.
  • PrivateDevices = true; — устанавливает новую точку монтирования /dev и добавляет псевдооборудование /dev/null, /dev/zero или /dev/random. Таким образом блокируется доступ к физическим устройствам.
  • ProtectHostname = true; — устанавливает новое пространство имен UTS и запрещает изменение имени хоста и домена.
  • ProtectKernelTunables = true; — запрещает изменения параметров ядра.
  • ProtectKernelModules = true; — запрещает загрузку и выгрузку модулей ядра.
  • ProtectControlGroups = true; — запрещает изменения в Linux Control Groups (cgroups). Доступ только на чтение.
  • RestrictAddressFamilies = [ «AF_UNIX» «AF_INET» «AF_INET6» ]; — разрешает доступ только к заданному семейству сокетов.
  • LockPersonality = true; — блокирует системный вызов personal.
  • MemoryDenyWriteExecute = mkDefault true; — запрещает маппинг в память, одновременно доступный на запись и исполнение. Требуется разрешить для модулей lua, lua-upstream и pagespeed.
  • RestrictRealtime = true; — запрещает попытки включить планирование в реальном времени.
  • RestrictSUIDSGID = true; — запрещает попытки установить set-user-ID (SUID) и set-group-ID (SGID) биты для файлов и каталогов.
  • PrivateMounts = true; — запускает службу в отдельном собственном пространстве имен в файловой системе.
  • SystemCallArchitectures = «native»; — ограничить неиспользуемые системные вызовы.

После изменения получим:

sudo systemd-analyze security | grep nginx
nginx.service                                                 4.2 OK        🙂

Полученные изменения в конфигурации systemd юнита nginx.service:

diff --git a/nginx.service b/nginx.service
index 042a40a..c6c7525 100644
--- a/nginx.service
+++ b/nginx.service
@@ -19,13 +19,30 @@ ExecReload=/nix/store/vssdbs9s059qm5rqpw5q25z3c2d065f7-coreutils-8.31/bin/kill -
 ExecStart=/nix/store/f355cri35wli9ndps5rjnrrc188hj2hc-nginx-1.18.0/bin/nginx -c '/nix/store/1s8jnvkia47ghyg91dli5rpqy90294rb-nginx.conf'
 ExecStartPre=/nix/store/h0daa9zlkvpy1xm61bwmqfy5y61jf76d-unit-script-nginx-pre-start/bin/nginx-pre-start
 Group=nginx
+LockPersonality=true
 LogsDirectory=nginx
 LogsDirectoryMode=0750
+MemoryDenyWriteExecute=true
 NoNewPrivileges=true
+PrivateDevices=true
+PrivateMounts=true
+PrivateTmp=true
+ProtectControlGroups=true
+ProtectHome=true
+ProtectHostname=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectSystem=strict
 Restart=always
 RestartSec=10s
+RestrictAddressFamilies=AF_UNIX
+RestrictAddressFamilies=AF_INET
+RestrictAddressFamilies=AF_INET6
+RestrictRealtime=true
+RestrictSUIDSGID=true
 RuntimeDirectory=nginx
 RuntimeDirectoryMode=0750
 StartLimitInterval=1min
+SystemCallArchitectures=native
 User=nginx

Для применения текущих изменений в NixOS надо установить nixos-unstable релиз и прописать в конфигурации enableSandbox = true;:

  services.nginx = {
    enable = true;
    package = pkgs.nginx;
    user = "nginx";
    group = "nginx";
    enableSandbox = true;
...
  };

Для применения изменений в других ОС Linux необходимо вручную править конфигурацию systemd юнита nginx.service и /etc/tmpfiles.d/nginx.conf.

Возможные проблемы и их решение

А сейчас кратко остановлюсь на проблемах, которые возникли после изменений, и способах их решения:

Проблема 1

https://github.com/NixOS/nixpkgs/issues/84391 — если попытаться вернуть старый способ работы сервиса nginx от пользователя root, от имени root заработают все процессы, в том числе и дочерние, а в правах директорий будет прописываться пользователь root.

Решение — https://github.com/NixOS/nixpkgs/pull/84960 — в конфигурации прописать:

services.nginx.appendConfig = let cfg = config.services.nginx; in ''user ${cfg.user} ${cfg.group};'';
systemd.services.nginx.serviceConfig.User = lib.mkForce "root";

Проблема 2

https://github.com/NixOS/nixpkgs/issues/85752 — если разместить кеш nginx в директории stateDir — proxy_cache_path /var/spool/nginx/proxycache … сервис nginx выдает ошибку:

Apr 22 07:41:46 oi-web01 s86gqdy00743baj5rrx1f85b6hpx9d3c-unit-script-nginx-pre-start[1083]: nginx: the configuration file /nix/store/w5jj77nr901gpv3rd22jv8zjdsicw6rx-nginx.conf syntax is ok
Apr 22 07:41:46 oi-web01 s86gqdy00743baj5rrx1f85b6hpx9d3c-unit-script-nginx-pre-start[1083]: 2020/04/22 07:41:46 [emerg] 1084#1084: mkdir() "/var/spool/nginx/proxycache" failed (2: No such file or directory)
Apr 22 07:41:46 oi-web01 s86gqdy00743baj5rrx1f85b6hpx9d3c-unit-script-nginx-pre-start[1083]: nginx: configuration file /nix/store/w5jj77nr901gpv3rd22jv8zjdsicw6rx-nginx.conf test failed
Apr 22 07:41:46 oi-web01 systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Apr 22 07:41:46 oi-web01 systemd[1]: nginx.service: Failed with result 'exit-code'.
Apr 22 07:41:46 oi-web01 systemd[1]: Failed to start Nginx Web Server.

Решение — https://github.com/NixOS/nixpkgs/pull/85862a) При сборке пакета nginx нужно вручную указать в параметрах сборки пути к log файлам и cache директориям:


  diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix
  index 67a914b6a9884..80bc1458ad7ab 100644
  --- a/pkgs/servers/http/nginx/generic.nix
  +++ b/pkgs/servers/http/nginx/generic.nix
  @@ -68,6 +68,14 @@ stdenv.mkDerivation {
       "--with-http_stub_status_module"
       "--with-threads"
       "--with-pcre-jit"
  +    "--http-log-path=/var/log/nginx/access.log"
  +    "--error-log-path=/var/log/nginx/error.log"
  +    "--pid-path=/var/log/nginx/nginx.pid"
  +    "--http-client-body-temp-path=/var/cache/nginx/client_body"
  +    "--http-proxy-temp-path=/var/cache/nginx/proxy"
  +    "--http-fastcgi-temp-path=/var/cache/nginx/fastcgi"
  +    "--http-uwsgi-temp-path=/var/cache/nginx/uwsgi"
  +    "--http-scgi-temp-path=/var/cache/nginx/scgi"
     ] ++ optionals withDebug [
       "--with-debug"
     ] ++ optionals withStream [

b) Добавим патч, который при сборке пакета nginx убирает проверку возможности создания log файлов. Иначе, если указать фиксированный путь, сборка пакета прервется с ошибкой:


builder for '/nix/store/0916gy7pga9xnmrcp8fgy1gqgbyyvb55-nginx-1.18.0.drv' failed with exit code 2; last 10 log lines:
         '/nix/store/m5b6ckpq2bz11zsv3sqsprsw7fykp6kr-nginx-1.18.0/conf/scgi_params.default'
  test -f '/nix/store/m5b6ckpq2bz11zsv3sqsprsw7fykp6kr-nginx-1.18.0/conf/nginx.conf' \
     || cp conf/nginx.conf '/nix/store/m5b6ckpq2bz11zsv3sqsprsw7fykp6kr-nginx-1.18.0/conf/nginx.conf'
  cp conf/nginx.conf '/nix/store/m5b6ckpq2bz11zsv3sqsprsw7fykp6kr-nginx-1.18.0/conf/nginx.conf.default'
  test -d '/var/log/nginx' \
          || mkdir -p '/var/log/nginx'
  mkdir: cannot create directory '/var': Permission denied
  make[1]: *** [objs/Makefile:2107: install] Error 1
  make[1]: Leaving directory '/build/nginx-1.18.0'
  make: *** [Makefile:11: install] Error 2
[0 built (1 failed), 0.0 MiB DL]
error: build of '/nix/store/0916gy7pga9xnmrcp8fgy1gqgbyyvb55-nginx-1.18.0.drv' failed
{{EJS24}}
diff --git a/auto/install b/auto/install
index d884487..dccc411 100644
--- a/auto/install
+++ b/auto/install
@@ -148,12 +148,6 @@ install:   build $NGX_INSTALL_PERL_MODULES
                || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH'
        cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default'
   
-       test -d '\$(DESTDIR) "$NGX_PID_PATH"' \\
-               || mkdir -p '\$(DESTDIR) "$NGX_PID_PATH"'
-
-       test -d '\$(DESTDIR) "$NGX_HTTP_LOG_PATH"' \\
-               || mkdir -p '\$(DESTDIR) "$NGX_HTTP_LOG_PATH"'
-
        test -d '\$(DESTDIR)$NGX_PREFIX/html' \\
                || cp -R $NGX_HTML '\$(DESTDIR)$NGX_PREFIX'
 END
@@ -161,9 +155,6 @@ END
   
 if test -n "$NGX_ERROR_LOG_PATH"; then
     cat << END                                                >> $NGX_MAKEFILE
-
-       test -d '\$(DESTDIR) "$NGX_ERROR_LOG_PATH"' \\
-               || mkdir -p '\$(DESTDIR) "$NGX_ERROR_LOG_PATH"'
 END
   
 fi

с) Убираем правила systemd.tmpfiles.rules, которые предварительно создавали необходимые для работы nginx директории:


diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 8d49dc66eb1ab..1e9cda7e47858 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -680,12 +680,6 @@ in
       }
     ];
    
-    systemd.tmpfiles.rules = [
-      "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
-      "d '${cfg.stateDir}/logs' 0750 ${cfg.user} ${cfg.group} - -"
-      "Z '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
-    ];
-
     systemd.services.nginx = {
       description = "Nginx Web Server";
       wantedBy = [ "multi-user.target" ];

d) Убираем настройку stateDir, которая запускала сервис nginx с опцией -p ${cfg.stateDir}. Параметр -p указывает рабочую директорию для nginx.


diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 8d49dc66eb1ab..1e9cda7e47858 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -187,7 +187,7 @@ let
     then "/etc/nginx/nginx.conf"
     else configFile;
    
-  execCommand = "${cfg.package}/bin/nginx -c '${configPath}' -p '${cfg.stateDir}'";
+  execCommand = "${cfg.package}/bin/nginx -c '${configPath}'";
    
   vhosts = concatStringsSep "\n" (mapAttrsToList (vhostName: vhost:
     let
@@ -463,13 +463,6 @@ in
         '';
       };
    
-      stateDir = mkOption {
-        default = "/var/spool/nginx";
-        description = "
-          Directory holding all state for nginx to run.
-        ";
-      };
-
       user = mkOption {
         type = types.str;
         default = "nginx";

e) В настройках systemd прописываем cache и log директории:


diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 8d49dc66eb1ab..1e9cda7e47858 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -708,6 +702,12 @@ in
         # Runtime directory and mode
         RuntimeDirectory = "nginx";
         RuntimeDirectoryMode = "0750";
+        # Cache directory and mode
+        CacheDirectory = "nginx";
+        CacheDirectoryMode = "0750";
+        # Logs directory and mode
+        LogsDirectory = "nginx";
+        LogsDirectoryMode = "0750";
         # Capabilities
         AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
       };

В итоге, у нас сервис nginx по умолчанию пишет log файлы в директорию /var/log/nginx а cache файлы в /var/cache/nginx.

Проблема 3

https://github.com/NixOS/nixpkgs/issues/87698 — ошибка доступа к временным файлам. В некоторых случаях при обновлении конфигурации системы прописываются неверные права директориям:

sudo ls -l /var/spool/nginx/
total 28
drwx------  2 nobody nginx 4096 May 12 15:47 client_body_temp
drwx------  2 nobody nginx 4096 May 12 15:47 fastcgi_temp
drwx------  4 nginx  nginx 4096 May 12 19:30 html
drwxr-x---  2 nginx  nginx 4096 May 12 15:47 logs
drwx------ 12 nobody nginx 4096 May 12 19:30 proxy_temp
drwx------  2 nobody nginx 4096 May 12 15:47 scgi_temp
drwx------  2 nobody nginx 4096 May 12 15:47 uwsgi_temp

Решение — https://github.com/NixOS/nixpkgs/pull/95264 — из сервиса nginx-config-reload нужно убрать проверку конфигурации и перенести ее в модуль ExecReload nginx:

diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 4c4b7f39e6bb6..461888c4cc4f0 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -704,7 +704,10 @@ in
       '';
       serviceConfig = {
         ExecStart = execCommand;
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        ExecReload = [
+          "${execCommand} -t"
+          "${pkgs.coreutils}/bin/kill -HUP $MAINPID"
+        ];
         Restart = "always";
         RestartSec = "10s";
         StartLimitInterval = "1min";
@@ -761,8 +764,7 @@ in
       serviceConfig.TimeoutSec = 60;
       script = ''
         if /run/current-system/systemd/bin/systemctl -q is-active nginx.service ; then
-          ${execCommand} -t && \
-            /run/current-system/systemd/bin/systemctl reload nginx.service
+          /run/current-system/systemd/bin/systemctl reload nginx.service
         fi
       '';
       serviceConfig.RemainAfterExit = true;

Ну что же, задача решена — мы повысили защиту сервиса nginx и убрали root привилегии.

Если у вас остались вопросы по применению этой функциональности, задавайте их в комментариях.

От редакции

Если вам интересно посещать бесплатные онлайн-мероприятия по DevOps, Kubernetes, Docker, GitlabCI и др. и задавать вопросы в режиме реального времени, подключайтесь к каналу DevOps by REBRAIN

*Анонсы мероприятий каждую неделю

Практикумы для специалистов по инфраструктуре и разработчиков — https://rebrainme.com.

Наш Youtube-канал — https://www.youtube.com/channel/UC6uIx64IFKMVmj12gKtSgBQ.

Агентство Fevlake, проектируем и поддерживаем IT-инфраструктуры с 2012 года — https://fevlake.com.

Комментарии (3)
Введено символов из возможных
Не отвечать

Вам также может понравится

Что должен уметь Linux-администратор
array(1) { [0]=> object(WP_Term)#11551 (16) { ["term_id"]=> int(6) ["name"]=> string(5) "Linux" ["slug"]=> string(5) "linux" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(6) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(28) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(6) ["category_count"]=> int(28) ["category_description"]=> string(0) "" ["cat_name"]=> string(5) "Linux" ["category_nicename"]=> string(5) "linux" ["category_parent"]=> int(0) } } Linux

Linux - это та операционная система, с которой вы точно будете работать в любой современной IT-компании. Знание ее изнутри, навык работы с ней при помощи разных инструментов - это тот фундамент, который поможет вам в дальнейшем развиваться в любом направлении IT.

Давайте посмотрим, какие шаги проходит в своей работе, что должен знать...

26
1
6 ноября 2020
30 псевдонимов оболочки Bash в ОС Linux / Unix / Mac OS X
array(1) { [0]=> object(WP_Term)#976 (16) { ["term_id"]=> int(6) ["name"]=> string(5) "Linux" ["slug"]=> string(5) "linux" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(6) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(28) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(6) ["category_count"]=> int(28) ["category_description"]=> string(0) "" ["cat_name"]=> string(5) "Linux" ["category_nicename"]=> string(5) "linux" ["category_parent"]=> int(0) } } Linux

Оригинал статьи - https://www.cyberciti.biz/tips/bash-aliases-mac-centos-linux-unix.html

Псевдоним (он же алиас) bash - это ярлык для команд. Команда alias позволяет пользователю запускать любую команду или группу команд (включая параметры и имена файлов), вводя одно слово. Используйте команду alias, чтобы отобразить список всех определенных...

8
1
9 октября 2020
Утилита для удаленного обслуживания систем на базе ОС NixOS — nixops
array(1) { [0]=> object(WP_Term)#11550 (16) { ["term_id"]=> int(6) ["name"]=> string(5) "Linux" ["slug"]=> string(5) "linux" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(6) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(28) ["filter"]=> string(3) "raw" ["cat_ID"]=> int(6) ["category_count"]=> int(28) ["category_description"]=> string(0) "" ["cat_name"]=> string(5) "Linux" ["category_nicename"]=> string(5) "linux" ["category_parent"]=> int(0) } } Linux

Автор - Юрий Изоркин

Сегодня давайте познакомимся с утилитой nixops для удаленного обслуживания систем на базе ОС NixOS. Также она поддерживает развертывание систем на VirtualBox VM, Amazon EC2, Google Compute Engine, Microsoft Azure, Hetzner physical machines, Digital Ocean, Libvirtd (Qemu), Datadog resources. Подробнее об этих возможностях...

1
2
18 декабря 2020