From 0523f824bd8f1c2b38200450f76e5cc339d545e8 Mon Sep 17 00:00:00 2001 From: howieyuen Date: Wed, 23 Feb 2022 20:59:55 +0800 Subject: [PATCH] [zh]sync content/zh/docs/tutorials/security/seccomp.md --- content/zh/docs/tutorials/clusters/seccomp.md | 626 -------------- content/zh/docs/tutorials/security/seccomp.md | 783 ++++++++++++++++++ 2 files changed, 783 insertions(+), 626 deletions(-) delete mode 100644 content/zh/docs/tutorials/clusters/seccomp.md create mode 100644 content/zh/docs/tutorials/security/seccomp.md diff --git a/content/zh/docs/tutorials/clusters/seccomp.md b/content/zh/docs/tutorials/clusters/seccomp.md deleted file mode 100644 index d724d605b6..0000000000 --- a/content/zh/docs/tutorials/clusters/seccomp.md +++ /dev/null @@ -1,626 +0,0 @@ ---- -title: 使用 Seccomp 限制容器的系统调用 -content_type: tutorial -weight: 20 -min-kubernetes-server-version: v1.22 ---- - - - -{{< feature-state for_k8s_version="v1.19" state="stable" >}} - - -Seccomp 代表安全计算模式,自 2.6.12 版本以来一直是 Linux 内核的功能。 -它可以用来对进程的特权进行沙盒处理,从而限制了它可以从用户空间向内核进行的调用。 -Kubernetes 允许你将加载到节点上的 seccomp 配置文件自动应用于 Pod 和容器。 - -确定工作负载所需的特权可能很困难。在本教程中,你将了解如何将 seccomp 配置文件 -加载到本地 Kubernetes 集群中,如何将它们应用到 Pod,以及如何开始制作仅向容器 -进程提供必要特权的配置文件。 - -## {{% heading "objectives" %}} - - -* 了解如何在节点上加载 seccomp 配置文件 -* 了解如何将 seccomp 配置文件应用于容器 -* 观察由容器进程进行的系统调用的审核 -* 观察当指定了一个不存在的配置文件时的行为 -* 观察违反 seccomp 配置的情况 -* 了解如何创建精确的 seccomp 配置文件 -* 了解如何应用容器运行时默认 seccomp 配置文件 - -## {{% heading "prerequisites" %}} - -{{< version-check >}} - - -为了完成本教程中的所有步骤,你必须安装 [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) -和 [kubectl](/zh/docs/tasks/tools/)。本教程将显示同时具有 alpha(v1.22 新版本) -和通常可用的 seccomp 功能的示例。 -你应该确保为所使用的版本[正确配置](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)了集群。 - - - - -## 启用 `RuntimeDefault` 作为所有工作负载的默认 seccomp 配置文件 - -{{< feature-state state="alpha" for_k8s_version="v1.22" >}} - -`SeccompDefault` 是一个可选的 kubelet -[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates), -相应地,`--seccomp-default` 是此特性门控的 -[命令行标志](/zh/docs/reference/command-line-tools-reference/kubelet)。 -必须同时启用两者才能使用该功能。 - - -如果启用,kubelet 将默认使用 `RuntimeDefault` seccomp 配置, -而不是使用 `Unconfined`(禁用 seccomp)模式,该配置由容器运行时定义。 -默认配置旨在提供一组强大的安全默认值设置,同时避免影响工作负载的功能。 -不同的容器运行时之间及其不同的发布版本之间的默认配置可能不同, -例如在比较 CRI-O 和 containerd 的配置文件时(就会发现这点)。 - - -某些工作负载可能相比其他工作负载需要更少的系统调用限制。 -这意味着即使使用 `RuntimeDefault` 配置文件,它们也可能在运行时失败。 -要处理此类失效,你可以: - -- 将工作负载显式运行为 `Unconfined`。 -- 禁用节点的 `SeccompDefault` 功能。 - 还要确保工作负载被安排在禁用该功能的节点上。 -- 为工作负载创建自定义 seccomp 配置文件。 - - -如果你将此功能引入到类似生产的集群中, -Kubernetes 项目建议你在节点的子集上启用此特性门控, -然后在集群范围内推出更改之前测试工作负载的执行情况。 - -有关可能的升级和降级策略的更多详细信息, -请参见[相关 Kubernetes 增强提案 (KEP)](https://github.com/kubernetes/enhancements/tree/a70cc18/keps/sig-node/2413-seccomp-by-default#upgrade--downgrade-strategy)。 - - -由于该功能处于 alpha 状态,因此默认情况下是被禁用的。要启用它, -请将标志 `--feature-gates=SeccompDefault=true --seccomp-default` -传递给 `kubelet` CLI 或通过 -[kubelet 配置文件](/zh/docs/tasks/administer-cluster/kubelet-config-file/)启用它。 -要在 [kind](https://kind.sigs.k8s.io) 中启用特性门控, -请确保 `kind` 提供所需的最低 Kubernetes 版本并 -[在 kind 配置中](https://kind.sigs.k8s.io/docs/user/quick-start/#enable-feature-gates-in-your-cluster) -启用 `SeccompDefault` 功能: - -```yaml -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -featureGates: - SeccompDefault: true -``` - - -## 创建 Seccomp 文件 - -这些配置文件的内容将在以后进行探讨,但现在继续进行,并将其下载到名为 `profiles/` 的目录中,以便可以将其加载到集群中。 - -{{< tabs name="tab_with_code" >}} -{{{< tab name="audit.json" >}} -{{< codenew file="pods/security/seccomp/profiles/audit.json" >}} -{{< /tab >}} -{{< tab name="violation.json" >}} -{{< codenew file="pods/security/seccomp/profiles/violation.json" >}} -{{< /tab >}}} -{{< tab name="fine-grained.json" >}} -{{< codenew file="pods/security/seccomp/profiles/fine-grained.json" >}} -{{< /tab >}}} -{{< /tabs >}} - - -## 使用 Kind 创建一个本地 Kubernetes 集群 - -为简单起见,可以使用 [kind](https://kind.sigs.k8s.io/) 创建一个已经加载 seccomp 配置文件的单节点集群。 -Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点都是一个容器。这允许将文件挂载到每个容器的文件系统中, -类似于将文件挂载到节点上。 - -{{< codenew file="pods/security/seccomp/kind.yaml" >}} -
- -下载上面的这个示例,并将其保存为 `kind.yaml`。然后使用这个配置创建集群。 - -``` -kind create cluster --config=kind.yaml -``` - - -一旦这个集群已经就绪,找到作为单节点集群运行的容器: - -``` -docker ps -``` - - -你应该看到输出显示正在运行的容器名称为 `kind-control-plane`。 - -``` -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -6a96207fed4b kindest/node:v1.18.2 "/usr/local/bin/entr…" 27 seconds ago Up 24 seconds 127.0.0.1:42223->6443/tcp kind-control-plane -``` - - -如果观察该容器的文件系统,则应该看到 `profiles/` 目录已成功加载到 kubelet 的默认 seccomp 路径中。 -使用 `docker exec` 在 Pod 中运行命令: - -``` -docker exec -it 6a96207fed4b ls /var/lib/kubelet/seccomp/profiles -``` - -``` -audit.json fine-grained.json violation.json -``` - - -## 使用 seccomp 配置文件创建 Pod 以进行系统调用审核 - -首先,将 `audit.json` 配置文件应用到新的 Pod 中,该配置文件将记录该进程的所有系统调用。 - -为你的 Kubernetes 版本下载正确的清单: - -{{< tabs name="audit_pods" >}} -{{< tab name="v1.19 或更新版本(GA)" >}} -{{< codenew file="pods/security/seccomp/ga/audit-pod.yaml" >}} -{{< /tab >}}} -{{{< tab name="v1.19之前版本(alpha)" >}} -{{< codenew file="pods/security/seccomp/alpha/audit-pod.yaml" >}} -{{< /tab >}} -{{< /tabs >}} -
- - -在集群中创建 Pod: - -``` -kubectl apply -f audit-pod.yaml -``` - - -这个配置文件并不限制任何系统调用,所以这个 Pod 应该会成功启动。 - -``` -kubectl get pod/audit-pod -``` - -``` -NAME READY STATUS RESTARTS AGE -audit-pod 1/1 Running 0 30s -``` - - -为了能够与该容器公开的端点进行交互,请创建一个 NodePort 服务, -该服务允许从 kind 控制平面容器内部访问该端点。 - -``` -kubectl expose pod/audit-pod --type NodePort --port 5678 -``` - - -检查这个服务在这个节点上被分配了什么端口。 - -``` -kubectl get svc/audit-pod -``` - -``` -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -audit-pod NodePort 10.111.36.142 5678:32373/TCP 72s -``` - - -现在你可以使用 `curl` 命令从 kind 控制平面容器内部通过该服务暴露出来的端口来访问这个端点。 - -``` -docker exec -it 6a96207fed4b curl localhost:32373 -``` - -``` -just made some syscalls! -``` - - -你可以看到该进程正在运行,但是实际上执行了哪些系统调用?因为该 Pod 是在本地集群中运行的, -你应该可以在 `/var/log/syslog` 日志中看到这些。打开一个新的终端窗口,使用 `tail` 命令来 -查看来自 `http-echo` 的调用输出: - -``` -tail -f /var/log/syslog | grep 'http-echo' -``` - -你应该已经可以看到 `http-echo` 发出的一些系统调用日志, -如果你在控制面板容器内 `curl` 了这个端点,你会看到更多的日志。 - -``` -Jul 6 15:37:40 my-machine kernel: [369128.669452] audit: type=1326 audit(1594067860.484:14536): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=51 compat=0 ip=0x46fe1f code=0x7ffc0000 -Jul 6 15:37:40 my-machine kernel: [369128.669453] audit: type=1326 audit(1594067860.484:14537): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=54 compat=0 ip=0x46fdba code=0x7ffc0000 -Jul 6 15:37:40 my-machine kernel: [369128.669455] audit: type=1326 audit(1594067860.484:14538): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000 -Jul 6 15:37:40 my-machine kernel: [369128.669456] audit: type=1326 audit(1594067860.484:14539): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=288 compat=0 ip=0x46fdba code=0x7ffc0000 -Jul 6 15:37:40 my-machine kernel: [369128.669517] audit: type=1326 audit(1594067860.484:14540): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=0 compat=0 ip=0x46fd44 code=0x7ffc0000 -Jul 6 15:37:40 my-machine kernel: [369128.669519] audit: type=1326 audit(1594067860.484:14541): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000 -Jul 6 15:38:40 my-machine kernel: [369188.671648] audit: type=1326 audit(1594067920.488:14559): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000 -Jul 6 15:38:40 my-machine kernel: [369188.671726] audit: type=1326 audit(1594067920.488:14560): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000 -``` - - -通过查看每一行上的 `syscall=` 条目,你可以开始了解 `http-echo` 进程所需的系统调用。 -尽管这些不太可能包含它使用的所有系统调用,但它可以作为该容器的 seccomp 配置文件的基础。 - -开始下一节之前,请清理该 Pod 和 Service: - -``` -kubectl delete pod/audit-pod -kubectl delete svc/audit-pod -``` - - -## 使用导致违规的 seccomp 配置文件创建 Pod - -为了进行演示,请将不允许任何系统调用的配置文件应用于 Pod。 - -为你的 Kubernetes 版本下载正确的清单: - -{{< tabs name="violation_pods" >}} -{{< tab name="v1.19 或更新版本(GA)" >}} -{{< codenew file="pods/security/seccomp/ga/violation-pod.yaml" >}} -{{< /tab >}}} -{{{< tab name="v1.19 之前版本(alpha)" >}} -{{< codenew file="pods/security/seccomp/alpha/violation-pod.yaml" >}} -{{< /tab >}} -{{< /tabs >}} -
- - -在集群中创建 Pod: - -``` -kubectl apply -f violation-pod.yaml -``` - - -如果你检查 Pod 的状态,你将会看到该 Pod 启动失败。 - -``` -kubectl get pod/violation-pod -``` - -``` -NAME READY STATUS RESTARTS AGE -violation-pod 0/1 CrashLoopBackOff 1 6s -``` - - -如上例所示,`http-echo` 进程需要大量的系统调用。通过设置 `"defaultAction": "SCMP_ACT_ERRNO"`, -来指示 seccomp 在任何系统调用上均出错。这是非常安全的,但是会删除执行有意义的操作的能力。 -你真正想要的只是给工作负载所需的特权。 - -开始下一节之前,请清理该 Pod 和 Service: - -``` -kubectl delete pod/violation-pod -kubectl delete svc/violation-pod -``` - - -## 使用设置仅允许需要的系统调用的 seccomp 配置文件来创建 Pod - -如果你看一下 `fine-pod.json` 文件,你会注意到在第一个示例中配置文件设置为 `"defaultAction": "SCMP_ACT_LOG"` 的一些系统调用。 -现在,配置文件设置为 `"defaultAction": "SCMP_ACT_ERRNO"`,但是在 `"action": "SCMP_ACT_ALLOW"` 块中明确允许一组系统调用。 -理想情况下,容器将成功运行,并且你将不会看到任何发送到 `syslog` 的消息。 - -为你的 Kubernetes 版本下载正确的清单: - -{{< tabs name="fine_pods" >}} -{{< tab name="v1.19 或更新版本(GA)" >}} -{{< codenew file="pods/security/seccomp/ga/fine-pod.yaml" >}} -{{< /tab >}}} -{{{< tab name="v1.19 之前版本(alpha)" >}} -{{< codenew file="pods/security/seccomp/alpha/fine-pod.yaml" >}} -{{< /tab >}} -{{< /tabs >}} -
- - -在你的集群上创建Pod: - -``` -kubectl apply -f fine-pod.yaml -``` - - -Pod 应该被成功启动。 - -``` -kubectl get pod/fine-pod -``` - -``` -NAME READY STATUS RESTARTS AGE -fine-pod 1/1 Running 0 30s -``` - - -打开一个新的终端窗口,使用 `tail` 命令查看来自 `http-echo` 的调用的输出: - -``` -tail -f /var/log/syslog | grep 'http-echo' -``` - - -使用 NodePort 服务为该 Pod 开一个端口: - -``` -kubectl expose pod/fine-pod --type NodePort --port 5678 -``` - - -检查服务在该节点被分配了什么端口: - -``` -kubectl get svc/fine-pod -``` - -``` -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -fine-pod NodePort 10.111.36.142 5678:32373/TCP 72s -``` - - -使用 `curl` 命令从 kind 控制面板容器内部请求这个端点: - -``` -docker exec -it 6a96207fed4b curl localhost:32373 -``` - -``` -just made some syscalls! -``` - - -你会看到 `syslog` 中没有任何输出,因为这个配置文件允许了所有需要的系统调用, -并指定如果有发生列表之外的系统调用将发生错误。从安全角度来看,这是理想的情况, -但是在分析程序时需要多付出一些努力。如果有一种简单的方法无需花费太多精力就能更接近此安全性,那就太好了。 - -开始下一节之前,请清理该 Pod 和 Service: - -``` -kubectl delete pod/fine-pod -kubectl delete svc/fine-pod -``` - - -## 使用容器运行时默认的 seccomp 配置文件创建 Pod - -大多数容器运行时都提供一组允许或不允许的默认系统调用。通过使用 `runtime/default` 注释 -或将 Pod 或容器的安全上下文中的 seccomp 类型设置为 `RuntimeDefault`,可以轻松地在 Kubernetes 中应用默认值。 - -为你的 Kubernetes 版本下载正确的清单: - -{{< tabs name="default_pods" >}} -{{< tab name="v1.19 或更新版本(GA)" >}} -{{< codenew file="pods/security/seccomp/ga/default-pod.yaml" >}} -{{< /tab >}}} -{{{< tab name="v1.19 之前版本(alpha)" >}} -{{< codenew file="pods/security/seccomp/alpha/default-pod.yaml" >}} -{{< /tab >}} -{{< /tabs >}} -
- - -默认的 seccomp 配置文件应该为大多数工作负载提供足够的权限。 - -## {{% heading "whatsnext" %}} - - -额外的资源: - -* [seccomp 概要](https://lwn.net/Articles/656307/) -* [Seccomp 在 Docker 中的安全配置](https://docs.docker.com/engine/security/seccomp/) \ No newline at end of file diff --git a/content/zh/docs/tutorials/security/seccomp.md b/content/zh/docs/tutorials/security/seccomp.md new file mode 100644 index 0000000000..9fe9b14b12 --- /dev/null +++ b/content/zh/docs/tutorials/security/seccomp.md @@ -0,0 +1,783 @@ +--- +title: 使用 seccomp 限制容器的系统调用 +content_type: tutorial +weight: 20 +min-kubernetes-server-version: v1.22 +--- + + + + +{{< feature-state for_k8s_version="v1.19" state="stable" >}} + + +Seccomp 代表安全计算(Secure Computing)模式,自 2.6.12 版本以来,一直是 Linux 内核的一个特性。 +它可以用来沙箱化进程的权限,限制进程从用户态到内核态的调用。 +Kubernetes 能使你自动将加载到 {{< glossary_tooltip text="节点" term_id="node" >}}上的 +seccomp 配置文件应用到你的 Pod 和容器。 + +识别你的工作负载所需要的权限是很困难的。在本篇教程中, +你将了解如何将 seccomp 配置文件加载到本地的 Kubernetes 集群中, +如何将它们应用到 Pod,以及如何开始制作只为容器进程提供必要的权限的配置文件。 + +## {{% heading "objectives" %}} + + +* 了解如何在节点上加载 seccomp 配置文件 +* 了解如何将 seccomp 配置文件应用到容器上 +* 观察容器进程对系统调用的审计 +* 观察指定的配置文件缺失时的行为 +* 观察违反 seccomp 配置文件的行为 +* 了解如何创建细粒度的 seccomp 配置文件 +* 了解如何应用容器运行时所默认的 seccomp 配置文件 + +## {{% heading "prerequisites" %}} + + +为了完成本篇教程中的所有步骤,你必须安装 [kind](/zh/docs/tasks/tools/#kind) +和 [kubectl](/zh/docs/tasks/tools/#kubectl)。 + +本篇教程演示的某些示例仍然是 alpha 状态(自 v1.22 起),另一些示例则仅使用 seccomp 正式发布的功能。 +你应该确保,针对你使用的版本, +[正确配置](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)了集群。 + +本篇教程也使用了 `curl` 工具来下载示例到你的计算机上。 +你可以使用其他自己偏好的工具来自适应这些步骤。 + +{{< note >}} + +无法将 seccomp 配置文件应用于在容器的 `securityContext` 中设置了 `privileged: true` 的容器。 +特权容器始终以 `Unconfined` 的方式运行。 +{{< /note >}} + + + + +## 下载示例 seccomp 配置文件 {#download-profiles} + +这些配置文件的内容将在稍后进行分析, +现在先将它们下载到名为 `profiles/` 的目录中,以便将它们加载到集群中。 + +{{< tabs name="tab_with_code" >}} +{{{< tab name="audit.json" >}} +{{< codenew file="pods/security/seccomp/profiles/audit.json" >}} +{{< /tab >}} +{{< tab name="violation.json" >}} +{{< codenew file="pods/security/seccomp/profiles/violation.json" >}} +{{< /tab >}}} +{{< tab name="fine-grained.json" >}} +{{< codenew file="pods/security/seccomp/profiles/fine-grained.json" >}} +{{< /tab >}}} +{{< /tabs >}} + + +执行这些命令: + +```shell +mkdir ./profiles +curl -L -o profiles/audit.json https://k8s.io/examples/pods/security/seccomp/profiles/audit.json +curl -L -o profiles/violation.json https://k8s.io/examples/pods/security/seccomp/profiles/violation.json +curl -L -o profiles/fine-grained.json https://k8s.io/examples/pods/security/seccomp/profiles/fine-grained.json +ls profiles +``` + + +你应该看到在最后一步的末尾列出有三个配置文件: +``` +audit.json fine-grained.json violation.json +``` + + + +## 使用 kind 创建本地 Kubernetes 集群 {#create-a-local-kubernetes-cluster-with-kind} + +为简单起见,[kind](https://kind.sigs.k8s.io/) 可用来创建加载了 seccomp 配置文件的单节点集群。 +Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点都是一个容器。 +这允许将文件挂载到每个容器的文件系统中,类似于将文件加载到节点上。 + +{{< codenew file="pods/security/seccomp/kind.yaml" >}} + + +下载该示例 kind 配置,并将其保存到名为 `kind.yaml` 的文件中: +```shell +curl -L -O https://k8s.io/examples/pods/security/seccomp/kind.yaml +``` + + +你可以通过设置节点的容器镜像来设置特定的 Kubernetes 版本。 +有关此类配置的更多信息, +参阅 kind 文档中[节点](https://kind.sigs.k8s.io/docs/user/configuration/#nodes)小节。 +本篇教程假定你正在使用 Kubernetes {{< param "version" >}}。 + + +作为 alpha 特性,你可以将 Kubernetes 配置为使用 +{{< glossary_tooltip text="容器运行时" term_id="container-runtime" >}} +默认首选的配置文件,而不是回退到 `Unconfined`。 +如果你想尝试,请在继续之前参阅 +[启用使用 `RuntimeDefault` 作为所有工作负载的默认 seccomp 配置文件](#enable-runtimedefault-as-default) + + +有了 kind 配置后,使用该配置创建 kind 集群: + +```shell +kind create cluster --config=kind.yaml +``` + + +新的 Kubernetes 集群准备就绪后,找出作为单节点集群运行的 Docker 容器: + +```shell +docker ps +``` + + +你应该看到输出中名为 `kind-control-plane` 的容器正在运行。 +输出类似于: +``` +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +6a96207fed4b kindest/node:v1.18.2 "/usr/local/bin/entr…" 27 seconds ago Up 24 seconds 127.0.0.1:42223->6443/tcp kind-control-plane +``` + + +如果观察该容器的文件系统, +你应该会看到 `profiles/` 目录已成功加载到 kubelet 的默认 seccomp 路径中。 +使用 `docker exec` 在 Pod 中运行命令: + +```shell +# 将 6a96207fed4b 更改为你从 “docker ps” 看到的容器 ID +docker exec -it 6a96207fed4b ls /var/lib/kubelet/seccomp/profiles +``` + +``` +audit.json fine-grained.json violation.json +``` + + +你已验证这些 seccomp 配置文件可用于在 kind 中运行的 kubelet。 + + +## 启用使用 `RuntimeDefault` 作为所有工作负载的默认 seccomp 配置文件 {#enable-runtimedefault-as-default} + +{{< feature-state state="alpha" for_k8s_version="v1.22" >}} + + +`SeccompDefault` 是一个可选的 kubelet [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates) +以及相应的 `--seccomp-default` [命令行标志](/zh/docs/reference/command-line-tools-reference/kubelet)。 +两者必须同时启用才能使用该功能。 + + +如果启用,kubelet 将会默认使用 `RuntimeDefault` seccomp 配置文件, +(这一配置文明是由容器运行时定义的),而不是使用 `Unconfined`(禁用 seccomp)模式。 +默认的配置文件旨在提供一组限制性较强且能保留工作负载功能的安全默认值。 +不同容器运行时及其不同发布版本之间的默认配置文件可能有所不同, +例如在比较来自 CRI-O 和 containerd 的配置文件时。 + +{{< note >}} + +启用该功能既不会更改 Kubernetes `securityContext.seccompProfile` API 字段, +也不会添加已弃用的工作负载注解。 +这为用户提供了随时回滚的可能性,而且无需实际更改工作负载配置。 +[`crictl inspect`](https://github.com/kubernetes-sigs/cri-tools) +之类的工具可用于验证容器正在使用哪个 seccomp 配置文件。 +{{< /note >}} + + +与其他工作负载相比,某些工作负载可能需要更少的系统调用限制。 +这意味着即使使用 `RuntimeDefault` 配置文件,它们也可能在运行时失败。 +要应对此类故障,你可以: + +- 将工作负载显式运行为 `Unconfined`。 +- 禁用节点的 `SeccompDefault` 功能。还要确保工作负载被调度到禁用该功能的节点上。 +- 为工作负载创建自定义 seccomp 配置文件。 + + +如果你将此功能引入到类似生产的集群中, +Kubernetes 项目建议你在部分节点上启用此特性门控, +然后在整个集群范围内推出更改之前,测试工作负载执行情况。 + +有关可能的升级和降级策略的更多详细信息, +请参阅[相关的 Kubernetes 增强提案 (KEP)](https://github.com/kubernetes/enhancements/tree/a70cc18/keps/sig-node/2413-seccomp-by-default#upgrade--downgrade-strategy)。 + + +由于此特性处于 alpha 阶段,默认是被禁用的。 +要启用它,传递标志 `--feature-gates=SeccompDefault=true --seccomp-default` 到 +kubelet CLI 或者通过 [kubelet 配置文件](/docs/tasks/administer-cluster/kubelet-config-file/)启用。 +要在 [kind](https://kind.sigs.k8s.io) 启用特性门控, +请确保 `kind` 提供所需的最低 Kubernetes 版本, +并[在 kind 配置中](https://kind.sigs.k8s.io/docs/user/quick-start/#enable-feature-gates-in-your-cluster) +启用了 `SeccompDefault` 特性: + +```yaml +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +featureGates: + SeccompDefault: true +nodes: + - role: control-plane + image: kindest/node:v1.23.0@sha256:49824ab1727c04e56a21a5d8372a402fcd32ea51ac96a2706a12af38934f81ac + kubeadmConfigPatches: + - | + kind: JoinConfiguration + nodeRegistration: + kubeletExtraArgs: + seccomp-default: "true" + - role: worker + image: kindest/node:v1.23.0@sha256:49824ab1727c04e56a21a5d8372a402fcd32ea51ac96a2706a12af38934f81ac + kubeadmConfigPatches: + - | + kind: JoinConfiguration + nodeRegistration: + kubeletExtraArgs: + feature-gates: SeccompDefault=true + seccomp-default: "true" +``` + + +如果集群已就绪,则运行一个 Pod: + +```shell +kubectl run --rm -it --restart=Never --image=alpine alpine -- sh +``` + + +现在应该附加了默认的 seccomp 配置文件。 +这可以通过使用 `docker exec` 为 kind 上的容器运行 `crictl inspect` 来验证: + +```shell +docker exec -it kind-worker bash -c \ + 'crictl inspect $(crictl ps --name=alpine -q) | jq .info.runtimeSpec.linux.seccomp' +``` + +```json +{ + "defaultAction": "SCMP_ACT_ERRNO", + "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32"], + "syscalls": [ + { + "names": ["..."] + } + ] +} +``` + + +## 使用 seccomp 配置文件创建 Pod 以进行系统调用审计 {#create-a-pod-with-a-seccomp-profile-for-syscall-auditing} + +首先,将 `audit.json` 配置文件应用到新的 Pod 上,该配置文件将记录进程的所有系统调用。 + +这是该 Pod 的清单: + +{{< codenew file="pods/security/seccomp/ga/audit-pod.yaml" >}} + +{{< note >}} + +已弃用的 seccomp 注解 `seccomp.security.alpha.kubernetes.io/pod`(针对整个 Pod)和 +`container.seccomp.security.alpha.kubernetes.io/[name]`(针对单个容器) +将随着 Kubernetes v1.25 的发布而被删除。 +请在可能的情况下使用原生 API 字段而不是注解。 +{{< /note >}} + + +在集群中创建 Pod: + +```shell +kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/audit-pod.yaml +``` + + +此配置文件不限制任何系统调用,因此 Pod 应该成功启动。 + +```shell +kubectl get pod/audit-pod +``` + +``` +NAME READY STATUS RESTARTS AGE +audit-pod 1/1 Running 0 30s +``` + + +为了能够与容器暴露的端点交互, +创建一个 NodePort 类型的 {{< glossary_tooltip text="Service" term_id="service" >}}, +允许从 kind 控制平面容器内部访问端点。 + +```shell +kubectl expose pod audit-pod --type NodePort --port 5678 +``` + + +检查 Service 在节点上分配的端口。 + +```shell +kubectl get service audit-pod +``` + + +输出类似于: +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +audit-pod NodePort 10.111.36.142 5678:32373/TCP 72s +``` + + +现在,你可以使用 `curl` 从 kind 控制平面容器内部访问该端点,位于该服务所公开的端口上。 +使用 `docker exec` 在属于该控制平面容器的容器中运行 `curl` 命令: + +```shell +# 将 6a96207fed4b 更改为你从 “docker ps” 看到的控制平面容器 ID +docker exec -it 6a96207fed4b curl localhost:32373 +``` + +``` +just made some syscalls! +``` + + +你可以看到该进程正在运行,但它实际上进行了哪些系统调用? +因为这个 Pod 在本地集群中运行,你应该能够在 `/var/log/syslog` 中看到它们。 +打开一个新的终端窗口并 `tail` 来自 `http-echo` 的调用的输出: + +```shell +tail -f /var/log/syslog | grep 'http-echo' +``` + + +你应该已经看到了一些由 `http-echo` 进行的系统调用的日志, +如果你在控制平面容器中 `curl` 端点,你会看到更多的写入。 + +例如: +``` +Jul 6 15:37:40 my-machine kernel: [369128.669452] audit: type=1326 audit(1594067860.484:14536): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=51 compat=0 ip=0x46fe1f code=0x7ffc0000 +Jul 6 15:37:40 my-machine kernel: [369128.669453] audit: type=1326 audit(1594067860.484:14537): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=54 compat=0 ip=0x46fdba code=0x7ffc0000 +Jul 6 15:37:40 my-machine kernel: [369128.669455] audit: type=1326 audit(1594067860.484:14538): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000 +Jul 6 15:37:40 my-machine kernel: [369128.669456] audit: type=1326 audit(1594067860.484:14539): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=288 compat=0 ip=0x46fdba code=0x7ffc0000 +Jul 6 15:37:40 my-machine kernel: [369128.669517] audit: type=1326 audit(1594067860.484:14540): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=0 compat=0 ip=0x46fd44 code=0x7ffc0000 +Jul 6 15:37:40 my-machine kernel: [369128.669519] audit: type=1326 audit(1594067860.484:14541): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000 +Jul 6 15:38:40 my-machine kernel: [369188.671648] audit: type=1326 audit(1594067920.488:14559): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=270 compat=0 ip=0x4559b1 code=0x7ffc0000 +Jul 6 15:38:40 my-machine kernel: [369188.671726] audit: type=1326 audit(1594067920.488:14560): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=29064 comm="http-echo" exe="/http-echo" sig=0 arch=c000003e syscall=202 compat=0 ip=0x455e53 code=0x7ffc0000 +``` + + +通过查看每一行的 `syscall=` 条目,你可以开始了解 `http-echo` 进程所需的系统调用。 +虽然这些不太可能包含它使用的所有系统调用,但它可以作为此容器的 seccomp 配置文件的基础。 + +在转到下一部分之前清理该 Pod 和 Service: + +```shell +kubectl delete service audit-pod --wait +kubectl delete pod audit-pod --wait --now +``` + + +## 使用导致违规的 seccomp 配置文件创建 Pod {#create-pod-with-seccomp-profile-that-causes-violation} + +出于演示目的,将配置文件应用于不允许任何系统调用的 Pod 上。 + +此演示的清单是: + +{{< codenew file="pods/security/seccomp/ga/violation-pod.yaml" >}} + + +尝试在集群中创建 Pod: + +```shell +kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/violation-pod.yaml +``` + + +Pod 创建,但存在问题。 +如果你检查 Pod 状态,你应该看到它没有启动。 + +```shell +kubectl get pod/violation-pod +``` + +``` +NAME READY STATUS RESTARTS AGE +violation-pod 0/1 CrashLoopBackOff 1 6s +``` + + +如上例所示,`http-echo` 进程需要相当多的系统调用。 +这里 seccomp 已通过设置 `"defaultAction": "SCMP_ACT_ERRNO"` 被指示为在发生任何系统调用时报错。 +这是非常安全的,但消除了做任何有意义的事情的能力。 +你真正想要的是只给工作负载它们所需要的权限。 + +在转到下一部分之前清理该 Pod: + +```shell +kubectl delete pod violation-pod --wait --now +``` + + +## 使用只允许必要的系统调用的 seccomp 配置文件创建 Pod {#create-pod-with-seccomp-profile-that-only-allows-necessary-syscalls} + +如果你看一看 `fine-grained.json` 配置文件, +你会注意到第一个示例的 syslog 中看到的一些系统调用, +其中配置文件设置为 `"defaultAction": "SCMP_ACT_LOG"`。 +现在的配置文件设置 `"defaultAction": "SCMP_ACT_ERRNO"`, +但在 `"action": "SCMP_ACT_ALLOW"` 块中明确允许一组系统调用。 +理想情况下,容器将成功运行,并且你看到没有消息发送到 `syslog`。 + +此示例的清单是: + +{{< codenew file="pods/security/seccomp/ga/fine-pod.yaml" >}} + + +在你的集群中创建 Pod: + +```shell +kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/fine-pod.yaml +``` + +```shell +kubectl get pod fine-pod +``` + + +此 Pod 应该显示为已成功启动: +``` +NAME READY STATUS RESTARTS AGE +fine-pod 1/1 Running 0 30s +``` + + +打开一个新的终端窗口并使用 `tail` 来监视提到来自 `http-echo` 的调用的日志条目: + +```shell +# 你计算机上的日志路径可能与 “/var/log/syslog” 不同 +tail -f /var/log/syslog | grep 'http-echo' +``` + + +接着,使用 NodePort Service 公开 Pod: + +```shell +kubectl expose pod fine-pod --type NodePort --port 5678 +``` + + +检查节点上的 Service 分配了什么端口: + +```shell +kubectl get service fine-pod +``` + + +输出类似于: +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +fine-pod NodePort 10.111.36.142 5678:32373/TCP 72s +``` + + +使用 `curl` 从 kind 控制平面容器内部访问端点: + +```shell +# 将 6a96207fed4b 更改为你从 “docker ps” 看到的控制平面容器 ID +docker exec -it 6a96207fed4b curl localhost:32373 +``` + +``` +just made some syscalls! +``` + + +你应该在 `syslog` 中看不到任何输出。 +这是因为配置文件允许所有必要的系统调用,并指定如果调用列表之外的系统调用应发生错误。 +从安全角度来看,这是一种理想的情况,但需要在分析程序时付出一些努力。 +如果有一种简单的方法可以在不需要太多努力的情况下更接近这种安全性,那就太好了。 + +在转到下一部分之前清理该 Pod 和服务: + +```shell +kubectl delete service fine-pod --wait +kubectl delete pod fine-pod --wait --now +``` + + +## 创建使用容器运行时默认 seccomp 配置文件的 Pod {#create-pod-that-uses-the-container-runtime-default-seccomp-profile} + +大多数容器运行时都提供了一组合理的默认系统调用,以及是否允许执行这些系统调用。 +你可以通过将 Pod 或容器的安全上下文中的 seccomp 类型设置为 `RuntimeDefault` +来为你的工作负载采用这些默认值。 + +{{< note >}} + +如果你已经启用了 `SeccompDefault` [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/), +只要没有指定其他 seccomp 配置文件,那么 Pod 就会使用 `SeccompDefault` 的 seccomp 配置文件。 +否则,默认值为 `Unconfined`。 +{{< /note >}} + + +这是一个 Pod 的清单,它要求其所有容器使用 `RuntimeDefault` seccomp 配置文件: + +{{< codenew file="pods/security/seccomp/ga/default-pod.yaml" >}} + + +创建此 Pod: +```shell +kubectl apply -f https://k8s.io/examples/pods/security/seccomp/ga/default-pod.yaml +``` + +```shell +kubectl get pod default-pod +``` + + +此 Pod 应该显示为成功启动: +``` +NAME READY STATUS RESTARTS AGE +default-pod 1/1 Running 0 20s +``` + + +最后,你看到一切正常之后,请清理: + +```shell +kubectl delete pod default-pod --wait --now +``` + +## {{% heading "whatsnext" %}} + + +你可以了解有关 Linux seccomp 的更多信息: + +* [seccomp 概述](https://lwn.net/Articles/656307/) +* [Docker 的 Seccomp 安全配置文件](https://docs.docker.com/engine/security/seccomp/) \ No newline at end of file