物理主机服务文件系统沙箱:限制写入并验证拒绝边界

物理主机服务文件系统沙箱:限制写入并验证拒绝边界

同一台物理主机承载多个后台服务时,程序通常只需要写入状态目录,却可能因目录属主配置过宽而改动发布文件。单独建立服务账户只能划出第一层边界;再把服务所见的文件系统设为只读、仅保留必要写入路径,才能减少误写范围。验收不能停在“服务启动成功”,还要证明不该写的位置确实写不进去。

一、先列写入清单,再设置沙箱

本文以 Ubuntu Server 24.04 LTS 为例,使用 systemd 管理系统级服务。操作需要管理员权限和 Python 3,所有路径均为独立实验目录,不修改现有业务单元。AmdMetal 物理主机的登录凭据在付款后到控制台查看,Linux 使用 SSH 接入。

先区分程序代码、持久状态、运行时文件与临时文件。代码应由部署账户更新,服务账户只读;状态目录存放必须跨重启保存的数据;套接字、进程标识等运行时文件与临时文件应另行登记。日志若写入标准输出,可交给日志系统接收,不必再开放整片日志目录。

核心配置是 ProtectSystem=strict:在服务的挂载命名空间中,将文件系统层级设为只读,部分 API 文件系统等有例外。ReadWritePaths 再为指定目录保留写入能力。它不改变宿主机全局挂载状态,也不是完整的进程隔离方案。

只读限制不等于保密。可读文件不会因此自动隐藏,网络访问也不会自动受限;写入白名单同样不能代替目录权限。

二、建立可区分原因的权限基线

实验准备两个目录:一个应允许写入,另一个普通权限允许写入、但应被沙箱拦截。这样才能排除“本来就没有权限”的假阳性。以下账户名与路径应先确认未被现有服务使用;它们是实验对象,不是机器默认登录账户。

sudo useradd --system --no-create-home \
  --shell /usr/sbin/nologin sandbox-check

sudo install -d -o root -g root -m 0755 \
  /srv/sandbox-check

sudo install -d -o sandbox-check -g sandbox-check -m 0750 \
  /srv/sandbox-check/blocked \
  /var/lib/sandbox-check

sudo runuser -u sandbox-check -- /usr/bin/python3 -c \
'import tempfile, os; f, p = tempfile.mkstemp(dir="/srv/sandbox-check/blocked"); os.close(f); os.unlink(p)'

最后一条命令应成功退出:它在候选禁止目录内创建随机临时文件,并立即删除。若失败,应先检查目录遍历权限、ACL 与底层挂载属性,不能继续把后续失败归因于沙箱。

部署脚本自身由管理员持有,避免服务账户改写检查逻辑。实验目录刻意采用可写属主,仅用于证明限制来源;正式应用的代码目录应坚持服务账户不可写,不能照搬这个实验例外。

三、配置写入白名单与独立探针

将下面脚本保存为 /srv/sandbox-check/probe.py,属主设为管理员,权限设为 0644。允许路径必须成功写入;禁止路径必须返回只读文件系统错误,其他错误一律视为验收失败。

import errno
import os
import tempfile

def create_and_remove(directory):
    fd, path = tempfile.mkstemp(prefix="probe-", dir=directory)
    try:
        with os.fdopen(fd, "w") as stream:
            stream.write("sandbox-check\n")
            stream.flush()
            os.fsync(stream.fileno())
    finally:
        os.unlink(path)

create_and_remove("/var/lib/sandbox-check")

try:
    create_and_remove("/srv/sandbox-check/blocked")
except OSError as exc:
    if exc.errno != errno.EROFS:
        raise
else:
    raise RuntimeError("Write boundary was not enforced")

print("Allowed write passed; blocked write returned EROFS")

这里使用随机文件名,避免覆盖已有数据;fsync 用于检查写入调用链,不代表完成了性能或断电持久性测试。探针输出是验收结果,不包含凭据或业务内容。

