欢迎光临
我们一直在努力

K8s 安全策略:从集群加固到零信任落地的生产实践

K8s 安全策略:从集群加固到零信任落地的生产实践

一、当集群裸奔遇上真实攻击:安全防线的第一课

去年我们集群遭遇了一次容器逃逸事件。攻击者通过一个未限制特权的 Pod,拿到宿主机的 root 权限,横向移动到 etcd 节点。整个排查过程持续 4 小时,业务中断波及 3 个核心服务。那次事故之后,我把 K8s 安全策略从"有空再说"提升到"上线前必审"。

K8s 默认配置的安全水位非常低。Pod 可以挂载宿主机路径、运行特权容器、甚至直接访问 kubelet API。很多团队上线只关注功能跑通,安全策略几乎为零。等出事了再补,代价远超预期。

安全策略的核心思路是:最小权限 + 纵深防御。不是加一道墙就完事,而是从集群准入、运行时隔离、网络分段到审计追踪,每一层都要有防线。

二、K8s 安全机制全景:从 API 到运行时的多层防护

K8s 安全不是单一组件的事,它横跨多个层次。下面这张图梳理了核心防护链路:

graph TD
A[用户/CI 请求] –> B[API Server 认证]
B –> C[RBAC 授权]
C –> D[Admission Controller]
D –> E{策略校验}
E –>|通过| F[Scheduler 调度]
E –>|拒绝| G[拒绝创建]
F –> H[Pod 运行时]
H –> I[SecurityContext 隔离]
H –> J[NetworkPolicy 分段]
H –> K[PodSecurityPolicy/PSS]
I –> L[审计日志]
J –> L
K –> L
L –> M[安全运营中心]

关键机制拆解:

1. RBAC:权限的第一道门

RBAC 控制"谁能做什么"。生产环境必须禁用 cluster-admin 绑定给 ServiceAccount 的做法。每个应用只授予需要的权限,按 namespace 隔离。

2. Admission Controller:准入拦截

这是策略执行的核心入口。PodSecurity(替代已废弃的 PSP)、LimitRanger、自定义 Webhook 都在这里工作。所有 Pod 创建请求必须经过策略校验。

3. SecurityContext:运行时隔离

控制 Pod 内进程的权限边界。runAsNonRoot、readOnlyRootFilesystem、allowPrivilegeEscalation: false 这三项是生产环境必须配置的。

4. NetworkPolicy:网络分段

默认 K8s 网络是全通的。必须用 NetworkPolicy 实现 namespace 级别和 Pod 级别的微隔离。

三、生产级安全策略实现:从 OPA 到完整配置

3.1 OPA Gatekeeper 策略引擎部署

# gatekeeper-values.yaml – 生产级 Helm 配置
replicas: 3
auditInterval: 60
auditMatchKindOnly: true
constraintViolationsLimit: 20
emitAuditEvents: true
emitAdmissionEvents: true

resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "200m"
memory: "256Mi"

# 审计日志持久化
auditChunkSize: 500
logLevel: INFO

3.2 核心安全约束模板

# 禁止特权容器 – ConstraintTemplate
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdenyprivileged
spec:
crd:
spec:
names:
kind: K8sDenyPrivileged
targets:
– target: admission.k8s.gatekeeper.sh
rego: |
package k8sdenyprivileged
# 拦截所有特权容器创建请求
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("禁止特权容器: %v", [container.name])
}
# 同时检查 initContainers
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("禁止特权 initContainer: %v", [container.name])
}

# 应用约束 – 对所有 namespace 生效
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyPrivileged
metadata:
name: deny-privileged-containers
spec:
match:
kinds:
– apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces:
– kube-system
– gatekeeper-system

3.3 Pod 安全基线配置

