排查 Azure Kubernetes 服务中的 seccomp 配置文件配置问题

安全计算(seccomp) 是一种 Linux 内核功能,用于限制系统调用(syscalls)容器可以进行,从而提高容器化工作负载的安全性。 在 Azure Kubernetes 服务(AKS)中,AKS 节点所使用的 containerd 运行时原生支持 seccomp。 启用 seccomp 配置文件可能会导致 AKS 工作负载失败,因为负载关键的系统调用 (syscalls) 被阻止。 本文介绍什么是 seccomp 配置文件、其工作原理,以及如何使用开源项目 Inspektor 小工具对它们进行故障排除。

背景

Syscalls 是允许用户空间程序请求内核服务的接口。 Seccomp 配置文件指定特定容器允许或拒绝的系统调用。 AKS 支持两个值:

  • RuntimeDefault:使用运行时提供的默认 seccomp 配置文件。
  • Unconfined:允许所有系统调用。

若要在 AKS 节点池上启用 seccomp,请参阅 使用内置 Linux 安全功能保护容器对资源的访问。 还可以配置自定义配置文件以满足工作负荷的特定需求,有关详细信息,请参阅 “配置自定义 seccomp 配置文件 ”。

使用 seccomp 配置文件时,测试并验证对工作负荷的影响非常重要。 某些工作负载需要的 syscall 限制可能比其他工作负载要少。 这意味着,如果工作负载需要的系统调用不包含在配置文件中,则它们在运行时可能会失败。

本文介绍如何使用开源项目 Inspektor Gadget 来诊断问题,并了解被阻止的系统调用。

症状

将 AKS 工作负载配置为使用 seccomp 配置文件后,工作负载意外退出,并出现以下错误之一:

  • 权限被拒绝

  • 未实现函数

先决条件

故障排除清单

步骤 1:修改 seccomp 配置文件

创建一个与您要进行故障排除的设定相匹配的自定义 seccomp 配置文件,并将其默认操作(如 SCMP_ACT_ERRNO)替换为 SCMP_ACT_LOG,以记录被阻止的 syscalls,而不是将其视为失败。

自定义 seccomp 配置文件可能如下所示:

{
    "defaultAction": "SCMP_ACT_ALLOW",
    "syscalls": [
      {
        "names": ["acct",
                "add_key",
                "bpf",
                "clock_adjtime",
                "clock_settime",
                "clone",
                "create_module",
                "delete_module",
                "finit_module",
                "get_kernel_syms",
                "get_mempolicy",
                "init_module",
                "ioperm",
                "iopl",
                "kcmp",
                "kexec_file_load",
                "kexec_load",
                "keyctl",
                "lookup_dcookie",
                "mbind",
                "mount",
                "move_pages",
                "nfsservctl",
                "open_by_handle_at",
                "perf_event_open",
                "personality",
                "pivot_root",
                "process_vm_readv",
                "process_vm_writev",
                "ptrace",
                "query_module",
                "quotactl",
                "reboot",
                "request_key",
                "set_mempolicy",
                "setns",
                "settimeofday",
                "stime",
                "swapon",
                "swapoff",
                "sysfs",
                "_sysctl",
                "umount",
                "umount2",
                "unshare",
                "uselib",
                "userfaultfd",
                "ustat",
                "vm86",
                "vm86old"],
        "action": "SCMP_ACT_LOG"
      }
    ]
  }

配置 自定义 seccomp 配置文件 的文章演示如何将自定义 seccomp 配置文件应用到 AKS 群集。 或者可以按照以下步骤进行:

  1. 运行以下命令获取 AKS 群集中节点的名称:

    kubectl get nodes 
    
  2. 使用kubectl debug命令在节点上启动调试 Pod,并确认seccomp文件夹存在且已安装tar工具(这样可以在下一步中将配置文件复制到节点):

    kubectl debug node/<node-name> -it --image=mcr.microsoft.com/azurelinux/base/core:3.0
    root [ / ]# mkdir -p /host/var/lib/kubelet/seccomp
    root [ / ]# tdnf install -y tar
    
  3. 复制运行命令时打印的 kubectl debug Pod 名称。 应类似于 node-debugger-<node-name>-<random-sufix>。 还可以通过列出 default 命名空间中的 pod 来检索它。

  4. 在另一个终端中,将 seccomp 配置文件直接传输到节点:

    kubectl cp <the path of the local seccomp profile>/my-profile.json <pod name>:/host/var/lib/kubelet/seccomp/my-profile.json
    

