一、云原生安全工具链全景图
云原生安全遵循 CNCF Cloud Native Security Whitepaper 的 "Secure Cloud Native" 框架:
┌──────────────────────────────────────────────────────────────┐
│ 云原生防御体系 │
├──────────────┬───────────────────────────────────────────────┤
│ 阶段 │ 工具 / 技术 │
├──────────────┼───────────────────────────────────────────────┤
│ 代码 (左移) │ Semgrep / CodeQL / Checkov / tfsec │
├──────────────┼───────────────────────────────────────────────┤
│ 构建 │ Trivy / Grype / Cosign / Syft │
├──────────────┼───────────────────────────────────────────────┤
│ 部署 │ OPA Gatekeeper / Kyverno / PSI / Sigstore │
├──────────────┼───────────────────────────────────────────────┤
│ 运行时 │ Falco / Tracee / Cilium Hubble / eBPF Guard │
├──────────────┼───────────────────────────────────────────────┤
│ 合规 │ Open Policy Agent / Polaris / Trivy Operator │
├──────────────┼───────────────────────────────────────────────┤
│ 治理 │ Kubescape / CloudSploit / ScoutSuite / Snyk │
└──────────────┴───────────────────────────────────────────────┘
二、Trivy:一把瑞士军刀解决 80% 的扫描需求
2.1 Trivy 能做什么
| 功能 | 说明 |
|---|---|
| 镜像漏洞扫描 | 扫描 OS 包漏洞 + 应用依赖漏洞 |
| 容器文件系统扫描 | 直接扫描运行中容器的漏洞 |
| 代码仓库扫描 | 扫描 Git 仓库的语言依赖漏洞 |
| 配置文件扫描 | 扫描 Dockerfile/Terraform/Helm/K8s YAML 反模式 |
| Secret 扫描 | 扫描硬编码的密码/API Key |
| License 扫描 | 扫描开源许可合规性 |
| K8s 集群扫描 | 扫描集群配置风险 |
2.2 生产可用 Helm 部署
# trivy-operator-values.yaml
operator:
replicas: 2
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
# 漏洞数据库设置
trivy:
ignoreUnfixed: true
securityChecks: vuln,misconfig,secret,license
severity: CRITICAL,HIGH,MEDIUM
# 模式: 1. 扫描新创建的 Pod (Admission) 2. 定期扫描全部 ClusterScan
scanJob:
cron: "0 2 * * *" # 每天凌晨 2 点扫描
scanOnce: false
# 触发模式
webhook:
# 拦截 Admission 请求: 阻止漏洞严重的 Pod 部署
mode: Enforce # Audit = 只告警不阻止,Enforce = 直接拒绝
# RBAC(最小权限)
rbac:
create: true
priorityClasses:
critical: 1000000 # CRITICAL 漏洞优先级 1000
high: 900000
# 结果上报到外部系统
report:
type: sarif # 或 json
format: table
helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aquasecurity/trivy-operator --namespace trivy-system --create-namespace -f trivy-operator-values.yaml
2.3 扫描结果 API 告警
#!/usr/bin/env python3
"""
Trivy Operator 扫描结果收集 + 推送到 Slack
"""
import json, urllib.request, sys
SLACK_WEBHOOK = "https://hooks.slack.com/services/XXX/YYY/ZZZ"
def fetch_scan_results():
results = []
# 列出所有 VulnerabilityReport / ClusterScanReport
import subprocess
for resource in ("vulnerabilityreports", "clusterscans"):
proc = subprocess.run(
["kubectl", "get", resource, "-A", "-o", "json"],
capture_output=True, text=True
)
data = json.loads(proc.stdout)
for item in data.get("items", []):
results.append(item)
return results
def analyze(result):
name = result["metadata"]["name"]
ns = result["metadata"]["namespace"]
cve_count = result.get("spec", {}).get("summary", {})
critical = cve_count.get("critical", 0)
high = cve_count.get("high", 0)
secret_count = result.get("spec", {}).get("checks", [])
return name, ns, critical, high
def send_to_slack(msg):
payload = json.dumps({"text": msg})
req = urllib.request.Request(
SLACK_WEBHOOK,
data=payload.encode(),
headers={"Content-Type": "application/json"}
)
urllib.request.urlopen(req)
def main():
results = fetch_scan_results()
alert = []
for r in results:
name, ns, critical, high = analyze(r)
if critical > 0 or high > 5:
alert.append(f"🔴 *{ns}/{name}*: CRITICAL={critical}, HIGH={high}")
if alert:
send_to_slack("🚨 Trivy 扫描发现严重漏洞:
" + "
".join(alert))
if __name__ == "__main__":
main()
三、Falco:运行时安全的第一防线
3.1 Falco 是什么
Falco 是云原生运行时安全引擎。它通过 eBPF 在内核层面捕获系统调用,实时检测异常行为。
┌─────────────────────────────────────────────┐
│ Falco 架构 │
│ │
│ syscall → eBPF probe → Falco Engine → Rules → Alert│
│ │ │
│ │ ├──→ stdout (日志)
│ │ ├──→ Webhook (Slack/DingTalk)
│ │ ├──→ gRPC
│ │ └──→ exec_program (自动响应)
└─────────────────────────────────────────────┘
3.2 安装(Helm)
# falco-values.yaml
falco:
image:
repository: docker.io/falco/falco
tag: 0.37.2
# 启用所有默认规则
defaultRules:
replaceAll: false
rules:
- custom_rules.yaml # 自定义规则文件
- /etc/falco/rules.d/*.yaml
driver:
kind: ebpf-kmod # 或 ebpf-ebpf (无内核模块版本)
# 输出
audit:
enabled: true
file: /var/log/audit.log
# 告警通道
outputs:
- name: syslog
- name: file
file_path: /var/log/falco-events.log
- name: webhook
url: https://hooks.slack.com/services/XXX/YYY/ZZZ
min_priority: CRITICAL
# Runtime
runtime:
# 关键: 开启 Kubernetes 元数据关联
k8s:
enabled: true
meta_parser: k8s
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco --namespace falco --create-namespace -f falco-values.yaml
# 验证部署
kubectl get pods -n falco -w
# 等所有 falco Pod Running
3.3 生产级自定义规则集
# rules/critical-security-rules.yaml
# 所有规则按优先级分类
- rule: Attacker Pod Executes Bash
desc: "任何 Pod 内执行 bash/sh"
condition: >
spawned_process and
proc.name in (bash, sh, zsh) and
proc.pid != 1
output: "🔴 可疑 shell: user=%user.name pid=%proc.pid ppid=%proc.ppid exe=%proc.exepath cmd=%proc.cmdline container=%container.name pod=%k8s.pod.name"
priority: CRITICAL
tags: [attack, execution]
- rule: Attacker Reads /etc/shadow or /etc/passwd
desc: "读取敏感系统文件"
condition: >
open_read and
(fd.name startswith /etc/shadow or fd.name startswith /etc/passwd or fd.name startswith /etc/gshadow) and
container.name != "istio-proxy"
output: "🔴 敏感文件读取: user=%user.name file=%fd.name cmd=%proc.cmdline container=%container.name pod=%k8s.pod.name"
priority: CRITICAL
tags: [attack, credential_access]
- rule: Attacker Tries to Access Cloud Metadata
desc: "访问 169.254.169.254 / 100.100.100.200 等云元数据"
condition: >
(dns_lookup and dns.name contains "metadata" and dns.name contains "169.254") or
(outbound_tcp and (fd.sip = 169.254.169.254 or fd.sip = 100.100.100.200 or fd.sip = fd.sip))
output: "🔴 元数据访问! user=%user.name cmd=%proc.cmdline container=%container.name pod=%k8s.pod.name dest=%fd.sip"
priority: CRITICAL
tags: [attack, metadata, cloud]
- rule: Attacker Port Scans the Network
desc: "短时间内大量 TCP connect → 端口扫描"
condition: >
outbound_tcp and evt.rawres = 0 and
not fd.sport in (80, 443, 53, 8080, 443)
output: "🟠 可疑 TCP 连接: user=%user.name cmd=%proc.cmdline src=%fd.cip dest=%fd.sip:%fd.sport container=%container.name"
priority: HIGH
tags: [attack, recon]
- rule: New Binary on Container Filesystem
desc: "新二进制文件被写入 /tmp 或 /dev/shm(攻击者植入 payload)"
condition: >
create or rename or open_write and
(fd.name startswith /tmp or fd.name startswith /dev/shm) and
fd.name endswith .sh
output: "🟠 新脚本文件: user=%user.name file=%fd.name container=%container.name pod=%k8s.pod.name"
priority: HIGH
tags: [attack, persistence]
- rule: Kubernetes API Server Privileged Pod Created
desc: "创建特权 Pod(K8s 审计事件)"
condition: >
event_type = "k8s" and
k8s.verb in (create, update) and
k8s.resource.name = "pods" and
k8s.object.spec.containers[].securityContext.privileged = true
output: "🔴 特权 Pod 创建! user=%k8s.user pod=%k8s.object.metadata.name container=%k8s.object.spec.containers[].name"
priority: CRITICAL
tags: [k8s, persistence, privileged]
- rule: Reverse Shell Detected
desc: "检测反弹 shell 模式"
condition: >
spawned_process and
(proc.cmdline contains "/dev/tcp" or proc.cmdline contains "nc -e" or proc.cmdline contains "ncat -e" or proc.cmdline contains "python-c" or proc.cmdline contains "python3 -c")
output: "🔴🔴 反弹 Shell! user=%user.name cmd=%proc.cmdline container=%container.name pod=%k8s.pod.name"
priority: CRITICAL
tags: [attack, reverse_shell]
- rule: Unexpected Package Manager in Container
desc: "容器里突然跑 apt/yum/pip(不像正常应用,可能在装恶意工具)"
condition: >
spawned_process and
proc.name in (apt, apt-get, yum, dnf, apk, pip, pip3, gem) and
container.image.repository not in ("alpine", "debian", "ubuntu", "centos", "python", "node")
output: "🟡 包管理器执行: user=%user.name proc=%proc.name cmd=%proc.cmdline pod=%k8s.pod.name image=%container.image.repository"
priority: MEDIUM
tags: [suspicious]
- rule: Kubeconfig File Manipulated
desc: "读写 kubeconfig(可能在获取集群凭证)"
condition: >
(open_read or open_write) and
(fd.name endswith config and fd.name startswith /home/) or
(fd.name contains .kube/config)
output: "🟠 kubeconfig 访问! user=%user.name fd=%fd.name cmd=%proc.cmdline"
priority: HIGH
tags: [k8s, credential_access]
3.4 Falco 自动响应(run program)
Falco 可以在检测到高危事件时自动执行命令:
# 追加到 falco-values.yaml 的 falco.rules 后面
- rule: Critical Attacker Detected
desc: "多种攻击迹象同时出现"
condition: >
open_read and fd.name startswith /etc/shadow and
(proc.cmdline contains curl or proc.cmdline contains wget)
output: "🔴 Critical!"
priority: CRITICAL
tags: [attack]
# 自动响应
source: syscall
action:
# 触发一个本地脚本(比如:kubectl 删除被入侵的 Pod)
exec:
program: /etc/falco/response-script.sh
args: ["--pod", "%k8s.pod.name", "--namespace", "%k8s.ns.name"]
bufsize: 1024
#!/bin/bash
# response-script.sh - 自动隔离被入侵 Pod
POD=$2
NAMESPACE=$4
echo "[Falco Auto-Response] 隔离被入侵 Pod: $NAMESPACE/$POD"
# 1. 先 dump Pod 内的进程信息(取证)
kubectl exec -n $NAMESPACE $POD -- ps aux > /tmp/falco-forensics-$POD.txt 2>/dev/null
# 2. 把 Pod 的 label 改成 "quarantine=true" 阻止 Service 继续路由到它
kubectl label pod -n $NAMESPACE $POD quarantine=true --overwrite 2>/dev/null
# 3. 触发告警
curl -X POST https://hooks.slack.com/services/XXX -d "{"text": "🚨 自动隔离 Pod: $NAMESPACE/$POD"}"
# 4. 可选: 直接删除 Pod
# kubectl delete pod -n $NAMESPACE $POD
四、OPA / Kyverno:准入控制的"守门员"
4.1 OPA vs Kyverno 选型
| 特性 | OPA Gatekeeper | Kyverno |
|---|---|---|
| 策略语言 | Rego(强大但复杂) | YAML(简单但受限) |
| 学习曲线 | 陡峭 | 平缓 |
| 适用场景 | 复杂逻辑(跨资源校验) | 常见 K8s 场景(Pod/Deployment) |
| 扩展性 | 支持自定义 Policy Template | 支持 mutation(改写资源) |
| 成熟度 | CNCF 毕业项目 | CNCF 毕业项目 |
建议:先用 Kyverno 覆盖 80% 常见场景,再用 OPA/Gatekeeper 处理复杂策略。
4.2 Kyverno 生产规则集
# kyverno-policies.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
annotations:
policies.kyverno.io/title: 强制所有资源必须有 security-contact label
policies.kyverno.io/category: Best Practices
spec:
validationFailureAction: enforce
background: true
rules:
- name: check-for-labels
match:
any:
- resources:
kinds: ["Pod", "Deployment", "Service", "ConfigMap"]
validate:
message: "必须设置 security-contact 标签"
pattern:
metadata:
labels:
security-contact: "?*"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-privileged-pods
annotations:
policies.kyverno.io/title: 禁止特权容器
spec:
validationFailureAction: enforce
rules:
- name: privileged-containers
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "禁止 privileged: true"
pattern:
spec:
containers:
- (securityContext):
(privileged): "false"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-volumes
annotations:
policies.kyverno.io/title: 禁止 hostPath 和其他危险卷
spec:
validationFailureAction: enforce
rules:
- name: hostpath-disallowed
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "禁止使用 hostPath 卷(除了 /tmp 和 /var/run)"
deny:
conditions:
all:
- key: "{{ request.object.spec.volumes[].hostPath.path }}"
operator: NotIn
value:
- "''"
- "/tmp"
- "/var/run"
- name: hostpid-ipc-disallowed
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "禁止 hostPID/hostIPC/hostNetwork"
anyPattern:
- spec:
hostPID: false
hostIPC: false
hostNetwork: false
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: image-sources
annotations:
policies.kyverno.io/title: 只允许从可信 Registry 拉镜像
spec:
validationFailureAction: enforce
rules:
- name: image-source-whitelist
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "镜像必须来自内部 Registry my-registry.io 或 ghcr.io"
forEach:
- context:
variable:
name: image
value: request.object.spec.containers[].image
deny:
conditions:
all:
- key: "{{ image }}"
operator: NotStartsWith
value:
- "my-registry.io/"
- "ghcr.io/my-org/"
- "nginx:"
- "alpine:"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: enforce-resource-requests
annotations:
policies.kyverno.io/title: 必须设置 Resource Requests/Limits
spec:
validationFailureAction: enforce
rules:
- name: check-resources
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "每个容器必须设置 requests 和 limits"
forEach:
- context:
variable:
name: container
value: request.object.spec.containers[]
allPatterns:
- resources:
requests:
memory: "?*"
cpu: "?*"
limits:
memory: "?*"
cpu: "?*"
---
# Mutation 自动加安全标签
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: auto-add-labels
spec:
background: true
rules:
- name: add-default-labels
match:
any:
- resources:
kinds: ["Pod", "Deployment"]
mutate:
patchStrategicMerge:
metadata:
labels:
managed-by: kyverno
security-scanned: "true"
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace
# 应用策略
kubectl apply -f kyverno-policies.yaml
# 测试: 一个特权 Pod 应该被拒绝
kubectl apply -f privileged-pod-test.yaml
# Error from server: admission webhook "kyverno" denied the request:
# restrict-privileged-pods: privileged-containers: 禁止 privileged: true
4.3 OPA Gatekeeper 示例(复杂场景)
# Gatekeeper ConstraintTemplate - 自定义策略模板
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedimagesnamespaces
spec:
crd:
spec:
names:
kind: K8sAllowedImagesNamespaces
validation:
openAPIV3Schema:
type: object
properties:
allowedRegistries:
type: array
items:
type: string
exemptNamespaces:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedimagesnamespaces
violation[{"msg": msg}] {
input.review.object.kind == "Pod"
not exempted
container := input.review.object.spec.containers[_]
not image_allowed(container.image)
msg := sprintf("镜像 %v 不在允许列表中,只允许: %v", [container.image, input.parameters.allowedRegistries])
}
exempted {
ns := input.review.object.metadata.namespace
ns == input.parameters.exemptNamespaces[_]
}
image_allowed(image) {
registry := input.parameters.allowedRegistries[_]
startswith(image, registry)
}
---
# 具体策略实例
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedImagesNamespaces
metadata:
name: restrict-images
spec:
parameters:
allowedRegistries:
- "my-registry.io/"
- "ghcr.io/my-org/"
exemptNamespaces:
- kube-system
- monitoring
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
五、CI/CD 集成:从代码到部署的流水线
5.1 完整安全流水线
# .gitlab-ci.yml / GitHub Actions 都类似
name: Security Pipeline
# Stage 1: 代码扫描
security-semgrep:
stage: code-scan
image: returntocorp/semgrep:latest
script:
- semgrep config --config=p/owasp-top-ten --config=p/r2c-ci --config=p/dockerfile
- semgrep ci --json > semgrep-report.json
allow_failure: false
# Stage 2: IaC 扫描
security-tfsec:
stage: code-scan
image: aquasec/tfsec:latest
script:
- tfsec . --minimum-severity=MEDIUM --format json > tfsec-report.json
allow_failure: false
# Stage 3: 构建 + 镜像扫描
security-build-scan:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- curl -sL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- trivy image --vuln-type os,library --severity CRITICAL,HIGH --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- trivy fs --scanners secret --exit-code 1 . # 扫描 Secret
- trivy image --format spdx-json --output sbom.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false
# Stage 4: 签名 + 准入控制
security-sign-deploy:
stage: deploy
image: sigstore/cosign:latest
script:
- echo "$COSIGN_PRIVATE_KEY" | base64 -d > cosign.key
- cosign sign --key cosign.key --yes $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- # 部署(Kyverno / OPA 会在 Admission 时验签)
- helm upgrade --install my-app ./charts --set image.tag=$CI_COMMIT_SHA --namespace production
environment:
name: production
allow_failure: false
# Stage 5: 部署后验证
security-verify:
stage: verify
image: bitnami/kubectl:latest
script:
- # 检查 Trivy 扫描结果没有 CRITICAL
- kubectl wait --for=condition=healthy clusterpolicy require-labels
- # 检查 Falco 没有新的 CRITICAL 告警
- kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -c CRITICAL || true
allow_failure: false
六、Kubescape:持续合规 + 风险评估
6.1 安装与运行
# 单次扫描
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
kubescape scan cluster --format html -o report.html
# 打开 report.html 看结果
# 定期扫描(Helm 部署 Operator)
helm repo add kubescape https://kubernetes.github.io/dn
helm install kubescape kubescape/kubescape-cloud-operator --namespace kubescape --create-namespace
# 查看扫描结果
kubectl get kubescapejobs -A
kubectl get kubescapereports -A
6.2 合规框架
# 按 NSA 加密指南扫描
kubescape scan framework nsa
# 按 CIS Benchmark 扫描
kubescape scan framework cis
# 按 All 扫描
kubescape scan framework all
# 按控制面组件扫描
kubescape scan control "C-0001" # 特定控件 ID
七、工具链协同全景
7.1 典型企业部署架构
开发者 push 代码
│
┌─────▼─────┐
│ CI/CD │
│ Semgrep │ ← 代码层扫描
│ Trivy │ ← 镜像层扫描 + SBOM
│ Cosign │ ← 签名
└─────┬─────┘
│ push 签名后的镜像
┌─────▼─────┐
│ Registry │ ← Harbor Trivy 二次扫描
│ (Harbor) │
└─────┬─────┘
│ 部署
┌─────▼─────┐
│ Kyverno │ ← Admission 验签 + 策略
│ / OPA │
└─────┬─────┘
│ Pod Running
┌──────────┼──────────┐
┌─────▼─────┐ ┌──▼────┐ ┌───▼──────┐
│ Falco │ │Cilium │ │Kubescape │
│ eBPF 检测 │ │Hubble │ │ 持续合规 │
│ 运行时 │ │可观测 │ │ 风险评估 │
└─────┬─────┘ └──┬────┘ └───┬──────┘
│ │ │
└─────┬─────┴──────────┘
▼
┌──────────────┐
│ Prometheus + │
│ Grafana + │
│ Alertmanager│
│ Slack/Ding │
└──────────────┘
八、总结:云原生安全工具链 Checklist
| 阶段 | 工具 | Helm Chart | 关键配置 |
|---|---|---|---|
| 代码 | Semgrep | CI 内置 | OWASP Top 10 规则集 |
| IaC | tfsec | CI 内置 | MEDIUM 以下允许 |
| 镜像 | Trivy Operator | aquasecurity/trivy-operator | mode: Enforce |
| 签名 | Cosign | sigstore/cosign | Keyless + Fulcio |
| 准入 | Kyverno/Gatekeeper | kyverno/kyverno | 生产策略集 |
| 运行时 | Falco | falcosecurity/falco | eBPF-kmod + 自定义规则 |
| 可观测 | Cilium Hubble | cilium/cilium | Network Flow Log |
| 合规 | Kubescape | kubescape-cloud-operator | CIS + NSA |
| 告警 | Alertmanager | prometheus-community | Slack + PagerDuty |
核心理念:安全工具链不是越多越好,而是要形成闭环——Trivy 扫描 → Kyverno 拦截 → Falco 运行时检测 → Kubescape 持续合规 → 告警到 Slack/PagerDuty。每一层都有明确的职责,任何一层出了问题都有下一层兜底。