我之前一直都是使用docker部署服务,一度热衷于使用docker部署各种self-hosted服务。不知哪一天脑子某根筋不对,
总纠结containerd占用了部分内存,索性尝试一下systemd。
之前我是了解过systemd的,所以只要在网上搜一下配置模板,然后配置好要启动的程序再systemctl start xxx.service
一下
就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/root/app/nginx/logs/nginx.pid
ExecStartPre=/root/app/nginx/sbin/nginx -t
ExecStart=/root/app/nginx/sbin/nginx
ExecReload=/root/app/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
|
上面是nginx的模板非常简单,但也足够使用了,直到我重新部署maddy(一个用go实现的邮件服务)。
经常使用linux小伙伴都知道启动一个服务最好不要用root用户以避免安全问题。对于我来说一直在使用root用户
图方便(反正是自己的vps,没啥重要数据),完全没有安全意识,而maddy官方文档中给出了更安全的配置方法,
借此我才有机会更多的了解了systemd,下面给出maddy systemd的配置步骤(maddy本身的配置不在本次讨论)。
- 创建一个新用户
1
|
useradd -mrU -s /sbin/nologin -d /var/lib/maddy -c "maddy mail server" maddy
|
参数解释:
-m
创建home目录
-r
创建为系统用户
-U
创建同名的group
-s
新用户的login shell
-d
home目录的路径
-c
用户的一些信息
- 复制maddy release附带的service配置文件到systemd标准目录中
1
|
cp systemd/*.service /etc/systemd/system
|
- 加载新service配置文件并启动
1
2
|
systemctl daemon-reload
systemctl start maddy
|
整个配置流程还算简单,关键在于maddy的service内容。maddy有两个service文件:maddy.service
和maddy@.service
,其中带@
符号的文件可以视为模板,这两个文件的内容差不多,这里只展示maddy.service
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
[Unit]
Description=maddy mail server
Documentation=man:maddy(1)
Documentation=man:maddy.conf(5)
Documentation=https://maddy.email
After=network-online.target
[Service]
Type=notify
NotifyAccess=main
User=maddy
Group=maddy
# cd to state directory to make sure any relative paths
# in config will be relative to it unless handled specially.
WorkingDirectory=/var/lib/maddy
ConfigurationDirectory=maddy
RuntimeDirectory=maddy
StateDirectory=maddy
LogsDirectory=maddy
ReadOnlyPaths=/usr/lib/maddy
ReadWritePaths=/var/lib/maddy
# Strict sandboxing. You have no reason to trust code written by strangers from GitHub.
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectHostname=true
ProtectClock=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
# Additional sandboxing. You need to disable all of these options
# for privileged helper binaries (for system auth) to work correctly.
NoNewPrivileges=true
PrivateDevices=true
DeviceAllow=/dev/syslog
RestrictSUIDSGID=true
ProtectKernelModules=true
MemoryDenyWriteExecute=true
RestrictNamespaces=true
RestrictRealtime=true
LockPersonality=true
# Graceful shutdown with a reasonable timeout.
TimeoutStopSec=7s
KillMode=mixed
KillSignal=SIGTERM
# Required to bind on ports lower than 1024.
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# Force all files created by maddy to be only readable by it
# and maddy group.
UMask=0007
# Bump FD limitations. Even idle mail server can have a lot of FDs open (think
# of idle IMAP connections, especially ones abandoned on the other end and
# slowly timing out).
LimitNOFILE=131072
# Limit processes count to something reasonable to
# prevent resources exhausting due to big amounts of helper
# processes launched.
LimitNPROC=512
# Restart server on any problem.
Restart=on-failure
# ... Unless it is a configuration problem.
RestartPreventExitStatus=2
ExecStart=/usr/local/bin/maddy run
ExecReload=/bin/kill -USR1 $MAINPID
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
|
可以看到配置中明确指定使用maddy用户启动服务,另外需要注意的是Type=notify
,该类型要求服务支持systemd notify
,
所以如果启动了自己写的程序或者不知道第三方应用是否支持,你可以把该类型改为simple
,并且不需要NotifyAccess
配置选项。
下面来详细说说配置文件中关于安全的选项(Gemini生成),其他选项可以自行搜索。
- PrivateTmp=true:为服务创建一个私有的 /tmp 和 /var/tmp 目录,与其他进程隔离。
- ProtectHome=true:禁止服务访问 /home、/root 和 /run/user 目录。邮件服务器通常不需要访问用户家目录。
- ProtectSystem=strict:将 /usr、/boot 和 /etc 目录挂载为只读,防止服务修改系统文件和配置。
- ProtectKernelTunables=true:禁止服务修改内核参数(sysctls)。
- ProtectHostname=true:禁止服务修改系统主机名。
- ProtectClock=true:禁止服务修改系统时钟。
- ProtectControlGroups=true:禁止服务修改 Linux 控制组(cgroups)文件系统,防止其逃避资源限制。
- RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6:限制服务能使用的网络协议族。这里只允许 Unix 套接字(用于本地通信)、IPv4 和 IPv6,这正是邮件服务器所需要的全部。
- NoNewPrivileges=true:禁止服务及其子进程通过 execve() 获取新的权限(例如,通过 SUID/SGID 程序)。这是一个非常重要的安全特性。
- PrivateDevices=true:禁止服务直接访问物理设备(/dev 下的文件),除非明确允许。
- DeviceAllow=/dev/syslog:作为 PrivateDevices 的例外,允许服务访问 /dev/syslog 以便写入系统日志。
- RestrictSUIDSGID=true:使文件上的 SUID 和 SGID 位失效。
- ProtectKernelModules=true:禁止服务加载或卸载内核模块。
- MemoryDenyWriteExecute=true:强制实施 W^X(Write XOR Execute)策略。内存页要么是可写的,要么是可执行的,但不能同时是两者。这可以防止许多缓冲区溢出类的攻击。
- RestrictNamespaces=true:禁止服务创建新的命名空间(namespace),防止其进一步隔离自身或创建容器。
- RestrictRealtime=true:禁止服务获取实时调度策略,防止其通过占用 CPU 资源发动拒绝服务攻击。
- LockPersonality=true:锁定进程的“个性”(personality),防止其改变执行域(例如,模拟旧版 Linux ABI)。
可以看出maddy的service配置文件相比最简单的模板来说安全了许多,大家可以根据它来自定义修改。