gzip不保存文件权限等元数据,必须用tar -p打包再gzip,解压时需sudo tar -xpf并验证setuid位是否为04000,同时确认文件系统未挂载nosuid。

gzip 本身不处理文件权限、属主或特殊位(如 setuid、sticky),它只压缩文件内容。真正影响权限保留的,是压缩前的文件读取方式和解压时的上下文。所谓“gzip导致权限丢失”,其实是误把 gzip 当作归档工具用了——它不是 tar,不存元数据。
要防止敏感密钥文件(如 /etc/ssh/host_key、/root/.pgpass)在压缩过程中隐式丢失 setuid、sticky、属主等关键属性,核心不是 gzip 做什么,而是怎么打包 + 怎么解压。
必须用 tar 封装后再 gzip,不能单独 gzip 文件
单独执行 gzip secret.key 只会生成 secret.key.gz,原始文件被重命名,权限信息彻底脱离上下文;解压后 gunzip secret.key.gz 得到的 secret.key 属主变成当前用户、所有特殊位清零——这是默认行为,且无提示。
正确做法是:
- 先用
tar打包并保留元数据 - 再用
gzip压缩归档包
# ✅ 正确:打包时带上 -p(保留权限)和 --owner=root --group=root(显式固定属主) tar -cf - --owner=0 --group=0 -p /etc/ssh/host_key | gzip > ssh_keys_backup.tar.gz # ❌ 错误:直接 gzip,丢权限、丢属主、丢 sticky/setuid gzip /etc/ssh/host_key
解压时必须用 root + -xp 组合,否则权限仍会降级
即使归档里存了 UID 0/GID 0 和 setuid 位,普通用户解压:
-
--same-owner自动失效 - 所有文件属主静默变为当前用户
-
setuid、sticky位被内核忽略(即使-p写入也无效)
所以还原命令必须是:
sudo tar -xpf ssh_keys_backup.tar.gz -C /tmp/
其中:
-
x:解包 -
p:还原权限、所有者、特殊位(setuid/sticky) -
f:指定归档文件 -
sudo:确保以 root 运行,使--same-owner生效
⚠️ 注意:如果目标系统没有对应 GID(比如归档里记的是 GID 1002,但
/etc/group里没这组),tar 会回退为nogroup或数字 ID,需提前检查目标环境。
验证关键权限是否真被保留
解压后立即验证,别依赖“没报错就成功”:
# 查看是否带 setuid(显示为 s 而非 x) ls -l /tmp/etc/ssh/host_key # 查看完整权限位(含 setuid: 4000, sticky: 1000) stat /tmp/etc/ssh/host_key | grep "Access:"
若 Access: 行显示 04000(即 rws------),说明 setuid 成功保留;若只是 0600,说明失败——大概率是没用 root 解压,或 tar 命令漏了 -p。
补充:密钥类文件还需注意挂载选项限制
即使权限还原成功,若目标目录所在文件系统挂载时用了 nosuid 或 noexec:
-
setuid位会被内核强制忽略(运行时无效) -
chmod u+s也会静默失败
检查方法:
mount | grep "$(df . | tail -1 | awk '{print $1}')"
# 看输出是否含 nosuid、noexec
如需真正生效,得确保挂载选项允许 suid(默认一般开启,但安全加固后常关闭)。
不复杂但容易忽略











