准备运行账号与目录

启动公告服务前,我们先规划好运行账号和目录权限。

不少新手图省事,习惯直接用 root 跑后台服务,或者遇到权限报错就把目录设成 777。这样一旦服务程序有漏洞,攻击者拿到手的直接就是 root 权限,整台服务器都会失守。因此配置服务时应当遵循最小权限原则:程序只需要完成本职工作的那点权限,多余的一概不给。

在这台图书馆服务器上,有两项不同的需求:

  1. 对外公告服务:只需要读取 /srv/bulletin 目录里已发布的公告,不应该访问其他内部文件。我们用专用的低权限系统账号 bulletin 来跑这个服务,并禁止该账号登录终端。
  2. 内部草稿协作:编辑人员需要登录服务器,在共享目录 /srv/editor-drafts 里共同编写未发布的草稿。这些草稿不能让对外公告服务读到。

查看服务专用账号

先看系统里预置的 bulletin 账号:

crow@opsbox:~$ getent passwd bulletin
bulletin:x:998:998::/nonexistent:/usr/sbin/nologin

这行记录对应 /etc/passwd 的七个字段:用户名、密码占位符 x、UID(998)、主组 GID(998)、注释、主目录(/nonexistent)和登录 Shell(/usr/sbin/nologin)。

  • 在 Ubuntu/Debian 中,UID 0 是 root,1~999 留给系统守护进程与服务账号(如 www-data、bulletin),普通用户的 UID 从 1000 起步。
  • 最后一列设为 /usr/sbin/nologin(或 /bin/false),代表该账号无法通过 SSH 或控制台登录交互式 Shell。需要手动创建这类系统服务账号时,可以执行 sudo useradd -r -s /usr/sbin/nologin 服务名。

创建编辑团队账号

接着创建编辑组 editors,并添加一个属于该组的普通用户 editor:

crow@opsbox:~$ sudo groupadd editors
crow@opsbox:~$ sudo useradd -m -s /bin/bash -G editors editor
crow@opsbox:~$ id editor
uid=1001(editor) gid=1002(editor) groups=1002(editor),1001(editors)
  • -m:自动创建家目录 /home/editor;
  • -s /bin/bash:指定登录 Shell 为 /bin/bash;
  • -G editors:把用户加入附加组 editors(如果是给已有用户追加附加组,用 sudo usermod -aG 组名 用户名,切记加上 -a,否则会覆盖原有的附加组)。

然后给 editor 设置登录密码(输入密码时终端不会显示任何字符):

crow@opsbox:~$ sudo passwd editor
New password:
Retype new password:
passwd: password updated successfully

提示

普通用户能不能用 sudo,由 /etc/sudoers 或 /etc/sudoers.d/ 决定。修改该配置时不要直接用编辑器改文件,应当运行 sudo visudo——它会在保存时自动检查语法,避免写错一行导致所有人没法用 sudo。想查看某个用户拥有哪些提权权限,可以运行 sudo -l -U 用户名。

配置团队共享草稿目录

接下来创建编辑团队共用的草稿目录 /srv/editor-drafts,设置属组和权限:

crow@opsbox:~$ sudo mkdir /srv/editor-drafts
crow@opsbox:~$ sudo chown root:editors /srv/editor-drafts
crow@opsbox:~$ sudo chmod 2770 /srv/editor-drafts
crow@opsbox:~$ ls -ld /srv/editor-drafts
drwxrws--- 2 root editors 4096 ... /srv/editor-drafts

四位八进制权限 2770 对应字符权限 drwxrws---:

  • 后三位 770 表示所有者 root 和属组 editors 都有读、写、进入目录的权限,其他用户(---)连进目录看文件名的权限都没有;
  • 开头的 2 表示在目录上设置了 SGID(Set Group ID),属组执行位从 x 变成了 s。目录开启 SGID 后,任何人在这个目录下新建文件或子目录,新文件的属组都会自动继承父目录的 editors,而不是创建者自己的私人主组。如果不设 SGID,张三建的文件属组是 zhangsan,同在 editors 组的李四也没法直接修改。

我们切到 editor 账号建一份草稿试试:

crow@opsbox:~$ sudo -iu editor
editor@opsbox:~$ umask 0002
editor@opsbox:~$ printf '阅览室周末照常开放。\n' > /srv/editor-drafts/weekend-draft.txt
editor@opsbox:~$ stat -c '%U %G %a' /srv/editor-drafts/weekend-draft.txt
editor editors 664
editor@opsbox:~$ exit

umask 0002 让新建文件的默认权限变成 664(0666 - 0002,即属主和属组都可读写);加上父目录的 SGID,weekend-draft.txt 的属组自动变成了 editors,同组的其他编辑就能直接修改它了。最后输入 exit 退回 crow 账号。

团队共享目录的特殊权限

练习

管理员将共享目录 /srv/editor-drafts 的权限设为 2770(drwxrws---),其中开头的 2(SGID)对目录起什么作用?

A. 让目录内新建的文件自动继承该目录的所属组(editors),便于同组成员协作修改。 B. 禁止除文件所有者以外的任何人删除该目录下的文件。 C. 让所有进入该目录的用户临时获得 root 权限。 D. 加密该目录下的所有草稿文件。

提交选项字母。

提交答案

题解 Hint

验证权限隔离效果

现在以对外公告服务账号 bulletin 的身份,测试它能不能读到公开公告和内部草稿:

crow@opsbox:~$ sudo -u bulletin cat /srv/bulletin/hours.txt
图书馆开放时间:09:00-18:00
crow@opsbox:~$ sudo -u bulletin cat /srv/editor-drafts/weekend-draft.txt
cat: /srv/editor-drafts/weekend-draft.txt: Permission denied

bulletin 可以正常读取 /srv/bulletin/hours.txt,但读取 /srv/editor-drafts/weekend-draft.txt 时直接返回 Permission denied。因为 /srv/editor-drafts 的权限是 2770,bulletin 既不是 root 也不在 editors 组里,直接被拦在了目录外面。就算对外公告服务出了任意文件读取漏洞,也不会泄露未发布的内部草稿。