Linux 服务器 /tmp 目录:使用机制与安全加固

Linux 服务器 /tmp 目录:使用机制与安全加固

本文基于 Kylin V10 SP3 / RHEL 8 系列系统实践整理,适用于云服务器和 Kubernetes 节点场景。

1. /tmp 的两种存储后端

很多人以为 /tmp 就是磁盘上的一个目录,但实际上它可能运行在两种完全不同的存储后端上。

基于磁盘(默认目录)

如果 /tmp 没有被单独挂载,它就是根文件系统 / 下的一个普通目录,数据存储在磁盘上,不占用内存。

基于内存(tmpfs)

如果 /tmp 被挂载为 tmpfs,它使用物理内存(RAM 不足时会使用 swap)。tmpfs 默认最大可使用 50% 的系统内存,但它是按需分配的------如果 /tmp 里只有 10MB 文件,就只占用 10MB 内存。

用以下命令确认你的系统使用的是哪种方式:

bash 复制代码
df -hT /tmp
findmnt /tmp

如果输出中 FSTYPEtmpfs,说明是内存模式;如果和根分区一样(如 xfsext4),说明是磁盘模式。

2. systemd 的隐式挂载行为

在 RHEL 8 / Kylin V10 系统上,即使 /etc/fstab 中没有 /tmp 的条目,systemd 也可能自动将 /tmp 挂载为 tmpfs。这是通过 tmp.mount 单元实现的。

bash 复制代码
systemctl status tmp.mount

你可能会看到类似如下输出:

复制代码
● tmp.mount - Temporary Directory (/tmp)
   Loaded: loaded (/usr/lib/systemd/system/tmp.mount; disabled; vendor preset: disabled)
   Active: active (mounted)

注意 disabledactive------说明这个单元没有被显式启用,但 systemd 的默认配置仍然触发了挂载。这种"隐式行为"很容易被忽视。

3. 对 Kubernetes 节点的影响

在 K8s 节点上,如果 /tmp 使用 tmpfs 且没有设置大小限制,需要特别注意:

  • 内存竞争 :kubelet、系统服务和 Pod 都在争用内存。如果某个进程向 /tmp 写入大量临时文件,会直接挤占可用内存,可能触发 OOM Killer。
  • 容器隔离 :好消息是,容器内部有自己独立的 /tmp,不会使用宿主机的 /tmp。但宿主机上的系统进程仍然会使用它。

