6.1 隔离边界对比:SELinux 与 seccomp


6.1 隔离边界对比:SELinux 与 seccomp

本节摘要:SELinux 从"文件访问域"上限制容器能碰什么,seccomp 从"系统调用"上限制容器能做什么。Podman 在启用 SELinux 的发行版上默认打标签隔离,seccomp 默认 profile 与 Docker 同源但演进更激进。本节讲两道防线的机制、默认姿态、以及查日志定位拒绝原因的方法——安全配置的第一能力是"看懂内核为什么不让你"。

第一道防线:SELinux 域与标签

SELinux 的思路是把"主体能不能访问客体"从权限位层面抽走,交给独立的策略引擎判断。容器场景里,它给容器进程与文件分别贴标签:进程跑在容器域(container_t),数据被贴容器文件标签(container_file_t),策略规定容器域只能读写带容器标签的文件——宿主系统文件的其他标签一概拒绝。

这就解释了第 5.2 节的第一个坑:你把家目录文件挂进容器,文件带的是用户主目录标签,容器进程在容器域——策略拒绝。挂载选项 :Z 的本质是一次 chcon(改标签)操作:把目录贴成容器文件标签,域与标签匹配,放行。

看一次真实的拒绝记录,这是排错的抓手:

# 容器内尝试读宿主系统文件失败后,查审计日志 sudo ausearch -m avc -ts recent | tail -12 # type=AVC msg=audit(...): avc: denied { read } for # pid=... comm="cat" name="shadow" # scontext=system_u:system_r:container_t:s0:c123,c456 # tcontext=system_u:object_r:shadow_t:s0 # tclass=file # 解读:scontext 是容器进程的标签,tcontext 是目标文件的 # 标签,denied { read } 是被拒的操作——cat 一个 shadow 标签 # 文件被拒,这正是 SELinux 在拦"容器读系统敏感文件" # 两个引擎的对比点: # Docker:也需要手动处理标签(文档里的 --security-opt label=...), # 历史上默认行为各版本不一,社区教程里经常直接教用户关闭 SELinux # Podman:把标签操作做进了 -v 的 :Z/:z 语法,默认路径更顺 # 但两边的底层防线是同一个内核模块——SELinux 不关心引擎是谁

值得点破的一层对比:网上大量 Docker 教程以"关闭 SELinux 解决权限报错"收场,这是把防线拆了迁就症状。Podman 的工程选择是把正确动作做便捷(一个冒号),让"关掉防线"不再是最短路径。防线用不用得上是用户的事,但工具不该诱导用户拆防线。

第二道防线:seccomp,调用级黑名单

seccomp 在比 SELinux 更细的粒度上工作:拦截进程发出的系统调用本身。默认 profile 是一份黑名单——放行绝大多数调用,拦截公认高危的一批(内核密钥环操作、旧式模块加载、若干历史漏洞相关的调用族)。Podman 与 Docker 的默认 profile 都源自 moby 项目的维护,但 Podman 更激进地跟进新内核的调用面(新增高危调用更早进黑名单)。

自定义的典型场景:某些运行时需要被默认黑名单拦掉的调用。比如老版本 JVM 的性能诊断工具依赖 perf_events 相关调用,容器里一跑就报操作不允许。两种修法:

# 修法一:为单个容器放宽(最小范围原则) podman run --security-opt seccomp=/path/to/unconfined-jvm.json \ --rm myapp:jdk8 ./run-diagnostics.sh # 自定义 profile 在默认基础上开少数口子 # 修法二:审计后确认不需要,直接禁用——不推荐,除非是一次性 # 调试容器且容器内没有不可信输入 podman run --security-opt unconfined --rm ... # 解读:unconfined 等于拆掉这道防线,审计意义上容器 # 重新获得全部系统调用能力

两道防线挡的东西不一样

初学者常把两者混为一谈,用一张对照表分开:

维度 SELinux seccomp
检查对象 文件等资源的访问(主体-客体) 进程发出的系统调用
粒度 标签与域的策略匹配 按调用号逐个拦截
典型拦截 容器读宿主敏感文件 容器加载内核模块、操纵密钥环
拒绝的报错形态 EACCES 加审计日志 EPERM 或进程被杀
关闭的常见借口 "挂载目录权限报错" "JVM 工具跑不起来"
正确的松绑方式 :Z/:z 或 audit2allow 自定义 profile 开口子

06-01-fig01

一个完整案例:一次"莫名其妙"的挂载失败审计

背景:同事的容器在 RHEL 服务器上读挂载目录报 Permission denied,ls 看权限位完全正常(所有人可读),他准备提工单。操作:先复现——podman run -v /opt/shared:/s alpine cat /s/conf,失败;再查审计——ausearch 里出现 avc denied,scontext 是 container_t,tcontext 是 usr_t(/opt 下文件的默认标签);结论:不是权限位问题,是 SELinux 策略拒绝,目录没贴容器标签。处置:数据目录加 :Z 重跑,成功。解读:权限位是 DAC(自主访问控制)层面的检查,SELinux 是 MAC(强制访问控制)层面,两层都放行才真放行;报错信息同为 Permission denied,必须查日志才能分层。变式:如果目录必须保持原标签(系统工具也在用它),就不能 :Z,改为容器侧用 audit2allow 生成定制策略——但那是最后一招,优先调整数据目录布局。

本节要点回顾

  • SELinux 管访问,seccomp 管动作:前者拦"读不该读",后者拦"做不该做"
  • :Z 的本质是贴标签:让容器域与数据标签匹配,而不是降低防线
  • 拒绝要看审计日志:ausearch 的 scontext 与 tcontext 直接指认冲突双方
  • 两引擎同源同一内核防线:差别在默认姿态与"松绑的正确动作是否顺手"
  • unconfined 与关闭 SELinux 都是拆防线:只在一次性调试场景考虑

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U