systemd: switch to deny-everything-by-default (TemporaryFileSystem=/) with explicit BindReadOnlyPaths + BindPaths allowlist
This commit is contained in:
@@ -15,10 +15,37 @@ ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)"
|
|||||||
TimeoutStartSec=10
|
TimeoutStartSec=10
|
||||||
LimitNOFILE=65535
|
LimitNOFILE=65535
|
||||||
|
|
||||||
# === hardening (compatible with LuaJIT + nginx workers + raweb agent) ===
|
# === hardening: deny-everything by default, allowlist via bind mounts ===
|
||||||
|
# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs.
|
||||||
|
# Everything not bind-mounted below is invisible to nginx workers — even
|
||||||
|
# read access. Compromise of a worker can no longer enumerate /etc/passwd,
|
||||||
|
# /home/*, /var/lib/*, /root, /opt, etc.
|
||||||
|
TemporaryFileSystem=/
|
||||||
|
|
||||||
|
# Read-only: nginx binary, dynamic linker, all linked libs, system config,
|
||||||
|
# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc).
|
||||||
|
BindReadOnlyPaths=/usr
|
||||||
|
BindReadOnlyPaths=/lib
|
||||||
|
BindReadOnlyPaths=/lib64
|
||||||
|
BindReadOnlyPaths=/bin
|
||||||
|
BindReadOnlyPaths=/sbin
|
||||||
|
BindReadOnlyPaths=/etc
|
||||||
|
|
||||||
|
# Read-only: vhost docroots + app projects. Add a new line here when you
|
||||||
|
# add a vhost whose root isn't under one of these parents.
|
||||||
|
BindReadOnlyPaths=/raweb
|
||||||
|
BindReadOnlyPaths=/srv
|
||||||
|
BindReadOnlyPaths=/hostdata
|
||||||
|
|
||||||
|
# Read-write: nginx runtime state.
|
||||||
|
# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock
|
||||||
|
# /var/log/nginx access.log, error.log
|
||||||
|
# /nginx config dir (read-mostly but reload writes some state)
|
||||||
|
BindPaths=/run
|
||||||
|
BindPaths=/var/log/nginx
|
||||||
|
BindPaths=/nginx
|
||||||
|
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectHome=true
|
|
||||||
ProtectKernelTunables=true
|
ProtectKernelTunables=true
|
||||||
ProtectKernelModules=true
|
ProtectKernelModules=true
|
||||||
ProtectKernelLogs=true
|
ProtectKernelLogs=true
|
||||||
@@ -35,16 +62,11 @@ LockPersonality=true
|
|||||||
SystemCallArchitectures=native
|
SystemCallArchitectures=native
|
||||||
SystemCallFilter=@system-service
|
SystemCallFilter=@system-service
|
||||||
SystemCallErrorNumber=EPERM
|
SystemCallErrorNumber=EPERM
|
||||||
# ProtectSystem=strict makes the entire filesystem read-only EXCEPT these.
|
|
||||||
# /run covers nginx.pid, nginx.lock, and the temp/ subdir (all tmpfs).
|
|
||||||
ReadWritePaths=/run /var/log/nginx /nginx /hostdata
|
|
||||||
# Read-only paths nginx legitimately accesses. ProtectSystem=strict already
|
|
||||||
# allows reads everywhere by default — these are documented for the operator's
|
|
||||||
# benefit (and so they survive future hardening tightening).
|
|
||||||
ReadOnlyPaths=/raweb /srv /etc/letsencrypt
|
|
||||||
# NOTE deliberately OFF:
|
# NOTE deliberately OFF:
|
||||||
# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages)
|
# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages)
|
||||||
# SystemCallFilter=~@resources breaks nginx workers' prlimit64()
|
# SystemCallFilter=~@resources breaks nginx workers' prlimit64()
|
||||||
|
# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/.
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
+32
-10
@@ -15,10 +15,37 @@ ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)"
|
|||||||
TimeoutStartSec=10
|
TimeoutStartSec=10
|
||||||
LimitNOFILE=65535
|
LimitNOFILE=65535
|
||||||
|
|
||||||
# === hardening (compatible with LuaJIT + nginx workers + raweb agent) ===
|
# === hardening: deny-everything by default, allowlist via bind mounts ===
|
||||||
|
# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs.
|
||||||
|
# Everything not bind-mounted below is invisible to nginx workers — even
|
||||||
|
# read access. Compromise of a worker can no longer enumerate /etc/passwd,
|
||||||
|
# /home/*, /var/lib/*, /root, /opt, etc.
|
||||||
|
TemporaryFileSystem=/
|
||||||
|
|
||||||
|
# Read-only: nginx binary, dynamic linker, all linked libs, system config,
|
||||||
|
# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc).
|
||||||
|
BindReadOnlyPaths=/usr
|
||||||
|
BindReadOnlyPaths=/lib
|
||||||
|
BindReadOnlyPaths=/lib64
|
||||||
|
BindReadOnlyPaths=/bin
|
||||||
|
BindReadOnlyPaths=/sbin
|
||||||
|
BindReadOnlyPaths=/etc
|
||||||
|
|
||||||
|
# Read-only: vhost docroots + app projects. Add a new line here when you
|
||||||
|
# add a vhost whose root isn't under one of these parents.
|
||||||
|
BindReadOnlyPaths=/raweb
|
||||||
|
BindReadOnlyPaths=/srv
|
||||||
|
BindReadOnlyPaths=/hostdata
|
||||||
|
|
||||||
|
# Read-write: nginx runtime state.
|
||||||
|
# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock
|
||||||
|
# /var/log/nginx access.log, error.log
|
||||||
|
# /nginx config dir (read-mostly but reload writes some state)
|
||||||
|
BindPaths=/run
|
||||||
|
BindPaths=/var/log/nginx
|
||||||
|
BindPaths=/nginx
|
||||||
|
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectHome=true
|
|
||||||
ProtectKernelTunables=true
|
ProtectKernelTunables=true
|
||||||
ProtectKernelModules=true
|
ProtectKernelModules=true
|
||||||
ProtectKernelLogs=true
|
ProtectKernelLogs=true
|
||||||
@@ -35,16 +62,11 @@ LockPersonality=true
|
|||||||
SystemCallArchitectures=native
|
SystemCallArchitectures=native
|
||||||
SystemCallFilter=@system-service
|
SystemCallFilter=@system-service
|
||||||
SystemCallErrorNumber=EPERM
|
SystemCallErrorNumber=EPERM
|
||||||
# ProtectSystem=strict makes the entire filesystem read-only EXCEPT these.
|
|
||||||
# /run covers nginx.pid, nginx.lock, and the temp/ subdir (all tmpfs).
|
|
||||||
ReadWritePaths=/run /var/log/nginx /nginx /hostdata
|
|
||||||
# Read-only paths nginx legitimately accesses. ProtectSystem=strict already
|
|
||||||
# allows reads everywhere by default — these are documented for the operator's
|
|
||||||
# benefit (and so they survive future hardening tightening).
|
|
||||||
ReadOnlyPaths=/raweb /srv /etc/letsencrypt
|
|
||||||
# NOTE deliberately OFF:
|
# NOTE deliberately OFF:
|
||||||
# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages)
|
# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages)
|
||||||
# SystemCallFilter=~@resources breaks nginx workers' prlimit64()
|
# SystemCallFilter=~@resources breaks nginx workers' prlimit64()
|
||||||
|
# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/.
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
Reference in New Issue
Block a user