# security-baseline.yaml – 生产环境 Pod 安全标准
apiVersion: v1
kind: Pod
metadata:
name: secure-app
annotations:
# 强制使用 Pod Security Standards 的 restricted 级别
pod-security.kubernetes.io/enforce: "restricted"
pod-security.kubernetes.io/audit: "restricted"
pod-security.kubernetes.io/warn: "restricted"
spec:
serviceAccountName: app-sa
automountServiceAccountToken: false # 不自动挂载 token
securityContext:
runAsNonRoot: true # 禁止 root 运行
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault # 使用默认 seccomp 配置
containers:
– name: app
image: app:1.0.0
securityContext:
allowPrivilegeEscalation: false # 禁止提权
readOnlyRootFilesystem: true # 只读根文件系统
capabilities:
drop:
– ALL # 丢弃所有 Linux capabilities
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
– name: tmp
mountPath: /tmp
– name: cache
mountPath: /app/cache
volumes:
– name: tmp
emptyDir: {}
– name: cache
emptyDir:
medium: Memory
sizeLimit: "64Mi"

3.4 NetworkPolicy 微隔离

# 网络分段策略 – 前端只访问后端,后端只访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes:
– Ingress
ingress:
– from:
– podSelector:
matchLabels:
tier: frontend
ports:
– protocol: TCP
port: 8080

# 默认拒绝所有出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
– Egress

3.5 RBAC 最小权限配置

# 应用专用 ServiceAccount – 只授予必要权限
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: production
automountServiceAccountToken: false

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-config-reader
namespace: production
rules:
– apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"] # 限定具体资源名
verbs: ["get", "list"]
– apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-secrets"]
verbs: ["get"]

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-config-reader-binding
namespace: production
subjects:
– kind: ServiceAccount
name: app-sa
roleRef:
kind: Role
name: app-config-reader
apiGroup: rbac.authorization.k8s.io

四、安全策略的代价:性能开销与运维复杂度权衡

安全不是免费的。每一层策略都有成本,需要根据业务场景做取舍。

Admission Webhook 的延迟开销

OPA Gatekeeper 在每次 Pod 创建时都会触发 Webhook 调用。实测在集群规模 500+ Pod 时,准入延迟增加 15-30ms。对于 CI/CD 流水线中批量创建 Pod 的场景,这个延迟会被放大。解决方案:开启 Gatekeeper 的缓存和审计模式分离,准入路径只做同步校验,复杂策略放到审计路径异步检查。

NetworkPolicy 的 CNI 兼容性

不是所有 CNI 都完整支持 NetworkPolicy。Calico 和 Cilium 支持最好,Flannel 基本不支持。如果团队用的是 Flannel,网络隔离等于零。切换 CNI 的迁移成本很高,需要提前规划。

readOnlyRootFilesystem 的适配成本

很多应用会往 /etc、/var 写临时文件。开启只读根文件系统后,必须用 emptyDir 或 hostPath 挂载可写路径。这个改造工作量不小,尤其是第三方镜像。建议分阶段推进:先在新服务强制要求,老服务逐步改造。

RBAC 权限收敛的运维负担

最小权限意味着每个应用都要单独定义 Role 和 RoleBinding。在多团队协作的集群里,权限配置的维护成本很高。推荐用命名约定 + 模板化工具(如 Kyverno)降低重复劳动。

安全策略与开发效率的矛盾

过严的策略会拖慢开发节奏。比如禁止 hostPath 挂载后,本地开发调试变得困难。我们的做法是区分环境:开发集群策略宽松,预发和生产集群严格执行。通过 namespace label 区分策略等级。

五、总结

K8s 安全策略不是一蹴而就的,它是一个持续演进的过程。核心原则就三条:最小权限、纵深防御、分层审计。

落地路线建议:

  • 第一阶段(1-2 周):开启 Pod Security Standards 的 baseline 级别,配置 RBAC 最小权限,部署 NetworkPolicy 默认拒绝规则
  • 第二阶段(2-4 周):引入 OPA Gatekeeper,实现自定义准入策略,完成 SecurityContext 基线配置
  • 第三阶段(持续):接入审计日志到安全运营平台,建立策略变更的 CI 流程,定期做安全扫描和渗透测试
  • 安全策略的价值不在于拦截了多少攻击,而在于缩小了爆炸半径。当某个容器被攻破时,策略能把影响控制在单个 Pod 内,而不是整个集群。这才是生产环境真正需要的安全水位。

    赞(0)
    未经允许不得转载:171主机测评 » K8s 安全策略:从集群加固到零信任落地的生产实践
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址