作为云原生环境的核心组件,Kubernetes(K8s)的安全性至关重要。容器默认以 Root 用户(UID 0)运行是K8s环境中最常见的安全隐患之一。一旦容器被攻破,攻击者可能利用 Root 权限在宿主机上执行恶意操作。
本文将聚焦两个最基础且必要的 K8s 安全加固措施:禁用 Root 容器的运行,以及利用 PodSecurityPolicy (PSP) 强制执行安全基线。
1. 禁用 Root 容器:最小权限原则的实践
最小权限原则要求应用程序以完成任务所需的最低权限运行。对于容器而言,这意味着应避免使用 Root 用户(UID 0)。
1.1 在 Dockerfile 中定义非 Root 用户
最佳实践是在构建容器镜像时就定义一个专用的非 Root 用户,并确保后续进程都以该用户身份运行。
# Dockerfile 示例:创建并使用非 Root 用户
FROM alpine:latest
# 1. 创建非 Root 用户和组
RUN addgroup -S appgroup && adduser -S appuser -G appgroup -u 1000
# 2. 设置工作目录权限
WORKDIR /app
RUN chown -R appuser:appgroup /app
# 3. 切换到非 Root 用户
USER appuser
# 4. 运行应用程序
CMD ["/bin/sh"]
1.2 在 Pod 配置中强制执行非 Root 运行
即使镜像中定义了非 Root 用户,我们仍然应该在 Pod 或 Deployment 的配置中明确禁止 Root 权限,以防止配置错误或覆盖。
通过设置 securityContext 中的 runAsNonRoot: true 和 runAsUser 可以实现这一点:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-non-root-app
spec:
selector:
matchLabels:
app: non-root
template:
metadata:
labels:
app: non-root
spec:
# 在 Pod 级别设置安全上下文
securityContext:
# 强制容器不能以 UID 0 (Root) 运行
runAsNonRoot: true
# 明确指定运行的用户 ID (必须是非 0)
runAsUser: 1000
fsGroup: 1000
containers:
- name: my-container
image: my-secure-image:latest
ports:
- containerPort: 8080
2. 开启 PodSecurityPolicy (PSP) 的必要性
虽然在应用配置中手动添加 securityContext 是一个好习惯,但在大型集群中很难保证所有开发人员都能遵守。PodSecurityPolicy (PSP) 是一种集群级别的准入控制器(Admission Controller),用于设置 Pod 必须满足的安全条件,否则 K8s API Server 将拒绝创建该 Pod。
重要提示: PodSecurityPolicy (PSP) 在 Kubernetes v1.21 中被标记为废弃 (Deprecated),并在 v1.25 中被移除。对于新部署的集群,推荐使用其替代品 Pod Security Admission (PSA)。但对于运行在旧版本或过渡阶段的集群,PSP 仍是强大的安全控制工具。
2.1 启用 PSP 准入控制器
在 K8s API Server 的启动参数中,需要确保 PodSecurityPolicy 已经被列在 –enable-admission-plugins 中。
2.2 定义严格的 PSP 策略
以下是一个限制性的 PSP 示例,它强制要求容器不能以 Root 身份运行,并禁用特权模式。
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-non-root-policy
spec:
# 1. 禁止特权容器
privileged: false
# 2. 禁止权限提升
allowPrivilegeEscalation: false
# 3. 强制运行用户规则:必须是非 Root
runAsUser:
rule: 'MustRunAsNonRoot'
# 4. 限制卷类型 (防止挂载主机目录)
volumes:
- 'configMap'
- 'secret'
- 'emptyDir'
- 'persistentVolumeClaim'
- 'projected'
# 5. 强制删除所有 Linux Capabilities
requiredDropCapabilities:
- ALL
# 6. 使用默认的 Seccomp 配置文件
seccompProfile:
rule: 'RuntimeDefault'
2.3 授权 PSP 给用户或服务账号
定义了 PSP 之后,还需要通过 Role/ClusterRole 和 RoleBinding/ClusterRoleBinding 将该策略绑定到特定的用户、组或 ServiceAccount 上,使其生效。
步骤 A: 定义 ClusterRole 引用 PSP
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: psp:restricted-non-root
rules:
- apiGroups:
- policy
resources:
- podsecuritypolicies
# PSP 名称必须与上面定义的 PSP 名称一致
resourceNames:
- restricted-non-root-policy
verbs:
- use
步骤 B: 绑定 ClusterRole 到 ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: default-restricted-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: psp:restricted-non-root
subjects:
- kind: ServiceAccount
name: default
namespace: default
完成以上配置后,在 default 命名空间中,任何尝试创建不满足 restricted-non-root-policy 规则的 Pod 都将被 K8s API Server 拒绝,从而大幅提升集群的整体安全性。
汤不热吧