一台暴露在公网上的 Ubuntu 服务器,从上线的那一刻起,就已经被全球范围的扫描器盯上了。密码爆破、漏洞探测、端口扫描几乎每时每刻都在发生。前面我们讲过了防火墙、SSH 加固、数据备份,今天这一篇把安全话题再往上推一层:如何用 AppArmor 做进程级强制访问控制、如何落实一套可复用的安全基线,以及如何部署入侵检测体系,让异常行为第一时间被发现。

一、为什么需要 AppArmor
传统 Linux 权限模型(UGO + root)遵循的是「自主访问控制」(DAC),即资源所有者可以自行决定谁能访问。这种模型的致命缺陷在于:一旦某个进程以 root 身份运行,它就拥有了几乎无限的能力,任何被攻破的服务都可能反过来控制整台机器。
AppArmor 是 Ubuntu 默认启用的「强制访问控制」(MAC)机制,它通过给每个程序绑定一个安全配置文件(profile),限制进程能访问的文件、目录、网络和系统调用。即使程序本身存在漏洞被利用,攻击者也只能在 profile 允许的范围内活动,无法为所欲为。
查看 AppArmor 运行状态
# 查看 AppArmor 是否加载
sudo aa-status
# 查看当前处于 enforce 模式的 profile 数量
sudo aa-status | grep -A2 "profiles are in enforce mode"
aa-status 的输出会列出哪些 profile 处于 enforce(强制)模式、哪些处于 complain(仅告警不拦截)模式。生产环境应尽量让关键服务处于 enforce 模式。
二、实战:为自定义服务编写 AppArmor Profile
假设我们要为一台运行在 /opt/myapp/ 下的 Node.js 服务做隔离,这个服务只需要读取自己的目录、写日志,并通过 8080 端口对外提供服务。
1. 生成基础 profile
# 安装 AppArmor 工具集
sudo apt update && sudo apt install -y apparmor-utils
# 用 aa-genprof 启动学习模式,自动生成 profile
sudo aa-genprof /usr/bin/node
aa-genprof 会先让程序进入 complain 模式运行,你正常操作一遍业务,工具会记录所有访问路径,随后交互式地把它们写入 profile。
2. 手写一个最小 profile
对于结构清晰的服务,直接手写更可控。创建 /etc/apparmor.d/opt.myapp.node:
#include <tunables/global>
/opt/myapp/node {
#include <abstractions/base>
#include <abstractions/nameservice>
/opt/myapp/** r,
/opt/myapp/** rw,
/var/log/myapp/** rw,
/tmp/** rw,
network inet stream,
network inet6 stream,
deny /etc/shadow r,
deny /root/** rw,
}
关键点说明:
r表示只读,rw表示可读写,**匹配任意深度的子路径。network inet stream允许 IPv4 的 TCP 连接,缺少这行服务就监听不了端口。deny规则可以显式封死敏感路径,即使前面的通配规则误放了权限,deny 的优先级也更高。
3. 加载并切换为 enforce 模式
# 加载 profile 到内核
sudo apparmor_parser -r /etc/apparmor.d/opt.myapp.node
# 切到 enforce 模式
sudo aa-enforce /opt/myapp/node
# 验证
sudo aa-status | grep myapp
如果服务在 enforce 模式下启动失败,先 sudo aa-complain /opt/myapp/node 切回告警模式,再查看 /var/log/syslog 中的 apparmor="DENIED" 日志逐条补白名单。
三、落地安全基线
安全加固不能靠「想起来一条做一条」,而要沉淀成可检查、可复用的基线清单。下面这套基线适用于绝大多数 Ubuntu 生产主机。
1. 账户与认证基线
# 锁定不必要的系统账号
sudo passwd -l bin
sudo passwd -l daemon
# 强制 root 只能通过 sudo,禁止直接登录
sudo passwd -l root
# 设置密码复杂度与过期策略(编辑 /etc/login.defs)
sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs
sudo sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' /etc/login.defs
sudo sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE 14/' /etc/login.defs
2. 内核参数加固(/etc/sysctl.conf)
# 开启 SYN Cookie 防御洪水攻击
net.ipv4.tcp_syncookies = 1
# 忽略 ICMP 重定向,防止路由被劫持
net.ipv4.conf.all.accept_redirects = 0
# 关闭 IP 源路由
net.ipv4.conf.all.accept_source_route = 0
# 记录可疑的 Martian 包
net.ipv4.conf.all.log_martians = 1
写入后执行 sudo sysctl -p 使其生效。这些参数能显著降低网络层攻击面。
3. 文件系统加固
# 给关键目录加不可变属性(需先 umount 写入需求)
sudo chattr +i /etc/passwd /etc/shadow /etc/group /etc/gshadow 2>/dev/null || true
# 卸载不用的内核模块
echo "blacklist usb-storage" | sudo tee /etc/modprobe.d/blacklist-usb.conf
四、部署入侵检测:AIDE + auditd
防火墙和 AppArmor 负责「挡在门外」,入侵检测系统(IDS)负责「门被撬开后及时发现」。
1. AIDE 文件完整性检测
AIDE 会为关键文件生成指纹,一旦文件被篡改(比如被植入后门),校验时就会报警。
# 安装并初始化
sudo apt install -y aide
sudo aideinit -y -f
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# 生成每日检查脚本
cat <<'EOF' | sudo tee /etc/cron.daily/aide-check
#!/bin/bash
/usr/bin/aide.wrapper --check
EOF
sudo chmod +x /etc/cron.daily/aide-check
2. auditd 审计关键事件
sudo apt install -y auditd
# 监控 passwd 和 shadow 的访问与修改
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo auditctl -w /etc/shadow -p wa -k shadow_changes
# 查看审计日志
sudo ausearch -k passwd_changes
建议把审计规则固化到 /etc/audit/rules.d/audit.rules,避免重启丢失。
五、常见问题
Q1:开了 AppArmor 后服务起不来,日志里全是 DENIED,怎么办?
先 aa-complain 切回告警模式恢复业务,然后 grep DENIED /var/log/syslog 逐条分析,把合理的访问路径加进 profile 的 allow 规则,确认无误后再 aa-enforce 切回。不要为了图省事直接删除 profile 或 aa-disable,那等于放弃了这层防护。
Q2:AIDE 每天报警,怎么区分正常变更和入侵?
正常升级(apt upgrade)会修改二进制文件,触发 AIDE 报警。做法是每次系统或软件升级后重新生成基准库 aideinit,让基线跟上合法变更,这样后续的报警才真正值得排查。
Q3:安全基线多久复查一次?
建议把基线做成脚本或引入配置管理(如 Ansible),每次新增主机自动应用;对已上线主机每月跑一次检查脚本,输出偏离项并修复。
六、总结
今天我们从「进程级权限」切入,学习了 AppArmor 的 profile 编写与 enforce/complain 双模式切换;然后落地了一套覆盖账户、内核参数、文件系统的安全基线;最后用 AIDE 和 auditd 补齐了入侵检测能力。安全从来不是某个单点工具,而是「边界防护 + 最小权限 + 持续检测」的体系。到这里,单机安全的核心拼图已经齐了。
下期预告:第 24 天我们将进入《内核与系统调优》,用 sysctl 深度优化 CPU、内存与 IO 参数,让这台已经加固好的 Ubuntu 跑得更快更稳,敬请期待。















暂无评论内容