安全上下文定义了 Pod 或容器的特权和访问控制设置。安全上下文设置包括但不限于:
自主访问控制 (DAC):访问对象(如文件)的权限基于 用户 ID (UID) 和组 ID (GID)。
安全增强型 Linux (SELinux):对象被分配了安全标签。
以特权或非特权方式运行。
Linux 能力 (Capabilities):赋予进程某些特权,但并非 root 用户的所有特权。
AppArmor:使用程序配置文件来限制各个程序的能力。
Seccomp:过滤进程的系统调用。
allowPrivilegeEscalation:控制进程是否可以获得比其父进程更多的特权。此布尔值直接控制容器进程是否设置了 no_new_privs 标志。当容器在以下情况时,allowPrivilegeEscalation 始终为 true:
CAP_SYS_ADMINreadOnlyRootFilesystem:将容器的根文件系统挂载为只读。
以上列举并非安全上下文设置的完整集合 —— 请参阅 SecurityContext 获取完整列表。
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。
要检查版本,请输入 kubectl version。
要为 Pod 指定安全设置,需在 Pod 规范中包含 securityContext 字段。securityContext 字段是一个 PodSecurityContext 对象。为 Pod 指定的安全设置将应用于 Pod 中的所有容器。以下是一个包含 securityContext 和 emptyDir 卷的 Pod 配置文件:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
supplementalGroups: [4000]
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox:1.28
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
在配置文件中,runAsUser 字段指定 Pod 中任何容器的所有进程都以用户 ID 1000 运行。runAsGroup 字段指定 Pod 中任何容器内的所有进程的主组 ID 为 3000。如果忽略此字段,容器的主组 ID 将为 root(0)。当指定 runAsGroup 时,创建的任何文件也将归用户 1000 和组 3000 所有。由于指定了 fsGroup 字段,容器的所有进程也都属于补充组 ID 2000。卷 /data/demo 的所有者以及在该卷中创建的任何文件的所有者将是组 ID 2000。此外,当指定 supplementalGroups 字段时,容器的所有进程也都属于指定的组。如果省略此字段,则表示为空。
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml
验证 Pod 的容器正在运行
kubectl get pod security-context-demo
获取运行中容器的 Shell
kubectl exec -it security-context-demo -- sh
在 Shell 中,列出正在运行的进程
ps
输出显示进程以用户 1000 身份运行,这是 runAsUser 的值。
PID USER TIME COMMAND
1 1000 0:00 sleep 1h
6 1000 0:00 sh
...
在 Shell 中,导航到 /data 并列出该目录
cd /data
ls -l
输出显示 /data/demo 目录的组 ID 为 2000,这是 fsGroup 的值。
drwxrwsrwx 2 root 2000 4096 Jun 6 20:08 demo
在 Shell 中,导航到 /data/demo 并创建一个文件
cd demo
echo hello > testfile
列出 /data/demo 目录中的文件
ls -l
输出显示 testfile 的组 ID 为 2000,这是 fsGroup 的值。
-rw-r--r-- 1 1000 2000 6 Jun 6 20:08 testfile
运行以下命令
id
输出类似于此
uid=1000 gid=3000 groups=2000,3000,4000
从输出中,您可以看到 gid 为 3000,与 runAsGroup 字段相同。如果省略了 runAsGroup,gid 将保持为 0 (root),并且该进程将能够与归 root(0) 组所有以及具有 root(0) 组所需权限的组的文件进行交互。您还可以看到 groups 除了包含 gid 外,还包含了由 fsGroup 和 supplementalGroups 指定的组 ID。
退出 Shell
exit
默认情况下,Kubernetes 会将来自 Pod 的组信息与容器镜像中 /etc/group 定义的信息合并。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
containers:
- name: sec-ctx-demo
image: registry.k8s.io/e2e-test-images/agnhost:2.45
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
allowPrivilegeEscalation: false
此 Pod 安全上下文包含 runAsUser、runAsGroup 和 supplementalGroups。但是,您可以看到连接到容器进程的实际补充组将包括来自容器镜像中 /etc/group 的组 ID。
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context-5.yaml
验证 Pod 的容器正在运行
kubectl get pod security-context-demo
获取运行中容器的 Shell
kubectl exec -it security-context-demo -- sh
检查进程身份
id
输出类似于此
uid=1000 gid=3000 groups=3000,4000,50000
您可以看到 groups 包含组 ID 50000。这是因为镜像中定义的该用户 (uid=1000) 属于容器镜像内 /etc/group 中定义的组 (gid=50000)。
检查容器镜像中的 /etc/group
cat /etc/group
您可以看到 uid 1000 属于组 50000。
...
user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image
退出 Shell
exit
Kubernetes v1.33 [beta](默认启用)可以通过为 kubelet 和 kube-apiserver 设置 SupplementalGroupsPolicy 特性门控,并为 Pod 设置 .spec.securityContext.supplementalGroupsPolicy 字段来启用此特性。
supplementalGroupsPolicy 字段定义了用于计算 Pod 中容器进程的补充组的策略。此字段有两个有效值:
Merge:将容器主要用户在 /etc/group 中定义的组成员身份进行合并。如果未指定,这是默认策略。
Strict:仅将 fsGroup、supplementalGroups 或 runAsGroup 字段中的组 ID 作为容器进程的补充组附加。这意味着不会合并容器主要用户在 /etc/group 中的任何组成员身份。
启用该特性后,它还会将附加到第一个容器进程的进程身份公开在 .status.containerStatuses[].user.linux 字段中。这对于检测是否附加了隐式组 ID 很有用。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
supplementalGroupsPolicy: Strict
containers:
- name: sec-ctx-demo
image: registry.k8s.io/e2e-test-images/agnhost:2.45
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
allowPrivilegeEscalation: false
此 Pod 清单定义了 supplementalGroupsPolicy=Strict。您可以看出,/etc/group 中定义的任何组成员身份都不会被合并到容器进程的补充组中。
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context-6.yaml
验证 Pod 的容器正在运行
kubectl get pod security-context-demo
检查进程身份
kubectl exec -it security-context-demo -- id
输出类似于此
uid=1000 gid=3000 groups=3000,4000
查看 Pod 的状态
kubectl get pod security-context-demo -o yaml
您可以看到 status.containerStatuses[].user.linux 字段公开了附加到第一个容器进程的进程身份。
...
status:
containerStatuses:
- name: sec-ctx-demo
user:
linux:
gid: 3000
supplementalGroups:
- 3000
- 4000
uid: 1000
...
status.containerStatuses[].user.linux 字段中的值是容器中第一个容器进程首次附加的进程身份。如果容器拥有足够的特权来进行与进程身份相关的系统调用(例如 setuid(2)、setgid(2) 或 setgroups(2) 等),容器进程可以更改其身份。因此,实际的进程身份将是动态的。已知以下容器运行时支持细粒度的 SupplementalGroups 控制。
CRI 级别
您可以在节点状态中查看是否支持该特性。
apiVersion: v1
kind: Node
...
status:
features:
supplementalGroupsPolicy: true
在此 alpha 版本(从 v1.31 到 v1.32)中,当带有 SupplementalGroupsPolicy=Strict 的 Pod 被调度到不支持此特性的节点(即 .status.features.supplementalGroupsPolicy=false)时,Pod 的补充组策略会静默回退到 Merge 策略。
然而,自 beta 版本 (v1.33) 起,为了更严格地执行该策略,此类 Pod 的创建将被 kubelet 拒绝,因为节点无法确保所指定的策略。当您的 Pod 被拒绝时,您会看到如下所示的 reason=SupplementalGroupsPolicyNotSupported 的警告事件:
apiVersion: v1
kind: Event
...
type: Warning
reason: SupplementalGroupsPolicyNotSupported
message: "SupplementalGroupsPolicy=Strict is not supported in this node"
involvedObject:
apiVersion: v1
kind: Pod
...
Kubernetes v1.23 [稳定]默认情况下,当挂载卷时,Kubernetes 会递归地更改每个卷内容的所有权和权限,以匹配 Pod 的 securityContext 中指定的 fsGroup。对于大容量卷,检查和更改所有权和权限可能非常耗时,从而导致 Pod 启动变慢。您可以使用 securityContext 中的 fsGroupChangePolicy 字段来控制 Kubernetes 检查和管理卷所有权和权限的方式。
fsGroupChangePolicy - fsGroupChangePolicy 定义了在 Pod 内挂载卷之前更改所有权和权限的行为。此字段仅适用于支持 fsGroup 控制所有权和权限的卷类型。此字段有两个可能的值:
例如
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
fsGroupChangePolicy: "OnRootMismatch"
Kubernetes v1.26 [稳定]如果您部署了一个支持 VOLUME_MOUNT_GROUP NodeServiceCapability 的 容器存储接口 (CSI) 驱动程序,则基于 securityContext 中指定的 fsGroup 设置文件所有权和权限的过程将由 CSI 驱动程序而不是 Kubernetes 执行。在这种情况下,由于 Kubernetes 不执行任何所有权和权限更改,fsGroupChangePolicy 不会生效;根据 CSI 的规定,驱动程序应使用提供的 fsGroup 挂载卷,从而生成一个可由 fsGroup 读取/写入的卷。
要为容器指定安全设置,请在容器清单中包含 securityContext 字段。securityContext 字段是一个 SecurityContext 对象。为容器指定安全设置仅适用于该单个容器,并且在重叠时会覆盖 Pod 级别的设置。容器设置不会影响 Pod 的卷。
以下是一个包含单个容器的 Pod 的配置文件。Pod 和容器都具有 securityContext 字段:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo-2
image: gcr.io/google-samples/hello-app:2.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml
验证 Pod 的容器正在运行
kubectl get pod security-context-demo-2
获取运行中容器的 Shell
kubectl exec -it security-context-demo-2 -- sh
在 Shell 中,列出正在运行的进程
ps aux
输出显示进程以用户 2000 身份运行。这是为容器指定的 runAsUser 值。它覆盖了为 Pod 指定的值 1000。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
2000 1 0.0 0.0 4336 764 ? Ss 20:36 0:00 /bin/sh -c node server.js
2000 8 0.1 0.5 772124 22604 ? Sl 20:36 0:00 node server.js
...
退出 Shell
exit
通过 Linux 能力 (Capabilities),您可以授予进程某些特权,而不必授予 root 用户的所有特权。要添加或删除容器的 Linux 能力,请在容器清单的 securityContext 部分中包含 capabilities 字段。
首先,看看如果不包含 capabilities 字段会发生什么。这是一个不添加或删除任何容器能力的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-3
spec:
containers:
- name: sec-ctx-3
image: gcr.io/google-samples/hello-app:2.0
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml
验证 Pod 的容器正在运行
kubectl get pod security-context-demo-3
获取运行中容器的 Shell
kubectl exec -it security-context-demo-3 -- sh
在 Shell 中,列出正在运行的进程
ps aux
输出显示了容器的进程 ID (PID)
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4336 796 ? Ss 18:17 0:00 /bin/sh -c node server.js
root 5 0.1 0.5 772124 22700 ? Sl 18:17 0:00 node server.js
在 Shell 中,查看进程 1 的状态
cd /proc/1
cat status
输出显示了该进程的能力位图
...
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
...
记下该能力位图,然后退出 Shell
exit
接下来,运行一个与上述容器相同的容器,只是它设置了额外的能力。
以下是一个运行单个容器的 Pod 的配置文件。该配置添加了 CAP_NET_ADMIN 和 CAP_SYS_TIME 能力:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-4
image: gcr.io/google-samples/hello-app:2.0
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml
获取运行中容器的 Shell
kubectl exec -it security-context-demo-4 -- sh
在 Shell 中,查看进程 1 的能力
cd /proc/1
cat status
输出显示了进程的能力位图
...
CapPrm: 00000000aa0435fb
CapEff: 00000000aa0435fb
...
比较两个容器的能力
00000000a80425fb
00000000aa0435fb
在第一个容器的能力位图中,第 12 位和第 25 位是清除的。在第二个容器中,第 12 位和第 25 位被设置。第 12 位是 CAP_NET_ADMIN,第 25 位是 CAP_SYS_TIME。有关能力常数的定义,请参见 capability.h。
CAP_XXX 的形式。但在容器清单中列出能力时,必须省略常数的 CAP_ 部分。例如,要添加 CAP_SYS_TIME,请在能力列表中包含 SYS_TIME。要设置容器的 Seccomp 配置文件,请在 Pod 或容器清单的 securityContext 部分中包含 seccompProfile 字段。seccompProfile 字段是一个 SeccompProfile 对象,由 type 和 localhostProfile 组成。type 的有效选项包括 RuntimeDefault、Unconfined 和 Localhost。仅当 type: Localhost 时才必须设置 localhostProfile。它表示节点上预配置配置文件的路径,相对于 kubelet 配置的 Seccomp 配置文件位置(通过 --root-dir 标志配置)。
以下是将 Seccomp 配置文件设置为节点容器运行时默认配置文件的示例:
...
securityContext:
seccompProfile:
type: RuntimeDefault
以下是将 Seccomp 配置文件设置为 <kubelet-root-dir>/seccomp/my-profiles/profile-allow.json 处预配置文件的示例:
...
securityContext:
seccompProfile:
type: Localhost
localhostProfile: my-profiles/profile-allow.json
要为容器设置 AppArmor 配置文件,请在容器的 securityContext 部分中包含 appArmorProfile 字段。appArmorProfile 字段是一个 AppArmorProfile 对象,由 type 和 localhostProfile 组成。type 的有效选项包括 RuntimeDefault(默认)、Unconfined 和 Localhost。仅当 type 为 Localhost 时才必须设置 localhostProfile。它表示节点上预配置配置文件的名称。该配置文件需要加载到所有适合 Pod 的节点上,因为您不知道 Pod 将被调度到哪里。设置自定义配置文件的方法在 设置具有配置文件的节点 中进行了讨论。
注意:如果 containers[*].securityContext.appArmorProfile.type 被明确设置为 RuntimeDefault,那么如果节点上未启用 AppArmor,Pod 将无法被准入。但是,如果未指定 containers[*].securityContext.appArmorProfile.type,则仅在节点启用 AppArmor 时才会应用默认值(也是 RuntimeDefault)。如果节点禁用了 AppArmor,Pod 将被准入,但容器不会受到 RuntimeDefault 配置文件的限制。
以下是将 AppArmor 配置文件设置为节点容器运行时默认配置文件的示例:
...
containers:
- name: container-1
securityContext:
appArmorProfile:
type: RuntimeDefault
以下是将 AppArmor 配置文件设置为名为 k8s-apparmor-example-deny-write 的预配置配置文件的示例:
...
containers:
- name: container-1
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: k8s-apparmor-example-deny-write
更多详细信息,请参阅 使用 AppArmor 限制容器对资源的访问。
要为容器分配 SELinux 标签,请在 Pod 或容器清单的 securityContext 部分中包含 seLinuxOptions 字段。seLinuxOptions 字段是一个 SELinuxOptions 对象。以下是应用 SELinux 级别的示例:
...
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
Kubernetes v1.36 [stable](默认启用)Kubernetes v1.27 引入了一种早期的受限行为,仅适用于使用 ReadWriteOncePod 访问模式的卷(以及 PersistentVolumeClaims)。
Kubernetes v1.36 将 SELinuxChangePolicy 和 SELinuxMount 特性门控 提升为 GA,以将该性能改进扩展到其他类型的 PersistentVolumeClaims,详见下文。SELinuxMount 默认仍处于禁用状态。
在 SELinuxMount 特性门控被禁用的情况下(Kubernetes 1.36 及之前版本的默认设置),容器运行时默认会递归地为所有 Pod 卷上的所有文件分配 SELinux 标签。为了加速此过程,Kubernetes 可以通过使用挂载选项 -o context=<label> 立即更改卷的 SELinux 标签。
要从这种加速中受益,必须满足以下所有条件:
accessModes 和 特性门控 的 PersistentVolumeClaim。accessModes: ["ReadWriteOncePod"]。SELinuxMount 特性门控,且 Pod 的 spec.securityContext.seLinuxChangePolicy 为 nil(默认)或 MountOption。seLinuxOptions。iscsi、rbd 或 fc 卷类型的卷。spec.seLinuxMount: true 来声明其支持使用 -o context 进行挂载。当不满足上述任何条件时,SELinux 重打标签将以另一种方式发生:容器运行时递归地更改卷中所有 inode(文件和目录)的 SELinux 标签。明确指出,这适用于 Kubernetes 临时卷(如 secret、configMap 和 projected)以及所有其 CSIDriver 实例未明确声明使用 -o context 进行挂载的卷。
当使用此加速时,在同一节点上同时使用相同适用卷的所有 Pod 必须具有相同的 SELinux 标签。具有不同 SELinux 标签的 Pod 将无法启动,并会处于 ContainerCreating 状态,直到删除所有使用该卷且具有不同 SELinux 标签的 Pod 为止。
Kubernetes v1.36 [stable](默认启用)spec.securityContext.seLinuxChangePolicy 设置为 Recursive。当多个 Pod 在同一节点上共享单个卷,但它们运行的 SELinux 标签允许同时访问该卷时,这是必需的。例如,运行在标签 spc_t 下的特权 Pod 和运行在默认标签 container_file_t 下的非特权 Pod。当 spec.securityContext.seLinuxChangePolicy 未设置(或使用默认值 MountOption)时,此类 Pod 中只有一个能够在节点上运行,另一个会因 conflicting SELinux labels of volume <卷名>: <运行中 Pod 的标签> and <无法启动的 Pod 的标签> 错误而处于 ContainerCreating 状态。为了更容易识别受 SELinux 卷重打标签变更影响的 Pod,kube-controller-manager 中引入了一个名为 SELinuxWarningController 的新控制器。它默认禁用,可以通过设置 --controllers=*,selinux-warning-controller 命令行标志,或在 KubeControllerManagerConfiguration 中设置 genericControllerManagerConfiguration.controllers 字段 来启用。此控制器要求启用 SELinuxChangePolicy 特性门控。
启用后,该控制器会观察正在运行的 Pod,当它检测到两个 Pod 使用相同的卷且具有不同的 SELinux 标签时:
kubectl describe pod <pod名> 显示 SELinuxLabel "<Pod上的标签>" 与使用相同卷且带有 SELinuxLabel "<另一个Pod的标签>" 的 Pod <另一个Pod名> 冲突。如果两个 Pod 落在同一节点上,只有一个 Pod 可以访问该卷。selinux_warning_controller_selinux_volume_conflict 指标。该指标包含 Pod 名 + 命名空间作为标签,以便轻松识别受影响的 Pod。集群管理员可以使用此信息识别受计划变更影响的 Pod,并主动让 Pod 选择不使用此优化(即设置 spec.securityContext.seLinuxChangePolicy: Recursive)。
SELinuxMount 特性门控或升级到默认启用 SELinuxMount 的版本之前,selinux_warning_controller_selinux_volume_conflict 指标不报告任何冲突。以下特性门控控制 SELinux 卷重打标签的行为:
SELinuxMountReadWriteOncePod:为具有 accessModes: ["ReadWriteOncePod"] 的卷启用此优化。这是一个非常安全的特性门控,因为不可能出现两个 Pod 共享一个卷的情况。此特性门控自 1.28 起默认启用,并在 1.36 中达到 GA。SELinuxChangePolicy:在 Pod 中启用 spec.securityContext.seLinuxChangePolicy 字段,并在 kube-controller-manager 中启用相关的 SELinuxWarningController。此特性可在启用 SELinuxMount 之前用于检查集群上运行的 Pod,并主动让 Pod 选择不使用该优化。此特性门控要求启用 SELinuxMountReadWriteOncePod。它是 beta 版本,自 1.33 起默认启用,在 1.36 中达到 GA。SELinuxMount:为所有符合条件的卷启用此优化。由于它可能会破坏现有工作负载,我们建议先启用 SELinuxChangePolicy 特性门控 + SELinuxWarningController 来检查变更的影响。此特性门控要求启用 SELinuxMountReadWriteOncePod 和 SELinuxChangePolicy。它是 beta 版本,但在 1.33 中默认禁用。Kubernetes v1.36 [stable](默认启用)对于遵循 OCI 运行时规范的运行时,容器默认以一种存在多个被屏蔽 (masked) 且只读路径的模式运行。结果是,容器在容器的挂载命名空间内存在这些路径,它们的功能类似于容器是一个隔离的主机,但容器进程无法写入它们。屏蔽和只读路径列表如下:
屏蔽路径
/proc/asound/proc/acpi/proc/kcore/proc/keys/proc/latency_stats/proc/timer_list/proc/timer_stats/proc/sched_debug/proc/scsi/sys/firmware/sys/devices/virtual/powercap只读路径
/proc/bus/proc/fs/proc/irq/proc/sys/proc/sysrq-trigger对于某些 Pod,您可能希望绕过默认的路径屏蔽。想要这样做的最常见场景是如果您试图在 Kubernetes 容器内(Pod 内)运行容器。
securityContext 字段 procMount 允许用户请求将容器的 /proc 设置为 Unmasked,或者将其挂载为容器进程可读写。这也适用于不在 /proc 中的 /sys/firmware。
...
securityContext:
procMount: Unmasked
procMount 设置为 Unmasked 需要 Pod 规范中的 spec.hostUsers 值为 false。换句话说:希望拥有 Unmasked /proc 或 unmasked /sys 的容器也必须处于 用户命名空间 中。Kubernetes v1.12 到 v1.29 未强制执行此要求。Pod 的安全上下文适用于 Pod 的容器,并在适用时也适用于 Pod 的卷。具体来说,fsGroup 和 seLinuxOptions 在卷上的应用方式如下:
fsGroup:支持所有权管理的卷会被修改为归 fsGroup 中指定的 GID 所有且可写。更多详细信息,请参阅 所有权管理设计文档。
seLinuxOptions:支持 SELinux 标签的卷会被重打标签,以便可由 seLinuxOptions 下指定的标签访问。通常您只需要设置 level 部分。这为 Pod 中的所有容器以及卷设置了 多类别安全 (MCS) 标签。
删除 Pod
kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4