注释

对群集中的每个节点重复上述步骤,以确保使工作负载可能运行的所有节点都具备 seccomp 配置文件。

现在,您可以修改 seccompProfile 目标 Pod 的配置,该配置应限定在记录的系统调用范围内。 例如:

apiVersion: v1
kind: Pod
metadata:
  name: default-pod
  labels:
    app: default-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: my-profile.json
  containers:
  - name: test-container
    image: docker.io/library/nginx:latest

步骤 2:安装 Inspektor 小工具

Inspektor Gadget 提供有关影响容器的系统调用的见解。 若要使用它,请运行以下命令,在 gadget 主机中安装 kubectl 插件,并将 Inspektor 小工具 部署到群集中:

kubectl krew install gadget
kubectl gadget deploy

有关详细信息,请参阅 如何在 AKS 群集中安装 Inspektor 小工具

步骤 3:运行audit_seccomp小工具

安装 Inspektor 小工具后,使用 kubectl 小工具运行命令启动audit_seccomp小工具

kubectl gadget run audit_seccomp

步骤 4:分析被阻止的系统调用(syscalls)

使用 kubectl apply -f 命令运行工作负荷。 然后,audit_seccomp工具 会记录 seccomp 配置文件应阻止的 syscalls 及其关联的 Pod、容器和进程。 可以使用此信息来确定工作负荷失败的根本原因。

例如,如果使用 default-pod Pod my-profile.json 的配置文件运行上述 pod,输出如下所示:

K8S.NODE                           K8S.NAMESPACE K8S.PODNAME  K8S.CONTAINERNAME  COMM                 PID      TID  CODE             SYSCALL
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     docker-entrypoi  3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     docker-entrypoi  3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     docker-entrypoi  3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     docker-entrypoi  3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     docker-entrypoi  3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996628  3996628  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996628  3996628  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996632  3996632  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996632  3996632  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996632  3996632  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996628  3996628  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     10-listen-on-ip  3996628  3996628  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     20-envsubst-on-  3996639  3996639  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     20-envsubst-on-  3996639  3996639  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     20-envsubst-on-  3996641  3996641  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     30-tune-worker-  3996643  3996643  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     nginx            3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE
aks-nodepool1-38695788-vmss000002  default       default-pod  test-container     nginx            3996610  3996610  SECCOMP_RET_LOG  SYS_CLONE

输出表明 test-container 执行 SYS_CLONE seccomp 配置文件应阻止的系统调用。 使用这些信息,您可以确定是否允许容器中列出的 syscalls。 如果是这样,请通过删除它们来调整 seccomp 配置文件,从而防止工作负载失败。

一些常见的系统调用会被阻止,请注意这些。 更全面的列表可在默认配置文件阻止的“重要 syscalls”中找到。

被阻止的 syscall 注意事项
clock_settimeclock_adjtime 如果您的工作负载需要精确的时间同步,请确保这一系统调用不会被阻止。
add_keykey_ctl 如果您的工作负载需要密钥管理,这些被阻止的系统调用会阻止容器使用内核密钥环来存储内核中的安全数据、身份验证密钥、加密密钥和其他数据。
clone 此 syscall 会阻止克隆新命名空间,但除外 CLONE_NEWUSER。 如果阻止此 syscall,则依赖于创建新命名空间的工作负荷可能会受到影响。
io_uring 此 syscall 在升级到 containerd 2.0 时被阻止。 但是,1.7 的配置文件 containerd 中不会阻止它。

后续步骤

如果由于阻止的系统调用而遇到工作负载问题,请考虑使用符合应用程序特定需求的自定义 seccomp 配置文件。 你可以查看 Inspektor Gadget advise_seccomp gadget

测试和优化 seccomp 配置文件有助于维护 AKS 工作负载的性能和安全性。 有关进一步帮助,请参阅 安全计算

使用内置 Linux 安全功能保护对资源的容器访问

第三方信息免责声明

本文讨论的第三方产品由独立于微软的公司制造。 Microsoft对这些产品的性能或可靠性不作任何明示或暗示的保证。

第三方联系人免责声明

为了帮助您获取有关此主题的更多信息,Microsoft 提供了第三方的联系信息。 该联系信息可能会在不通知的情况下更改。 微软不保证第三方联系信息的准确性。

联系我们以获得帮助

如果有疑问,可以询问 Azure 社区支持。 您还可以向Azure反馈社区提交产品反馈。