Kubernetes 容器 Seccomp 默认配置文件加固:RuntimeDefault 启用、配置验证与系统调用排查

枫少@KillBoy
枫少@KillBoy
枫少@KillBoy
管理员
370
文章
0
粉丝
云原生安全1 13字数 2514阅读8分22秒阅读模式
AI智能摘要
容器共享宿主机内核,未配置 Seccomp 且 kubelet 未启用默认值时,容器可能以 Unconfined 方式运行。RuntimeDefault 能收窄攻击面,却不是统一系统调用清单,也替代不了 Capabilities 与权限控制。各运行时默认配置不同,盘点 Pod 与初始化容器的 seccompProfile 后,再启用节点默认值并验证生效?
— AI 生成的文章内容摘要

容器与宿主机共享 linux 内核。如果工作负载未配置 Seccomp,且节点 kubelet 没有启用默认配置,容器可能以 Unconfined 方式运行,缺少 Seccomp 系统调用过滤。将默认配置收敛到 RuntimeDefault,可以减少不必要的内核接口暴露;但它不是统一的系统调用清单,也不能替代 linux Capabilities、权限控制和其他容器隔离措施。

本文适用于运行 Linux 容器、能够管理 kubelet 或工作负载清单的团队。实施前应确认 Kubernetes、容器运行时和托管平台的支持情况,并在测试环境验证:不同运行时及其版本的默认配置可能不同,同一个应用在不同节点上的兼容性也可能不同。

Kubernetes 容器 Seccomp 默认配置文件加固:RuntimeDefault 启用、配置验证与系统调用排查

准备:盘点配置与变更范围

先记录工作负载当前设置、节点运行时和回滚基线,避免把节点默认值误认为已经写入 Pod 清单。

# 查看节点及运行时版本
kubectl get nodes -o wide
kubectl get nodes 
  -o custom-columns='NODE:.metadata.name,RUNTIME:.status.nodeInfo.containerRuntimeVersion'

# 查看目标工作负载的 Pod 模板
kubectl -n <命名空间> get deployment <工作负载名> -o yaml

重点检查 Pod 级别、普通容器和初始化容器级别的 securityContext.seccompProfile,以及是否存在有意配置的 Localhost 或 Unconfined。容器级配置可以覆盖 Pod 级配置;仅检查 Pod 级字段不足以发现例外。

配置位置作用与检查重点
kubelet 默认配置为未指定 Seccomp 配置的工作负载提供节点级默认值;不改写 Pod API 字段
Pod 级 securityContext为 Pod 内容器提供默认配置,适合在工作负载清单中显式声明
容器级 securityContext可覆盖 Pod 级设置;需单独检查普通容器和初始化容器
Localhost使用节点上的本地配置文件;需保证目标节点具备对应文件
Unconfined不应用 Seccomp 配置;应作为受控例外,而不是常规回滚目标

选择具有代表性的测试工作负载,覆盖启动、健康检查、核心业务路径和定时任务。提前保存原始清单及 kubelet 配置,并确定负责节点变更、应用验证和故障回退的人员。

实施:先显式配置,再扩大节点默认值

在工作负载中声明 RuntimeDefault

将以下片段放入 Deployment 等控制器的 spec.template.spec;对于独立 Pod,则放入 spec。示例同时设置了初始化容器和普通容器,便于核对继承关系:

spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  initContainers:
    - name: init-example
      image: <初始化镜像>
  containers:
    - name: app
      image: <应用镜像>

Pod 级配置供未单独指定配置的容器继承。如果某个容器已有自己的 seccompProfile,应检查其覆盖结果,而不是假设它会采用 Pod 级值。修改控制器的 Pod 模板后,按照现有发布流程滚动更新,并观察状态:

kubectl -n <命名空间> rollout status deployment/<工作负载名>
kubectl -n <命名空间> get pods -o wide
kubectl -n <命名空间> describe pod <Pod名>
kubectl -n <命名空间> logs <Pod名> -c <容器名> --previous

--previous 用于查看发生过重启的容器上一次运行日志;如果容器没有先前实例,该命令可能没有可用结果。启动成功也不代表所有业务路径都兼容,仍需执行功能测试。

在节点上启用默认配置

需要为未显式声明配置的工作负载提供默认保护时,可在目标节点的 kubelet 配置文件中设置:

seccompDefault: true

也可以使用 kubelet 启动参数 --seccomp-default。具体配置入口、版本要求和重启方式应以集群发行版或托管平台的文档为准;不要直接覆盖平台生成的 kubelet 配置。

建议先对少量测试节点执行变更:保存原配置,按平台流程排空或隔离节点、更新配置并重启 kubelet,确认节点恢复就绪后,再让测试工作负载在节点上新建容器。启用节点默认值不会修改已有 Pod 的 securityContext.seccompProfile 字段,也不应依赖它改变已经运行的容器。完成验证后,再分批扩展到其他节点。

