Linux chcon -t container_file_t 的容器卷挂载 SELinux 标签修复

1次阅读

chcon -t container_file_t 挂载后不生效,根本原因是 docker/podman 使用 :z 或 :z 挂载时会自动重打标签并覆盖手动设置,且容器进程的 mcs 标签(如 c12,c34)需与文件上下文匹配,而 chcon 默认不设置 mcs。

Linux chcon -t container_file_t 的容器卷挂载 SELinux 标签修复

chcon -t container_file_t 为什么挂载后不生效

根本原因是 chcon 修改的是宿主机文件的 SElinux 上下文,但容器启动时若使用 -v 挂载卷,默认会触发 :z:Z 重标签行为——Docker / Podman 会主动覆盖你手动设的 container_file_t,尤其在启用 selinux-enabled=true 的环境中。

常见错误现象:ls -Z 看宿主机目录确实是 container_file_t,但容器内 cat /proc/1/attr/current 显示进程上下文是 system_u:system_r:container_t:s0:c12,c34,而访问挂载路径仍报 Permission denied,日志里出现 avc: denied { read } for ... scontext=system_u:system_r:container_t:s0:c12,c34 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir

  • 确认是否真需要 container_file_t:多数只读配置文件用 container_file_t 合理;但数据库数据目录、日志目录等应优先考虑 container_file_t + svirt_sandbox_file_t 组合或直接用 :Z
  • 如果用了 docker run -v /host/path:/cont/path:zchcon 白改——:z 会让 Docker 自动打上 system_u:object_r:container_file_t:s0递归处理,且比你手改更可靠
  • 若必须手动干预(如离线环境、Podman rootless 场景),先停容器,再 chcon -R -t container_file_t /host/path,最后确保挂载时不加 :z:Z,否则覆盖

container_file_t 和 svirt_sandbox_file_t 到底该选哪个

区别不在“能不能用”,而在“谁负责策略放行”。container_file_t 是通用容器文件类型,依赖 container_manage_cgroupcontainer_read_etc 等布尔值控制权限粒度;svirt_sandbox_file_t 是 libvirt/QEMU 虚拟机沙箱专用类型,被 virt_sandbox_file_t 进程域默认允许读写,Docker 也兼容它,但语义上不精准。

使用场景判断:

  • 标准 Docker/Podman 容器 → 优先 container_file_t,配合 setsebool -P container_manage_cgroup on 开启必要能力
  • 运行 systemd、需要 cgroup v1 写入的容器(如监控 agent)→ 必须用 container_file_tsvirt_sandbox_file_t 不含 cgroup 写权限
  • 临时调试、快速绕过限制 → svirt_sandbox_file_t 常更“好使”,因为策略宽松,但上线前应回退
  • 注意:两者都不能绕过 noexecnodev 等挂载选项限制,SELinux 标签和 mount flags 是两层控制

Podman rootless 下 chcon 失败提示 “Operation not supported”

这是 rootless 容器的典型限制:非 root 用户无法调用 setfilecon() 系统调用,chcon 会直接报错 Operation not supported,哪怕你用 sudo chcon,目标路径若在用户家目录(/home/xxx)下,底层 Filesystem 可能不支持扩展属性(如某些 NFS、exFAT 挂载)。

解决路径只有两条:

  • 换用 podman run --security-opt label=type:container_file_t,让 Podman 在挂载时注入上下文(需 newroleload_policy 权限,通常 rootless 默认有)
  • 改用 :Z 挂载:它会自动为 rootless 用户创建私有 container_file_t 标签,并处理 user_home_tcontainer_file_t 的转换,比手改安全
  • 检查宿主机 /home 所在分区是否支持 xattr:mount | grep "$(df . | tail -1 | awk '{print $1}'),输出中应含 context=... 或至少没禁用 xattr

为什么 ls -Z 显示 container_file_t 却 still get AVC denial

SELinux 拒绝不是单看目标文件类型,而是三元组匹配:scontext(源进程)、tcontext(目标文件)、tclass对象类别,如 filedirsock_file)。即使 tcontextcontainer_file_t,若 scontextsystem_u:system_r:container_t:s0:c12,c34,而策略里没允许这个具体 container_t 域读 container_file_t 目录,照样拒绝。

排查关键动作:

  • 查完整 AVC 日志:ausearch -m avc -ts recent | audit2why,别只看 ls -Z
  • 确认容器进程实际类型:ps -eZ | grep docker 或进容器执行 cat /proc/1/attr/current
  • 检查相关布尔值:getsebool container_manage_cgroup container_read_etc container_use_ceph,按需开启
  • 临时测试是否策略问题:setenforce 0 后重试,若 OK,说明纯 SELinux 策略限制,不是上下文错

最常被忽略的一点:容器内进程的 scontext 中的 c12,c34 是 MCS 标签,它要求目标文件也带相同 MCS(container_file_t:s0:c12,c34),而 chcon -t container_file_t 默认不设 MCS —— 正确做法是 chcon -t container_file_t:z /path:z 表示自动分配匹配的 MCS)或者用 :Z 让容器运行时处理。

text=ZqhQzanResources