创建 /etc/systemd/system/sandbox-check.service:

[Unit]
Description=Filesystem sandbox verification

[Service]
Type=oneshot
User=sandbox-check
Group=sandbox-check
ExecStart=/usr/bin/python3 /srv/sandbox-check/probe.py
ProtectSystem=strict
ReadWritePaths=/var/lib/sandbox-check
PrivateTmp=true
NoNewPrivileges=true

PrivateTmp=true 给服务提供隔离的临时目录视图,因此不能把“只允许一个持久目录写入”理解为“整个进程只有一个可写位置”。NoNewPrivileges=true 限制通过执行程序获得新增特权,但不会撤销已经授予的文件访问权限。

四、同时验收成功与拒绝

先校验单元,再加载并执行:

sudo systemd-analyze verify /etc/systemd/system/sandbox-check.service
sudo systemctl daemon-reload
sudo systemctl start sandbox-check.service

sudo systemctl show sandbox-check.service \
  -p Result -p ExecMainStatus -p ProtectSystem -p ReadWritePaths

sudo journalctl -u sandbox-check.service -b --no-pager -n 30

期望结果为 Result=success、ExecMainStatus=0,日志中出现探针通过信息。单次执行服务结束后显示非运行状态并不异常;这里没有配置持续运行或保留活动状态。

仅查看配置值不足以证明边界有效。有效证据应同时包括:沙箱外同账户写入成功、沙箱内允许目录写入成功、禁止目录写入返回 EROFS。若得到 EACCES,只能证明普通权限或其他安全策略拒绝访问,不能算通过本项验收。

正式服务还要测试真实业务路径

探针通过后,再为实际服务编写独立的加固配置。执行一次覆盖上传、缓存生成、状态保存与临时文件清理的业务测试。应用若通过“临时文件加重命名”更新数据,目标目录本身也必须可写;只给单个文件开例外往往不足。

同时检查符号链接的真实落点。配置中看似位于状态目录内的链接,可能最终指向另一处只读路径,不能通过扩大整个父目录的权限来掩盖问题。

五、排错、撤销与验收记录

服务启动前失败时,先读日志确认是否无法建立挂载命名空间、路径不存在,或配置拼写错误。启动后失败时,再按文件操作位置判断:程序是否偷偷向代码目录写缓存,是否依赖共享临时文件,是否需要额外运行时目录。

正式服务若需要运行时目录,可使用 RuntimeDirectory 让 systemd 管理其生命周期,再测试实际访问。不要直接把 /var、/srv 全部加入白名单;应按已确认的写入需求逐项放行。

配置变更后,daemon-reload 只重新加载单元定义,不会把新沙箱套到已经运行的进程上。正式服务必须通过受控重启创建新的进程环境,并重新执行正向与反向测试。

撤销实验时,停止单元、删除本次创建的单元文件,再重新加载定义。实验数据目录与账户应在确认没有进程使用后单独清理,不执行递归删除业务目录的通用命令。正式服务则恢复变更前留存的配置,并重启验证。

最终记录单元有效配置、服务账户、允许写入清单、探针退出状态与实际业务测试结果。验收目标不是安全评分更高,而是每一项必要写入均成功,每一项预期禁止写入都有可解释、可重复的拒绝证据。

常见问题

ReadWritePaths 能让服务写入原本没有权限的目录吗?

不能。它只在只读文件系统沙箱中保留可写路径,不改变目录属主、模式位或 ACL;服务账户必须同时具备普通文件权限。

ProtectSystem=strict 能阻止服务读取密钥吗?

不能。它主要限制写入,不会自动隐藏可读文件,也不限制网络访问。敏感文件仍需设置独立权限,并根据需求另外配置路径隐藏与网络边界。

AMD EPYC 7543P 独享物理主机

$458.7/月起

配置 AmdMetal 物理主机 查阅 AmdMetal 租用价格

物理主机配置逐项确认

AMD EPYC 7543P 整机独享,机型与选配在配置页统一核算。