如果你已经跟着前面的内容把 Ubuntu 装起来、把常用命令跑熟了,那到了第3课第004篇,我们终于要摸到整个系统里最硬核的一条主干了:用户、权限、sudo 和 PAM。这四个词你平时都听过,甚至很多命令你早就在用了,可大多数人并没有把它们串成一条线,结果就是——遇到“新建用户没权限”“sudo 卡死”“远程登录被拒绝”这类问题,只能一个个搜片段,越搜越乱。
这篇我不想再给你列枯燥概念,而是把你丢进真实运维场景里,从一个普通用户如何诞生、如何拿到 sudo 提权、到系统底层怎么认证、怎么锁账户、怎么防爆破,一条链路走完。哪怕你只是笔记本电脑上装的单机 Ubuntu,理解这套机制后,以后看任何 Linux 服务器的权限问题都会通透很多。
1. 先搞清楚你在学什么:用户、权限、sudo、PAM 不是四件事
1.1 用“门禁系统”把四个概念一次理顺
很多教程把用户管理和权限管理分开讲,这是最大的误区。实际 Linux 的安全体系是连贯的:用户是身份,权限是边界,sudo 是提权入口,PAM 是认证规则。
打个比方。公司大楼不是让你随便进的,得先有工牌,这是用户;门禁能读到你工牌属于哪个部门,决定了你能进哪几层,这是权限;你临时要进服务器机房,不能直接拿万能钥匙,得找管理员登记授权,这是 sudo;而最外层那道闸机本身怎么验证你的卡、连续刷错几次会锁卡、什么时段允许刷卡,这是 PAM。
如果你只学会了 gpasswd 和 chmod,那只是拿到了几把钥匙,还不知道整栋楼的安全策略从哪儿下发。等出问题时,你都不知道该去查 /etc/passwd、/etc/sudoers 还是 /etc/pam.d。
1.2 Ubuntu 的安全体系和 Windows 有什么本质差异
之前有朋友问我:“为什么 Ubuntu 里不能像 Windows 那样直接用管理员账户?”这问题其实没问到点子上。
Windows 的 Administrator 是一个默认存在的超级用户,日常登录的一般是你自己建的管理员组成员,UAC 弹窗只是在模拟提权。Ubuntu 完全不同:安装系统时创建的那个用户虽然是“第一个用户”,但它本质上只是普通用户,只是安装程序顺手把你放到了 sudo 组里。
也就是说,Ubuntu 设计路线是:**root 账户存在但默认不可用,日常用普通身份干活,需要提升再到命令级授权。**这套设计的好处是:就算 Apache 被入侵、运行着恶意 PHP 脚本,它也只是一个 www-data 用户,写不了你的 /home 目录,更动不了系统核心文件。如果一上来就跑 root,那任何漏洞都是“管理员权限被拿下”的灾难级事故。
所以后面我们做的所有练习,都应该围绕“最小权限”这个原则来。你不是在学怎么把一个用户变成万能管理员,而是在学怎么精确地给每个身份发刚刚好够用的权限。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Ubuntu 用户管理的底层:/etc/passwd、/etc/shadow 和 UID 分配
2.1 创建用户时系统到底改了什么文件
很多人用过的第一个建用户命令可能是 adduser 或 useradd,但大多数人不知道它们背后改了哪些文件。如果你不知道,后面排查问题就只能靠猜。
Linux 的用户信息核心在三个文件:
| 文件 | 存放内容 | 权限 |
|---|---|---|
| /etc/passwd | 用户名、UID、GID、家目录、登录 Shell | 所有用户可读 |
| /etc/shadow | 密码哈希、账户过期时间、锁定标记 | 仅 root 可读 |
| /etc/group | 组名、GID、组成员 | 所有用户可读 |
为什么密码哈希单独放在 /etc/shadow?因为历史上 /etc/passwd 是全局可读的,而哈希值一旦被读到,离线爆破只是时间问题。所以现代 Linux 把密码迁移到 root 专属文件里,/etc/passwd 的密码字段只留一个 x。
拿我自己一台服务器上的记录举例,/etc/passwd 里一行大概是:
text复制zhangsan:x:1001:1001::/home/zhangsan:/bin/bash
字段依次是:用户名、密码占位符、UID、主 GID、描述、家目录、登录 Shell。看到 UID 1001 你就该知道,这是个安装系统后手动创建的普通用户。Ubuntu 从 1000 开始分给普通用户,0 是 root,1 到 999 是给系统服务和守护进程的。
2.2 为什么你不会在 /etc/shadow 里看到明文密码
/etc/shadow 里保存的是经过单向哈希算法处理的密码,常用的有 SHA-512、bcrypt、yescrypt。所谓单向,就是只能从密码算出哈希,不能从哈希反推密码。
我见过有人手痒把 /etc/shadow 里的哈希复制出来,放到在线网站想“解密”,最后当然一无所获。正确的思路是:登录时系统把你输入的密码做同样的哈希计算,然后和 shadow 里的值对比,一致则认证成功。
线上环境还要注意,不要把 /etc/shadow 从一个发行版直接复制到另一个发行版。不同系统默认哈希算法可能不同,比如 Ubuntu 22.04 以后逐渐切到 yescrypt,换到旧系统可能会出现所有密码都验证不了的情况。
2.3 用户组不是摆设:主组和附属组的区别
每个用户必有一个主组,写在 /etc/passwd 的 GID 字段。同时可以加入若干附属组,写在 /etc/group 里。
举个例子:
bash复制sudo usermod -aG sudo zhangsan
这里的 sudo 是附属组。用户对某个文件的实际权限,是由“主组权限 + 所有附属组权限合并”决定的。这不是简单的叠加,而是取最大权限集。比如一个用户和另一个用户在同一个组里,即使两人主组不同,也能通过组权限共享文件。
我强烈建议,给用户加组时永远带上 -a 参数。如果漏了 -a,直接执行 usermod -G sudo zhangsan,会把该用户原来的附属组全部替换掉,用户可能瞬间失去 docker 组、dialout 组等之前加的权限,而且这种错误很难第一时间想到。
3. 新建一个用户并让它安全地使用 sudo:从命令到验证
3.1 useradd 和 adduser,到底该用哪个
这是 Linux 新手最常见的选择困难。其实没有谁更高级,只是定位不同。
useradd 是 Linux 原生的底层工具,参数多但不会主动问你密码,也不会顺手帮你创建家目录。很多人用 sudo useradd zhangsan 建完用户,切过去发现连目录都没有,就是因为少了一堆参数。
adduser 是 Perl 脚本写的友好前端,在 Ubuntu 上它会一步步问你要密码、确认信息、自动创建家目录并拷贝 /etc/skel 下的默认配置。
那是不是无脑用 adduser 就好?也不是。批量创建用户、需要在脚本里指定 UID/家目录/Shell 时,useradd 参数化更可控。我是一个习惯:交互式建用户用 adduser,自动化脚本里用 useradd。
如果非要用 useradd 一次建好,推荐这样:
bash复制sudo useradd -m -s /bin/bash -G sudo zhangsan
sudo passwd zhangsan
-m 是创建家目录,-s 指定登录 Shell,-G 加到 sudo 组。没有 -G 的话,这个用户即使建成功也无法执行任何提权命令。
3.2 加入 sudo 组就等于拿到管理员吗
在 Ubuntu 上,把用户加入 sudo 组,确实就让它拥有了完整的管理员提权能力。但这不代表它每次命令都能直接执行,还是需要输入该用户自己的密码,而且输入密码后会有 15 分钟左右的免密窗口(默认 timestamp_timeout)。
有些朋友刚建完用户,立刻让该用户去执行 sudo ls /root,结果报错,然后怀疑自己没加成功。别忘了:新加的组不会对当前已登录会话立刻生效。该用户必须重新登录,或者执行 newgrp sudo 切换组身份,id 命令才会显示新的组。
我自己的验证习惯是三步走:
bash复制sudo adduser zhangsan
sudo usermod -aG sudo zhangsan
su - zhangsan
id
sudo whoami
看到 whoami 输出 root,才算真的走通了。
3.3 服务账户和人工账户别混用
有一类用户永远不会登录系统,比如跑 nginx 的 www-data、跑 MySQL 的 mysql。这些叫系统账户,它们只需要运行服务,不需要交互式 Shell,也没有家目录。
需要新建一个服务账户时,至少这样写:
bash复制sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
重点在 /usr/sbin/nologin。这个 Shell 会调用 PAM 的 account 模块,凡是用该 Shell 的用户都无法交互式登录,但服务进程照样能跑。如果你给服务账户直接配 /bin/bash,万一某天它有提权漏洞被利用,攻击者等于得到一个能登录系统的真实用户,攻击面会大很多。
4. sudo 的权限边界:别一上来就发“ALL=(ALL:ALL) ALL”
4.1 su、sudo、pkexec 三种提权的差异
先问一个问题:当你执行 sudo apt update 时,系统核心动作是什么?
答案是:系统先验证你的密码是否匹配(由 PAM 完成),然后以 root 身份执行后面的命令。这个过程中 root 的密码完全不需要出现,因为你用的是自己的身份。
而 su - 是切换用户。如果执行 su -,系统要求你输入的是目标用户(默认 root)的密码。问题来了,Ubuntu 安装完默认 root 密码是锁定的,直接 su - 是不行的,除非你专门用 sudo passwd root 设一个新密码。
这其实是刻意设计:让你走 sudo,这样每条提权动作都有日志可查,知道是谁在什么时间执行了什么命令。一旦你养成了 su - 切到 root 再操作的坏习惯,日志里只剩一堆 root 操作,出了安全问题根本没法定位责任人。
pkexec 走的是另一个体系(PolicyKit),图形桌面环境下某些系统设置会用到。日常命令行里 sudo 是绝对主流。
4.2 visudo 不是编辑器,而是一道保险
Ubuntu 下直接编辑 /etc/sudoers 是先用 visudo 命令,而不是 vim nano。visudo 会在你保存退出前检查语法,如果语法错误,会阻止保存并提示错误行。
很多教程让新手直接改 /etc/sudoers,我是不赞成的。Ubuntu 默认就配置了 /etc/sudoers.d/ 目录,建议自定义内容都放这个目录下单独文件,例如:
bash复制sudo visudo -f /etc/sudoers.d/my-custom
修改 /etc/sudoers 本身风险高,因为它是核心权限文件;而 sudoers.d 下的文件只要权限保持 0440,系统一样会读。好处是拆散成独立文件,出问题可以只删或改名某一个,不会动全局。
4.3 “sudo 不需要密码”的正确打开方式
每次搜怎么免 sudo 密码,网上回复几乎都是 NOPASSWD。但很多回答没提醒:如果你写了 zhangsan ALL=(ALL) NOPASSWD: ALL,那这台机器对这个用户来说,root 等于不设防。一旦用户账号被攻破,连二次认证都省了。
更合理的做法是只对固定命令做免密。举个例子,你有个自动化脚本每天要用 systemctl 重启某个服务,希望不需要交互:
bash复制zhangsan ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp
写成这样,用户只对 restart myapp 这个动作免密,其他 systemctl 子命令照样要密码。尽量把命令写到绝对路径,防止恶意脚本通过 PATH 劫持同名命令。
NOPASSWD 用户仍然输入 sudo 时不会提示密码。如果你配置完发现还是要密码,八成是文件里的用户或主机名段写错了。Ubuntu 默认主机名写的是 ALL,不要自作主张改成你的主机名;语法里第一段“允许的来源主机”,几乎总是 ALL。
4.4 sudo 后找不到命令的原因不是权限,是 PATH
遇到过这样的问题:普通用户在终端能执行 flutter 或某个自定义脚本,一加 sudo 就报 command not found。
原因是 sudo 默认会用 secure_path 重置环境变量,它不会继承你当前用户的 PATH。Ubuntu 默认 secure_path 里只有 /usr/local/sbin、/usr/local/bin、/usr/sbin、/usr/bin、/sbin、/bin 这些标准目录。你装在 /opt 下或用户目录下的可执行文件,sudo 后自然找不到。
三个解决办法:
- 执行命令时写绝对路径,如
sudo /opt/flutter/bin/flutter ... - 在 /etc/sudoers.d/local 中追加该目录到 secure_path
- 重要命令建议做软链接到 /usr/local/bin
我个人不推荐把用户自定义目录一股脑塞进 secure_path,污染面太大,增加被植入同名可执行文件的风险。能用绝对路径就先用绝对路径。
4.5 把 sudoers 改坏了怎么办
最常见的翻车现场:你把自己唯一的管理员用户从 sudoers 里删了,或者 sudoers 语法写错导致所有 sudo 都不可用,而系统当前只有一个普通用户,且该用户没有其他通道提权。
别慌,按情况处理:
- 如果机器还有另一个 sudo 用户,登录它执行
sudo visudo恢复。 - 如果是有图形界面的桌面版,可以尝试
pkexec visudo,会弹出类似 GUI 的授权框。 - 如果都没有,那就只能重启机器,在 GRUB 菜单进入 recovery mode,选 root shell,然后手动把错误文件改回来。
也正因为如此,我每次修改核心配置文件前,都会先备份:
bash复制sudo cp /etc/sudoers /root/sudoers.bak.$(date +%F)
sudo visudo -c
visudo -c 可以在不进入编辑器的情况下直接检查语法,写配置前检查一把,能避免很多低级错误。
5. PAM:sudo、登录、密码策略背后那层你看不见的安检系统
5.1 PAM 不是一个程序,而是一套“认证插槽”
很多教程最后才讲 PAM,但实际你从第一次 Ubuntu 登录开始,PAM 就已经在为你工作了。
PAM 全称 Pluggable Authentication Modules,可插拔认证模块。它不是某个具体软件,而是一个框架。像 sshd、sudo、login、su 这些要验证身份的程序,都约定好在执行认证时去调用 PAM 配置里的模块。这样密码策略、失败锁定、双因素认证这些功能就不需要每个程序自己重复实现了。
在 Ubuntu 的 /etc/pam.d/ 目录下,每一个需要认证的服务都对应一个配置文件。比如:
text复制/etc/pam.d/login
/etc/pam.d/sshd
/etc/pam.d/sudo
/etc/pam.d/common-auth
/etc/pam.d/common-password
/etc/pam.d/common-account
/etc/pam.d/common-session
很多服务文件里是 include 公共配置。例如打开 /etc/pam.d/sshd,会看到它 include common-auth。意思是,sshd 的认证流程和 login 的认证流程共享同一套 auth 规则。所以你在 common-auth 里加了一条“失败五次锁定账户”,那么 ssh 和 sudo 都会受影响。
5.2 四种 PAM 模块组,分别控制什么
PAM 的每个配置行由四列组成:模块类型、控制标记、模块路径、参数。
模块类型有四种:
| 类型 | 作用 | 实际场景 |
|---|---|---|
| auth | 验证用户身份 | 核对密码、二次验证 |
| account | 检查账户是否可用 | 是否过期、是否限制登录地点 |
| password | 更新密码 | 修改密码时的复杂度检查 |
| session | 会话建立后的附加动作 | 记录日志、设置资源限制 |
控制标记也很重要。常见的是 requisite、required、sufficient、optional。它们的区别是:requisite 失败后直接拒绝且不再执行后续模块;required 失败最终会拒绝,但可能继续执行完后续模块;sufficient 成功且前面没有 required 失败时,不再执行后续模块。
正常我们不会去手动改默认 PAM 配置,因为一旦顺序或控制标记写错,可能导致所有用户无法登录。但理解这些字段能帮你读懂系统日志,知道某次登录为什么被拒。
5.3 一个实际调优:修改密码复杂度和过期策略
Ubuntu 在密码修改界面调用的是 common-password 文件。新版本默认会加载 pam_pwquality.so,我可以给出一个生产上常用的强度要求:
bash复制sudo cp /etc/pam.d/common-password /etc/pam.d/common-password.bak
sudo nano /etc/pam.d/common-password
找到包含 pam_pwquality.so 的行,加上这串参数:
text复制password requisite pam_pwquality.so retry=3 minlen=12 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 reject_username
参数含义:允许重试 3 次,最小长度 12,新密码至少比旧密码多 3 处不同,必须包含至少一个大写字母、一个小写字母和一个数字,拒绝和用户名相同的密码。
改完记得换另一个终端测试一下新密码能否正常设置。我能提醒的就是,密码策略别一下子定太狠。之前有人直接把 minlen 设成 20,还要大小写数字特殊字符全来一遍,结果普通用户自己改密码时怎么都改不出来,最后只能 root 帮他们重置。
5.4 暴力破解防护:faillock 和 pam_tally2
以前老系统多用 pam_tally2 做失败锁定,Ubuntu 22.04 之后新装系统更推荐 faillock。两者模块名不同,别搞混。
faillock 的配置路径有两个选择:直接改 /etc/security/faillock.conf 或者放到 /etc/pam.d/common-auth 里。
常见需求:密码连续错 5 次,锁账户 15 分钟。在 /etc/pam.d/common-auth 的 auth 部分最前面插入:
text复制auth required pam_faillock.so preauth audit deny=5 unlock_time=900
auth sufficient pam_unix.so
auth required pam_faillock.so authfail audit deny=5 unlock_time=900
注意这里所谓“锁账户”并不是真的把用户删掉或设为锁定状态,而是在 PAM 认证层加了门槛。被锁的用户确实无法通过正常途径登录,但 root 永远可以绕过 PAM 限制直接操作。
解锁命令:
bash复制sudo faillock --user zhangsan --reset
查看当前所有失败记录:
bash复制sudo faillock
在配置失败锁定前,你要想清楚一个问题:这个策略也会作用于合法用户。如果运维人员自己在服务器上连续输错密码,也会被锁在外面。所以线上机器必须有 root 或者带外管理口备用通道,否则一次性锁了所有用户,就只能物理重启进恢复模式了。
5.5 PAM 能限制登录时间,也能限制进程数
除了认证,PAM 还能通过 pam_limits.so 读取 /etc/security/limits.conf,控制用户最大进程数、打开文件数、内存占用。
不过这是用户态限制,不是内核级 cgroup,很多容器环境里单独调这个文件作用有限。对新手而言,知道 /etc/security/limits.conf 由 PAM session 模块加载就够了。
举个例子,限制 zhangsan 用户最大可以打开 4096 个文件:
text复制zhangsan hard nofile 4096
改完后需要重新登录会话生效。如果哪天普通用户在跑高并发程序时报“Too many open files”,除了去调 ulimit,也要想起这个文件,因为它才是会话开始时的默认底子。
6. 高频排错:那些你在真实环境中必踩的坑
6.1 sudo dpkg --configure -a 卡死,第一步不该是杀进程
网上经常看到有人命令执行不下去了,回复里来一句:执行 sudo dpkg --configure -a。结果这条命令本身也会卡死,很多人就懵了。
dpkg --configure -a 的作用是配置所有未配置完的软件包。之所以卡死,最常见的原因不是权限,而是有另一个 apt 或 dpkg 进程还在运行,系统锁还没释放。另一个常见场景是源地址网络超时,apt 在等待连接,表面看起来就是卡死。
正确排查链路是这样:
bash复制ps aux | grep -E 'apt|dpkg'
如果看到类似 apt-get update 的进程还在跑,那就等它结束。如果确实没有任何 apt/dpkg 进程,但锁文件还存在,先不要手滑删掉 /var/lib/dpkg/lock。确认无进程后可以先检查锁:
bash复制sudo lsof /var/lib/dpkg/lock
没有进程持有锁时再考虑移走锁文件。很多小白一看到 lock 就 rm,结果把正在运行的 dpkg 的记账状态一起搞没,系统包管理直接分裂,下一步更麻烦。
如果只是 apt update 卡住,大概率是网络源慢。我会先用 sudo apt update -o Acquire::http::Timeout=5 测试超时时间,再决定是否换镜像源,而不是一直等。
6.2 自己想配“sudo 免密”,配完却报错 user not in sudoers
有朋友为了省事,期望执行 sudo 不用密码,结果把用户从其他组搞丢,或者直接用错误语法改了 sudoers,最后连 sudo 都用不了,提示“zhangsan is not in the sudoers file. This incident will be reported.”
这个提示不是说密码错了,而是说 PAM 认证通过了,但 sudo 的授权阶段没找到该用户的任何规则。根因通常是:
- 用户确实不在 sudo 组
- sudoers.d 里自定义文件权限不是 0440
- 加入了 sudo 组但当前会话还没刷新
检查时先看 id:
bash复制id zhangsan
如果显示有 sudo 组,让该用户重开一个终端再试;如果没显示,用 root 或其他 sudo 用户把它加回去。加回来之后不会立即可见,得重新 login。对于已经登录的用户,执行 newgrp sudo 能临时刷新组,但我更倾向于直接 exit 再登录。
6.3 只想让 wheel 组的用户可以 SSH 登录
这是一个很经典的需求:修改 /etc/ssh/sshd_config 里的 AllowGroups。
先明确一点:Ubuntu 默认没有 wheel 组,系统用的是 root/sudo 这套分组。如果你想按 RHEL 的习惯只允许 wheel 组 SSH 登录,需要自己建组并加人:
bash复制sudo groupadd wheel
sudo usermod -aG wheel zhangsan
然后编辑 /etc/ssh/sshd_config,加上:
text复制AllowGroups wheel
如果你想更彻底,同时禁止 root 直接 SSH 登录,再加一行:
text复制PermitRootLogin no
每次改完 sshd_config 都要先测语法,再重启:
bash复制sudo sshd -t
sudo systemctl restart sshd
必须强调:不要开一个新的 SSH 连接,应该在当前会话保持不断的情况下测完语法再重启。万一语法或权限配置有误,你当前会话还没断开,还能救回来;要是当前会话先断了,新规则又不对,那就只能去机器前解决了。
有人问“设置了只有 wheel 能登录,为什么还是能登录普通用户”?这其实是误解:AllowGroups 的限制是组成员,不是用户名单。如果你把 zhangsan 加进了 wheel,它自然能被允许。如果你希望排除所有不在 wheel 的用户,那 AllowGroups 本身已经做到了,不要在服务器上留一个什么组都没加的测试账号。
6.4 虚拟机里的 U 盘权限,和“权限”没关系
如果你在虚拟机 Ubuntu 里插 U 盘,提示没有权限读写,很多人第一反应是 sudo chmod 777。
其实这种情况多数是因为当前用户不在 dialout、vboxusers 或 libvirt 组里,系统不允许设备节点被普通用户直接访问。正确操作是看你的虚拟机平台,把自己加到对应组,然后重新登录:
bash复制sudo usermod -aG vboxusers $USER
sudo usermod -aG dialout $USER
退出当前会话再重新登录,组权限生效后,U 盘、串口设备一般就能直接打开。这里有一个很多人忽略的经验:修改组后不是立刻生效的。就算新开了一个终端,如果那个终端继承的父进程还是旧会话,组信息依然是旧的。最稳妥的办法是完全注销再登录,或者重启虚拟机。
6.5 运行安装器报 Exception in thread,未必是 sudo 的问题
像 sudo ./xsetup 这类图形安装包报 Exception in thread "splash_load_message",说明程序启动阶段就崩了,和权限基本无关。常见原因是软件包自带的某个运行时组件和系统 GLIBC、图形库不匹配。
面对这种错误,不要反复加 sudo 重试。我的一般处理方式是:
- 先不带 sudo 跑一遍,确认是否所有用户都报同样的错
- 用
ldd看二进制依赖哪个版本的动态库,检查是否缺失 - 打开软件日志目录,看完整堆栈,不是只看终端输出
- 如果是安装包自带的 JDK 或运行时,优先尝试安装官方要求的系统依赖
sudo 的作用是提升权限,不是修复路径、依赖、库缺失。把 sudo 当成“开挂指令”是所有新手最容易走偏的地方。
7. 课后自测与一组可直接落地的安全基线
7.1 这五道题能帮你验证自己是否真的理解了
我不喜欢出那种死记命令的题,下面是几个我得过教训后总结的思考题,每个都能延伸出一个很长的排查故事:
- Ubuntu 安装完成后,root 用户默认能不能用密码登录系统?如果要让 root 可以 su 登录,应该做什么,风险在哪?
- 新建的用户加入 sudo 组后,为什么刚开的终端里执行 sudo 还是可能提示没有权限?
- sudoers 里 NOPASSWD 配了为什么仍然要密码?规则顺序对结果有没有影响?
- 连续错输密码 5 次后用户被锁,root 去解锁应该用什么命令?faillock 和 pam_tally2 有什么区别?
- SSH 配置文件里 AllowGroups 设置成 wheel,不在 wheel 组的 root 还能登录吗?如果想禁止 root 远程登录,要加哪条配置?
如果你能不看文档说出每个问题的处理步骤和原因,这章的核心就算过关了。
7.2 我的个人服务器最小权限配置参考
无论给客户做项目还是自己玩,只要服务器能 SSH 登录,我至少会做以下基线调整:
- 禁止 root 直接登录,所有管理动作通过有 sudo 权限的管理员用户执行
- 新建管理员时不直接无脑把整个 sudo 组给它,而是通过 /etc/sudoers.d/ 单独授权命令范围
- 安全相关的核心命令(用户管理、sudoers 修改、PAM 配置)只允许个别用户执行
- 开启 faillock,登录失败 5 次锁定 15 分钟
- 修改 common-password 密码复杂度,并测试普通用户可以正常改密
- 每次改动前备份文件,改完用
visudo -c或sshd -t做语法检查
下面是一份很常用的 sudoers.d 规则片段,适合自动化部署场景:
text复制Defaults env_reset, timestamp_timeout=10
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl status myapp
ops ALL=(ALL:ALL) ALL
上面这个例子里,deploy 用户只能重启和查看 myapp 服务,ops 用户是普通管理员,拥有完整提权但需要密码。对于只跑固定服务的机器,我不建议把所有运维人员都放进 sudo 组,因为权限太大,审计时也分不清谁是谁。
7.3 最后的经验之谈
这一章内容系统,但真正能沉淀下来的往往不是命令,而是你出问题时的排查顺序。我见过太多人排错时第一反应就往 PAM、sudo 上猜,可实际只是一条命令路径写错了。
结合我这几年踩坑的经验,权限问题要按“数据流向”去看:先确认用户身份对不对,再确认授权规则是否存在,最后才去怀疑 PAM 或系统级限制。顺序反了,你会在 PAM 日志里折腾半天,结果发现只是用户没加入正确的组。
配置安全策略时也记住一个原则:能只给一条命令的权限,就不要给整个 Shell;能锁 15 分钟,就不要锁 10 秒。权限体系在大多数时候不是用来防内部恶意员工,而是为了在出事之后让日志能讲清楚整个故事。一个没有日志、没有边界、所有用户都运行在 root 权限下的系统,出问题只是时间问题。