节点默认值不会覆盖工作负载显式指定的配置。因此,要同时治理显式的 Unconfined 例外;仅启用 kubelet 默认值不能消除这些例外。

验证:区分声明、生效状态与实际行为

核对 Pod 声明

kubectl -n <命名空间> get pod <Pod名> -o yaml

检查 Pod 级及各容器级的 seccompProfile。如果只启用了 kubelet 默认值,API 字段仍可能为空;这并不能单独证明配置未生效。Kubernetes 官方的 Seccomp 操作教程也说明了节点默认配置不会回写该字段。

在节点上检查容器运行时

通过受控管理通道登录运行目标容器的节点,使用已配置好运行时端点的 crictl 查找容器并检查运行时信息:

sudo crictl ps --name <容器名>
sudo crictl inspect <容器ID> | jq '.info.runtimeSpec.linux.seccomp'

如果输出包含 Seccomp 配置对象,说明检查结果中存在运行时配置;结合节点 kubelet 设置、Pod 声明和容器创建时间判断它是否符合预期。不同运行时的 inspect 输出结构可能不同,字段为空时应查阅对应运行时的检查方式,不能直接断言过滤已启用或已关闭。

还可以在节点上检查容器进程的 /proc/<宿主机PID>/status 中的 Seccomp 字段,确认进程是否处于过滤模式。但该字段本身不能证明使用的是哪一份配置,也不能证明目标系统调用已被阻断。

用受控测试确认阻断行为

在隔离测试环境中,针对当前运行时配置中已确认会被拒绝的系统调用,执行可复现的测试程序,记录节点、镜像、运行时版本、调用结果和时间。不要假定某个系统调用在所有 RuntimeDefault 配置中都会被拒绝。

测试应同时包括正常业务路径:阻断测试说明过滤器能发挥作用,业务测试才有助于发现它是否影响了必要功能。

排查:从应用错误关联到内核审计

Seccomp 拒绝系统调用可能表现为 Operation not permitted 等错误,但同类错误也可能来自 Capabilities、LSM、文件权限或其他限制。应先收集证据,再判断是否需要调整 Seccomp。

  1. 确定影响范围。 记录首次故障时间、Pod 与容器 ID、所在节点、镜像版本、重启次数,以及故障是否只出现在启用默认配置的新容器上。
  2. 检查应用日志和事件。 比较变更前后的错误与健康检查结果,确认失败发生在启动阶段还是特定业务操作中。
  3. 检查节点审计记录。 在具备相应权限且已配置审计采集的节点上,按故障时间查询。例如,使用 auditd 的环境可尝试:
   sudo ausearch -m SECCOMP -ts recent
   # 如节点通过 systemd 日志收集相关记录,也可检查
   sudo journalctl -k --since "15 minutes ago" | grep -i seccomp
  1. 关联进程与调用。 审计记录可能包含进程 ID、系统调用编号、架构和动作等信息。结合节点架构、运行时元数据及故障时间,将记录关联到目标容器;必要时使用系统提供的审计工具解析系统调用编号。
  2. 复现并排除其他原因。 在测试环境比较相同镜像和请求在不同配置下的表现,同时检查 LSM、Capabilities 和权限设置。确认调用确属业务必需后,再评估例外方案。

没有 SECCOMP 日志不等于没有发生阻断。 是否产生并收集日志取决于过滤动作、内核和审计配置;例如,直接返回错误的规则未必留下可供上述命令查询的记录。应结合应用错误、运行时配置和受控复现判断。

回滚与复盘:保留最小例外

发生兼容性故障时,优先缩小影响范围,而不是立即关闭所有节点的保护:

  1. 回滚工作负载发布。 若故障由 Pod 模板中新增的 RuntimeDefault 引起,可恢复先前经过验证的工作负载修订,并确认新 Pod 健康。注意:如果节点已启用 seccompDefault,仅删除 Pod 字段仍可能得到 RuntimeDefault,不一定能恢复原来的运行行为。
  2. 处理节点级变更。 若问题来自 kubelet 默认配置,按平台流程恢复原 kubelet 配置并重启 kubelet;将受影响工作负载迁移或重建到已恢复的节点,再验证业务。该操作影响节点上其他未显式配置 Seccomp 的新容器,应控制批次。
  3. 为必要例外设置期限。 若确认应用确实需要默认配置拒绝的调用,可评估经安全审查的 Localhost 自定义配置,并确保所有可调度节点都有一致的配置文件。确需临时使用 Unconfined 时,应记录批准人、影响范围、监控措施和到期时间;同时确认集群准入策略允许该例外。

变更完成后,将测试结果、受影响调用、运行时版本、例外清单和回滚记录纳入运维资料。后续升级容器运行时或迁移节点时,应重新执行关键兼容性测试:RuntimeDefault 是运行时提供的默认配置,其内容可能随运行时及版本变化。

 
枫少@KillBoy
    • 新年爆竹
      新年爆竹 1

      先上测试节点比较稳,生产直接改容易懵。

    匿名

    发表评论

    匿名网友

    拖动滑块以完成验证