建议方案:

  • 如果内存充足,保留 tmpfs 但设置大小限制(如 size=512M
  • 如果内存紧张,改为磁盘模式,避免 /tmp 与 Pod 争用内存

4. CIS 安全加固要求

CIS Benchmark(国际互联网安全中心基准)是业界广泛认可的安全加固标准,其中对 /tmp 的要求主要涉及三个挂载选项:

选项 作用
noexec 禁止执行 /tmp 中的任何程序或脚本
nosuid 忽略 /tmp 中文件的 SUID/SGID 位
nodev 禁止在 /tmp 中创建设备文件

为什么需要 noexec?

/tmp 是所有用户都可以写入的目录(权限为 1777)。攻击者常见的手法是:将恶意可执行文件上传到 /tmp,然后执行它。noexec 在内核层面阻止了这种行为。

noexec 和 chmod 去掉 x 权限是一回事吗?

不是。这是两个完全不同层面的机制:

  • chmod -x /tmp(目录权限) :去掉目录的 x 权限意味着用户无法"进入"该目录(无法 cd /tmp),这会导致系统大面积故障,绝对不能这么做。
  • noexec(挂载选项) :在内核层面禁止执行该挂载点上的任何文件。文件的读写不受影响,只是不能作为程序运行。即使文件本身有 chmod +x 的执行权限,内核也会拒绝执行。
bash 复制代码
# noexec 效果演示
cp /usr/bin/ls /tmp/ls
chmod +x /tmp/ls
/tmp/ls
# 结果:Permission denied(内核拒绝执行)

5. 加固操作步骤

检查当前状态

bash 复制代码
# 查看 /tmp 挂载信息
findmnt /tmp

# 查看当前挂载选项
mount | grep /tmp

方案一:保留 tmpfs + 安全选项 + 大小限制

/etc/fstab 中添加:

复制代码
tmpfs   /tmp   tmpfs   defaults,noexec,nosuid,nodev,size=512M   0 0

立即生效(无需重启):

bash 复制代码
mount -o remount,noexec,nosuid,nodev /tmp

方案二:磁盘模式 --- 独立分区(推荐)

如果选择将 /tmp 放在磁盘上,强烈建议使用独立分区而不是让它留在根文件系统中。

原因很简单:/tmp 是所有用户可写的目录,如果没有隔离,任何用户或失控进程都可以向 /tmp 写入大量数据,直到撑满整个根分区。根分区一旦满了,后果很严重------系统日志无法写入、服务无法启动、甚至无法通过 SSH 登录。这在生产环境中是非常危险的故障模式。

独立分区的好处:

  • 空间隔离/tmp 写满只影响 /tmp 自身,不会波及根分区和其他关键目录(如 /var/log/etc
  • 容量可控 :分区大小在创建时确定,天然限制了 /tmp 的最大占用
  • 安全挂载选项 :独立分区可以直接在 /etc/fstab 中设置 noexec,nosuid,nodev

操作步骤:

如果是新装系统,在安装时规划分区,为 /tmp 分配 1-2GB 的独立分区即可。

如果是已有系统,可以使用 LVM 创建新的逻辑卷(前提是 VG 中有剩余空间):

bash 复制代码
# 1. 禁用 systemd 的 tmpfs 挂载
systemctl disable tmp.mount
systemctl mask tmp.mount

# 2. 创建逻辑卷(假设 VG 名为 klas,分配 2GB)
lvcreate -L 2G -n tmp klas

# 3. 格式化
mkfs.xfs /dev/klas/tmp

# 4. 添加到 /etc/fstab
echo '/dev/mapper/klas-tmp   /tmp   xfs   defaults,noexec,nosuid,nodev   0 0' >> /etc/fstab

# 5. 备份当前 /tmp 内容,挂载新分区
cp -a /tmp /tmp.bak
mount /tmp
chmod 1777 /tmp
cp -a /tmp.bak/* /tmp/ 2>/dev/null; rm -rf /tmp.bak

方案三:磁盘模式 --- bind mount(无法划分独立分区时的替代方案)

如果系统已经部署完毕且 VG 没有剩余空间,无法创建独立分区,可以退而求其次使用 bind mount。这种方式可以添加安全挂载选项,但无法实现空间隔离 ------/tmp 仍然和根分区共享磁盘空间。

bash 复制代码
# 禁用 systemd 的 tmpfs 挂载
systemctl disable tmp.mount
systemctl mask tmp.mount

/etc/fstab 中添加:

复制代码
/tmp   /tmp   none   bind,noexec,nosuid,nodev   0 0

使用 bind mount 时,建议配合 磁盘配额(quota) 或定期清理计划任务来防止 /tmp 无限增长:

bash 复制代码
# 添加定时清理(例如清理超过 7 天的文件)
echo 'systemd-tmpfiles --clean' > /etc/cron.daily/tmp-cleanup
chmod +x /etc/cron.daily/tmp-cleanup

验证

bash 复制代码
findmnt /tmp
# 确认 OPTIONS 中包含 rw,nosuid,nodev,noexec

6. 注意事项

兼容性影响

某些软件会在 /tmp 中写入并执行临时文件,添加 noexec 后可能受到影响:

  • 部分软件安装程序(如某些 RPM 的 %post 脚本)
  • pip install 编译 C 扩展时
  • 某些 Java 应用的临时文件
  • rpmbuild 构建过程

遇到问题时可以临时放开限制:

bash 复制代码
mount -o remount,exec /tmp
# 完成操作后恢复
mount -o remount,noexec /tmp

K8s 节点特别说明

对于 K8s 节点,noexec 通常不会影响容器化工作负载,因为容器使用自己的文件系统。但如果你在宿主机上直接运行构建任务或安装软件,需要留意兼容性。

7. 总结

场景 推荐方案
内存充足的通用服务器 tmpfs + noexec,nosuid,nodev + size= 限制
内存紧张的 K8s 节点 独立分区 + noexec,nosuid,nodev(首选)
已部署系统,无法新建分区 bind mount + noexec,nosuid,nodev + 定期清理
开发/构建服务器 独立分区或 bind mount + nosuid,nodev(考虑不加 noexec

无论选择哪种方案,核心原则有两个:一是让 /tmp 的配置显式可控 ------不要依赖 systemd 的隐式行为,在 /etc/fstab 中明确定义,确保重启后配置一致;二是空间隔离 ------尽量避免 /tmp 与根分区共享空间,防止 /tmp 被写满后影响整个系统。

相关推荐
小江的记录本2 小时前
【RocketMQ】RocketMQ核心知识体系全解(5大核心模块:架构模型、事务消息两阶段提交、回查机制、延迟消息、顺序消息)
linux·运维·服务器·前端·后端·架构·rocketmq
数据知道2 小时前
claw-code 源码详细分析:命令宇宙 vs 工具宇宙——`commands` / `tools` 镜像清单如何驱动路由与 shim 执行?
linux·服务器·网络·python·ai·claude code
三万棵雪松2 小时前
【Linux 物联网网关主控系统-Web部分(二)】
linux·前端·物联网
一叶之秋14122 小时前
通信之道:解锁Linux进程间通信的无限可能(一)
linux·运维·服务器
Deitymoon2 小时前
linux——线程的概念
linux
郝学胜-神的一滴2 小时前
Pytorch自动微分模块:从原理到实战,解锁反向传播核心奥秘
服务器·人工智能·pytorch·python·深度学习·机器学习
eF06U766F2 小时前
Ubuntu Linux 上 固定P/E 核混合架构CPU频率
linux·ubuntu·架构
minji...2 小时前
Linux 多线程(三)线程控制,线程终止,线程中的异常问题
linux·运维·服务器·开发语言·网络·算法
zzzsde2 小时前
【Linux】进程间通信(1)管道&&进程池实现
linux·运维·服务器