Появление DevOps в 2009 (хотя, по некоторым источникам, это все-таки было в 2008) в корне поменяло процесс взаимодействия между отделами разработки и эксплуатации. До этого момента это были два совершенно разные подразделения со своими целями, задачами и KPI. Как следствие, они не слишком вникали в деятельность друга и часто возникала абсолютно...
Sandboxing Nginx
Visitors have accessed this post 4405 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 от непривилегированного пользователя.
Для этого я сделал несколько пул-реквестов с некоторыми изменениями:
- https://github.com/NixOS/nixpkgs/pull/56255 — nginx: do not run anything as root,
- https://github.com/NixOS/nixpkgs/pull/76174 — nixos/nginx: forced change permissions,
- https://github.com/NixOS/nixpkgs/pull/76533 — nixos/nginx: fixup permissions for Nginx state dir.
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 - teststat -c %a ${cfg.stateDir}
= "750" || chmod 750 ${cfg.stateDir} - teststat -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.
Вам также может понравится
Перевод статьи — https://opensource.com/article/17/11/5-keys-get-started-devops
Вы готовы внедрять DevOps, но не знаете с чего начать? Советуем посмотреть на 5 лучших практик.
DevOps часто вводит в заблуждение новичков некоторой неоднозначностью, не говоря уже о глубине и масштабах. Когда кто-то начинает интересоваться DevOps, его первые...
Часть 2
Автор — Сергей Попов
1 часть статьи
Сканирование портов
Рассказать вам шутку про UDP?
Только она до вас не дойдет.
Изначально Nmap был эффективным средством сканирования портов, и, несмотря на развитие прочего функционала, он им и остается.
Большинство типов сканирования доступны только привилегированным пользователям, потому...