阶段二 · 密钥与供应链安全

策略即代码

一句话总结

安全规则写在文档里会被忽略, 写在代码里才会被执行.
策略即代码(Policy as Code)用声明式策略定义"什么是合规的", 由准入控制器自动拦截违规资源, 从"事后审计"变为"事前阻止".

为什么需要策略即代码

前几篇讲的安全配置(非 root, drop capabilities, NetworkPolicy...), 如何确保每个团队, 每个 Deployment 都遵守?

方式 问题
写文档 + 培训 人会忘, 会犯错, 新人不知道
Code Review 检查 YAML 变更容易遗漏安全字段
事后审计 违规资源已经在跑了, 发现时已经有风险
准入控制自动拦截 违规资源根本创建不出来

文档规定"不许闯红灯" vs 路口装了自动拦截栏杆.
前者靠人的自觉(总有人闯), 后者靠机制保证(物理上过不去).
策略即代码 = 给 K8s 集群装自动拦截栏杆.

Kyverno

Kyverno 是 K8s 原生的策略引擎, 用 YAML 定义策略(而非 Rego 这类专用语言), 学习成本极低.

策略类型

类型 作用 示例
Validate 校验资源是否合规 拒绝 privileged 容器
Mutate 自动修改资源 自动注入 securityContext 默认值
Generate 自动创建关联资源 新 Namespace 自动创建 NetworkPolicy
VerifyImages 验证镜像签名 拒绝未签名镜像

常见策略示例

# 1. 禁止 privileged 容器
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged
spec:
validationFailureAction: Enforce # Enforce=拒绝, Audit=只记录
rules:
- name: deny-privileged
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "Privileged containers are not allowed."
pattern:
spec:
containers:
- securityContext:
privileged: "false"
# 2. 禁止使用 latest tag
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce
rules:
- name: deny-latest
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "Using ':latest' tag is not allowed. Use a specific version."
pattern:
spec:
containers:
- image: "!*:latest"
# 3. 强制设置 resource limits
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce
rules:
- name: check-limits
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "CPU and memory limits are required."
pattern:
spec:
containers:
- resources:
limits:
memory: "?*"
cpu: "?*"
# 4. Mutate: 自动注入安全默认值
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-default-security-context
spec:
rules:
- name: add-security-defaults
match:
any:
- resources:
kinds: ["Pod"]
mutate:
patchStrategicMerge:
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
# 5. Generate: 新 Namespace 自动创建 default-deny NetworkPolicy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-default-deny-networkpolicy
spec:
rules:
- name: generate-netpol
match:
any:
- resources:
kinds: ["Namespace"]
generate:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
name: default-deny-ingress
namespace: "{{request.object.metadata.name}}"
data:
spec:
podSelector: {}
policyTypes:
- Ingress

OPA / Gatekeeper

OPA(Open Policy Agent)是通用策略引擎, Gatekeeper 是 OPA 的 K8s 准入控制器适配层. 用 Rego 语言编写策略.

OPA/Gatekeeper vs Kyverno

Kyverno OPA/Gatekeeper
策略语言 YAML(K8s 原生) Rego(专用语言)
学习曲线 低(会写 K8s YAML 就行) 高(需要学 Rego)
验证+变异+生成 全支持 主要做验证(变异有限)
镜像签名验证 内置 VerifyImages 需要额外组件
生态广度 K8s 专用 可用于 Terraform/CI/API 等多场景
适用场景 K8s 安全策略(大多数团队首选) 多平台统一策略, 复杂逻辑

选择建议

只做 K8s 准入策略 → Kyverno(简单直观, 功能完整).
需要跨平台策略(K8s + Terraform + CI pipeline)或复杂计算逻辑 → OPA/Gatekeeper.

两者不冲突, 可以共存.

Gatekeeper 示例

# ConstraintTemplate 定义策略模板
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("Missing required labels: %v", [missing])
}

---
# Constraint 实例化策略
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
labels: ["team", "env"]

合规基线

不需要从零开始写策略, 社区有现成的安全基线可以直接采用:

基线 来源 覆盖
Pod Security Standards K8s 官方 Pod 安全最低要求
Kyverno Best Practices Kyverno 社区 30+ 开箱即用的生产策略
CIS Kubernetes Benchmark CIS 完整的集群安全基线(200+ 检查项)
NSA/CISA K8s Hardening Guide 美国 NSA K8s 安全加固最佳实践
# 安装 Kyverno 社区策略库
$ helm repo add kyverno https://kyverno.github.io/kyverno
$ helm install kyverno kyverno/kyverno -n kyverno --create-namespace
$ helm install kyverno-policies kyverno/kyverno-policies -n kyverno \
--set podSecurityStandard=restricted # 直接启用 restricted 级别所有策略

策略测试与 CI 集成

策略测试

策略也是代码, 需要测试. Kyverno CLI 支持离线测试:

# 测试策略: 给一个违规的 YAML 是否被正确拒绝
$ kyverno apply policy.yaml --resource bad-pod.yaml
# 输出: FAIL - Privileged containers are not allowed.

# 测试策略: 给一个合规的 YAML 是否被正确放行
$ kyverno apply policy.yaml --resource good-pod.yaml
# 输出: PASS

CI Pipeline 集成

# GitHub Actions: PR 中自动检查 K8s YAML 合规性
- name: Test Kyverno policies
run: |
kyverno apply policies/ --resource k8s/*.yaml
if [ $? -ne 0 ]; then
echo "Policy violation detected!"
exit 1
fi

左移安全(Shift Left)

在 CI 中验证策略 = 开发阶段就发现违规, 而非等到部署被 Admission Webhook 拒绝才知道出了问题.

CI 报错 → 开发者本地修复 → 再次提交. 体验远好于"kubectl apply 被拒绝然后手忙脚乱".

策略部署策略

  1. Audit 模式起步: 先 validationFailureAction: Audit, 只记录不拦截, 收集违规数据
  2. 修复存量违规: 根据审计报告逐个修复不合规的 Deployment
  3. 切换 Enforce: 确认无误后切为拦截模式
  4. 持续监控: 监控策略触发次数, 新策略总是先 Audit

快速回顾

  • 策略即代码: 安全规则声明式定义 + 准入控制器自动执行, 从"靠人"变为"靠机制"
  • Kyverno: K8s 原生 YAML 策略, 支持 Validate / Mutate / Generate / VerifyImages
  • OPA/Gatekeeper: Rego 语言, 适合复杂逻辑和多平台统一策略
  • 合规基线: CIS Benchmark / PSS / Kyverno Policies 开箱即用
  • 策略测试: kyverno CLI 离线测试 + CI 集成 = 左移安全
  • 渐进部署: Audit → 修复 → Enforce, 不要一上来就拦截

动手练习

  1. Kyverno 基础策略: 安装 Kyverno, 部署"禁止 privileged 容器"策略(Enforce 模式), 尝试创建 privileged Pod 验证被拒绝
  2. Validate 策略编写: 编写一条 Kyverno 策略要求所有 Deployment 必须有 team label, 先用 Audit 模式观察现有违规
  3. Mutate 策略编写: 编写 Mutate 策略, 自动为没有设置 securityContext 的 Pod 注入 runAsNonRoot: true
  4. Generate 策略编写: 编写 Generate 策略, 每创建一个新 Namespace 自动生成 default-deny NetworkPolicy + ResourceQuota
  5. CI 集成测试: 用 kyverno apply 命令在 CI 中验证 K8s YAML 是否合规