Kubernetes 安全加固
大约 12 分钟约 3621 字
Kubernetes 安全加固
简介
Kubernetes 安全是一个纵深防御(Defense in Depth)体系,涵盖从集群基础设施到应用工作负载的各个层面。由于 Kubernetes 集群通常运行着企业的核心业务应用,一旦被攻破,影响范围巨大。安全加固不是一次性工作,而是贯穿集群生命周期全过程的持续实践。
Kubernetes 安全涉及多个维度:容器镜像安全、Pod 安全策略、网络隔离、身份认证与授权、Secret 管理、审计日志等。本文将系统地介绍 Kubernetes 安全的各个方面,提供可操作的加固方案。
特点
- 纵深防御:多层安全机制相互配合
- 最小权限:遵循最小权限原则配置 RBAC 和 Security Context
- 默认安全:通过安全策略确保默认配置安全
- 可观测:完善的审计和监控机制
- 持续合规:定期扫描和合规检查
Pod 安全标准(Pod Security Standards)
三个安全策略级别
Pod 安全标准级别:
Privileged(特权)
├── 不受限制
├── 适用于系统级工作负载(如 CNI 插件、日志采集)
└── 不推荐用于普通业务 Pod
Baseline(基线)
├── 禁止明显的提权行为
├── 不允许 hostPath、hostNetwork、privileged
└── 适用于大多数标准工作负载
Restricted(受限)
├── 严格限制
├── 强制 drop ALL capabilities
├── 必须以非 root 运行
├── 只读根文件系统
└── 适用于安全敏感的工作负载Pod Security Admission 配置
# Pod Security Admission 配置
# 保存为 pod-security-admission.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: "baseline"
enforce-version: "latest"
audit: "restricted"
audit-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
usernames: []
runtimeClasses: []
namespaces:
- kube-system
- cattle-system# 命名空间级别配置 Pod 安全标准
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.29
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.29
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.29
---
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.29
---
apiVersion: v1
kind: Namespace
metadata:
name: system-components
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/enforce-version: v1.29安全的 Pod 配置示例
# 符合 Restricted 标准的 Pod 配置
apiVersion: v1
kind: Pod
metadata:
name: secure-application
namespace: production
labels:
app: myapp
spec:
# 使用 Security Context
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 8080
# 容器级别安全上下文
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# 资源限制(防止资源耗尽攻击)
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
# 健康检查
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# 环境变量不包含敏感信息
env:
- name: LOG_LEVEL
value: "Information"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# 挂载 tmpfs 用于临时文件(因为根文件系统只读)
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: "64Mi"
- name: cache
emptyDir:
sizeLimit: "128Mi"
# 优先使用镜像摘要而非标签
# image: myapp@sha256:abc123...网络策略(Network Policies)
基础网络隔离
# 默认拒绝所有入站和出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # 选择所有 Pod
policyTypes:
- Ingress
- Egress# 允许同命名空间内的通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: production# 前端到后端的精确网络策略
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
namespaceSelector:
matchLabels:
name: production
ports:
- protocol: TCP
port: 8080# 允许后端访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-to-database
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgresql
ports:
- protocol: TCP
port: 5432
# 允许 DNS 解析
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53多层网络策略架构
# 完整的多层微服务网络策略
# 1. 数据库层 - 只接受来自服务层的连接
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-policy
namespace: production
spec:
podSelector:
matchLabels:
layer: database
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
layer: service
ports:
- protocol: TCP
port: 5432
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
---
# 2. 服务层 - 接受来自 API 网关的连接,可以访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: service-policy
namespace: production
spec:
podSelector:
matchLabels:
layer: service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
layer: gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
layer: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
---
# 3. API 网关层 - 接受外部流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: gateway-policy
namespace: production
spec:
podSelector:
matchLabels:
layer: gateway
policyTypes:
- Ingress
- Egress
ingress:
- from: [] # 允许所有入站(通过 LoadBalancer/Ingress 控制)
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
egress:
- to:
- podSelector:
matchLabels:
layer: service
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53RBAC 最佳实践
最小权限原则
# 错误示例:过度授权
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: developer-role-bad
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
# 这是极其危险的配置!
---
# 正确示例:最小权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer-role
namespace: production
rules:
# 只允许查看 Pod
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
# 只允许管理自己的 Deployment
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
resourceNames: ["my-app-deployment"]
# 允许查看 ConfigMap(不含 Secret)
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]# CI/CD 服务账号的 RBAC
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-cd-sa
namespace: production
automountServiceAccountToken: true
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-cd-role
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments/status"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-cd-binding
namespace: production
subjects:
- kind: ServiceAccount
name: ci-cd-sa
namespace: production
roleRef:
kind: Role
name: ci-cd-role
apiGroup: rbac.authorization.k8s.ioRBAC 审计工具
# 审计 RBAC 权限
# 查看用户/服务账号的权限
kubectl auth can-i --list --as=system:serviceaccount:production:ci-cd-sa -n production
# 检查特定操作权限
kubectl auth can-i create deployments --as=system:serviceaccount:production:ci-cd-sa -n production
# 检查是否有过度授权的 ClusterRoleBinding
kubectl get clusterrolebindings -o json | jq -r '
.items[] |
select(.roleRef.name == "cluster-admin") |
.subjects[]?.name // "undefined"
'
# 查找绑定了 cluster-admin 的主体
kubectl get clusterrolebindings -o json | jq -r '
.items[] |
select(.roleRef.name == "cluster-admin") |
"\(.metadata.name): \(.subjects)"
'
# 使用 rakkess 工具可视化 RBAC
kubectl rakkess -n productionSecrets 管理
原生 Secret 的问题
# Kubernetes 原生 Secret 只是 Base64 编码,不是加密!
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # echo -n 'admin' | base64
password: cGFzc3dvcmQxMjM= # echo -n 'password123' | base64# 启用 etcd 加密
# 创建加密配置
cat > encryption-config.yaml << 'EOF'
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
EOF
# API Server 启动参数添加
--encryption-provider-config=/etc/kubernetes/encryption-config.yamlSealed Secrets
# 安装 Sealed Secrets
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# 安装 kubeseal CLI
brew install kubeseal # macOS
# 或
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/kubeseal-linux-amd64 -O /usr/local/bin/kubeseal
# 从 Secret 创建 SealedSecret
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=SuperSecret123 \
--dry-run=client -o yaml | kubeseal \
-o yaml > sealed-secret.yaml
# 现在 sealed-secret.yaml 可以安全地提交到 Git# SealedSecret 示例(可以安全提交到 Git)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: production
spec:
encryptedData:
username: AgBfjhd7k2PQR...(加密后的数据)
password: AgCX9mKp3vNRS...(加密后的数据)
template:
metadata:
name: db-credentials
namespace: production
type: OpaqueExternal Secrets Operator
# External Secrets Operator - 从外部密钥管理服务同步
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: azure-keyvault-store
namespace: production
spec:
provider:
azurekv:
authType: ManagedIdentity
vaultUrl: https://my-keyvault.vault.azure.net/
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: azure-keyvault-store
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: database-username
- secretKey: password
remoteRef:
key: database-password
version: "" # 最新版本容器运行时安全
容器运行时安全配置
# 使用 RuntimeClass 选择安全运行时
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
---
# 使用 gvisor 运行时的 Pod
apiVersion: v1
kind: Pod
metadata:
name: sandboxed-app
spec:
runtimeClassName: gvisor
containers:
- name: app
image: myapp:1.0.0
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL镜像准入策略
# 使用 OPA/Gatekeeper 限制镜像来源
# 约束模板
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
not any(satisfied)
msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
not any(satisfied)
msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}
---
# 应用约束:只允许公司镜像仓库
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: repos-are-allowed
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "production"
parameters:
repos:
- "registry.mycompany.com/"
- "mcr.microsoft.com/"审计日志
审计策略配置
# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录 Secret 访问
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
namespaces: ["production"]
# 记录所有写操作
- level: Request
omitStages:
- "RequestReceived"
verbs:
- create
- update
- patch
- delete
# 记录 RBAC 变更
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
# 记录 Pod 安全策略变更
- level: RequestResponse
resources:
- group: "policy"
resources: ["podsecuritypolicies"]
# 忽略系统命名空间的读操作
- level: None
namespaces: ["kube-system", "kube-public"]
verbs: ["get", "list", "watch"]
# 忽略健康检查
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services"]
# 默认级别
- level: Metadata
omitStages:
- "RequestReceived"# API Server 审计日志配置
# 在 kube-apiserver 启动参数中添加
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-path=/var/log/kubernetes/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=200审计日志分析
# 使用 jq 分析审计日志
# 查找对 Secret 的访问
cat /var/log/kubernetes/audit.log | jq 'select(.objectRef.resource=="secrets") |
{user: .user.username, namespace: .objectRef.namespace, name: .objectRef.name,
verb: .verb, timestamp: .stageTimestamp}'
# 查找失败的请求
cat /var/log/kubernetes/audit.log | jq 'select(.responseStatus.code >= 400) |
{user: .user.username, resource: .objectRef.resource, verb: .verb,
code: .responseStatus.code, message: .responseStatus.message}'
# 查找特权操作
cat /var/log/kubernetes/audit.log | jq '
select(.objectRef.resource == "pods" and
(.verb == "create" or .verb == "update")) |
select(.requestObject.spec.securityContext.privileged == true) |
{user: .user.username, namespace: .objectRef.namespace, name: .objectRef.name}
'CIS Kubernetes Benchmark
关键安全检查项
# 使用 kube-bench 执行 CIS Benchmark 检查
# 安装 kube-bench
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
# 或使用 Helm 安装
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm install kube-bench aqua/kube-bench
# 查看 CIS 检查结果
kubectl logs job/kube-bench
# 在节点上直接运行
kube-bench run --targets master,node,etcd,policiesCIS Kubernetes Benchmark 关键检查项:
1. 控制平面安全
[PASS] 1.1.1 确保 API Server 使用 TLS
[PASS] 1.1.2 确保 etcd 使用 TLS
[FAIL] 1.2.1 禁用匿名认证
[PASS] 1.2.2 启用 RBAC
[WARN] 1.2.6 确保 kubelet 证书轮换
2. 节点安全
[PASS] 2.1.1 确保 kubelet 使用 TLS
[FAIL] 2.1.7 确保保护 kubelet anonymous-auth
[PASS] 2.2.1 确保 kube-proxy 文件权限
3. 策略检查
[FAIL] 3.1.1 确保 CNI 网络策略支持
[PASS] 3.2.1 确保 Pod Security Admission 启用安全扫描工具
Trivy 镜像扫描
# Trivy 扫描容器镜像
# 安装
brew install trivy # macOS
# 或
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add -
# 扫描镜像
trivy image nginx:1.25
trivy image --severity HIGH,CRITICAL myapp:1.0.0
trivy image --ignore-unfixed myapp:1.0.0
# 扫描 Kubernetes 集群中的所有镜像
trivy k8s --report summary cluster
# 扫描特定命名空间
trivy k8s -n production --report all cluster
# 输出 JSON 格式
trivy image --format json --output results.json myapp:1.0.0# Trivy Operator - 持续扫描集群中的镜像
apiVersion: aquasecurity.github.io/v1alpha1
kind: TrivyOperator
metadata:
name: trivy-operator
spec:
scanner:
scanJobTimeout: 5m
report:
trivy:
severity: HIGH,CRITICAL
ignoreUnfixed: trueFalco 运行时安全监控
# Falco - 运行时异常检测
apiVersion: falco.org/v1
kind: Falco
metadata:
name: falco
spec:
rules:
# 检测在容器中启动 shell
- rule: Terminal Shell in Container
desc: A shell was spawned in a container
condition: >
spawned_process and container and
proc.name in (bash, sh, zsh, ash) and
not proc.pname in (docker-entrypoint)
output: >
Shell spawned in container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
priority: WARNING
tags: [container, shell]
# 检测读取敏感文件
- rule: Read Sensitive File
desc: Attempt to read sensitive file
condition: >
open_read and container and
fd.name in (/etc/shadow, /etc/passwd, /etc/ssh/ssh_host_*)
and not proc.name in (sshd, passwd)
output: >
Sensitive file read in container
(user=%user.name container=%container.name
file=%fd.name proc=%proc.name)
priority: WARNING
# 检测特权容器操作
- rule: Privileged Container Activity
desc: Activity in privileged container
condition: >
container and container.privileged=true and
(open_write or spawned_process)
output: >
Activity in privileged container
(user=%user.name container=%container.name
image=%container.image.repository)
priority: CRITICAL安全上下文(Security Context)
# 全面的安全上下文配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-deployment
spec:
replicas: 3
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
# Pod 级安全上下文
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
fsGroupChangePolicy: "OnRootMismatch"
seccompProfile:
type: RuntimeDefault
serviceAccountName: app-sa
automountServiceAccountToken: false
containers:
- name: app
image: myapp@sha256:abc123
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
privileged: false
volumeMounts:
- name: tmp
mountPath: /tmp
- name: config
mountPath: /app/config
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
- name: config
configMap:
name: app-config总结
Kubernetes 安全加固是保护容器化应用的关键实践。通过纵深防御策略,从 Pod 安全标准、网络隔离、RBAC、Secret 管理到运行时监控,构建全面的安全体系。
核心原则:最小权限、默认拒绝、纵深防御、持续监控。
关键知识点
- Pod 安全标准分为 Privileged、Baseline、Restricted 三个级别
- 网络策略实现零信任网络架构
- RBAC 应遵循最小权限原则
- 原生 Secret 只是 Base64 编码,需要配合加密或外部密钥管理
- 审计日志是安全事件追溯的基础
- CIS Benchmark 提供了标准化的安全检查清单
常见误区
误区1:Kubernetes 默认配置足够安全
Kubernetes 的默认配置偏重可用性而非安全性。需要显式配置安全策略、网络策略和 RBAC。
误区2:网络策略影响性能
现代 CNI 插件(如 Calico、Cilium)使用 eBPF 等高效技术实现网络策略,性能开销可以忽略不计。
误区3:Secret 是加密的
Kubernetes 原生 Secret 只是 Base64 编码。需要启用 etcd 加密或使用外部密钥管理方案。
误区4:镜像来自官方仓库就安全
官方镜像也可能存在漏洞。应持续扫描所有镜像,包括基础镜像。
进阶路线
- 服务网格安全:Istio/Linkerd 的 mTLS 和授权策略
- 零信任架构:BeyondCorp 模式在 K8s 中的应用
- eBPF 安全:使用 Cilium/Tetragon 实现内核级安全监控
- 安全合规自动化:OPA/Gatekeeper 策略即代码
- 供应链安全:Sigstore、SLSA 框架
适用场景
- 金融行业的合规要求
- 多租户集群的安全隔离
- 面向互联网的服务暴露
- 处理敏感数据的工作负载
- CI/CD 管道的安全加固
落地建议
- 从 CIS Benchmark 检查开始,建立安全基线
- 在所有命名空间启用 Pod 安全标准
- 实施默认拒绝的网络策略
- 使用 Sealed Secrets 或 External Secrets 管理 Secret
- 定期扫描镜像漏洞
- 配置审计日志并设置告警
- 定期审查 RBAC 权限
排错清单
复盘问题
- 你的集群 CIS Benchmark 合规率是多少?
- 是否有定期扫描镜像漏洞的流程?
- 你的 RBAC 策略上次审查是什么时候?
- Secret 管理方案是否满足合规要求?
- 是否有运行时异常检测机制?
延伸阅读
- Kubernetes Security Documentation
- CIS Kubernetes Benchmark
- Pod Security Standards
- Trivy Documentation
- Falco Documentation
- OPA Gatekeeper
- 《Kubernetes Security》- Liz Rice & Michael Hausenblas
