安全最佳实践

安全最佳实践

安全防护层次

┌────────────────────────────────────────┐
│          镜像安全                      │
│  (Image Scanning & Signing)          │
└────────────────┬───────────────────────┘
                 │
┌────────────────▼───────────────────────┐
│          Pod 安全                      │
│  (Security Context & Pod Security)    │
└────────────────┬───────────────────────┘
                 │
┌────────────────▼───────────────────────┐
│          网络安全                      │
│      (Network Policy)                │
└────────────────┬───────────────────────┘
                 │
┌────────────────▼───────────────────────┐
│          访问控制                      │
│         (RBAC)                       │
└────────────────┬───────────────────────┘
                 │
┌────────────────▼───────────────────────┐
│          审计日志                      │
│    (Audit Logging)                   │
└────────────────────────────────────────┘

RBAC - 访问控制

核心概念

  • Role: 命名空间级别的权限集合
  • ClusterRole: 集群级别的权限集合
  • RoleBinding: 将 Role 绑定到用户/组
  • ClusterRoleBinding: 将 ClusterRole 绑定到用户/组

最小权限原则

# ❌ 不要给予过大权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: bad-example
subjects:
- kind: User
  name: developer
roleRef:
  kind: ClusterRole
  name: cluster-admin  # 过大的权限!
  apiGroup: rbac.authorization.k8s.io
# ✅ 只授予必要的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: dev
rules:
- apiGroups: [""]
  resources: ["pods", "services"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
  namespace: dev
subjects:
- kind: User
  name: alice
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

常用角色示例

只读用户

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch"]

开发者角色

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: dev
rules:
# Pod 管理
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "delete"]
# Deployment 管理
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Service 管理
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
# ConfigMap/Secret 读取
- apiGroups: [""]
  resources: ["configmaps", "secrets"]
  verbs: ["get", "list"]

运维角色

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ops-engineer
rules:
# 所有资源的读权限
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
# Pod 操作权限
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "delete"]
# 节点管理
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch", "update", "patch"]
# Event 查看
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]

ServiceAccount

# 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: production
---
# 绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-role
  namespace: production
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: app-role-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: app-sa
  namespace: production
roleRef:
  kind: Role
  name: app-role
  apiGroup: rbac.authorization.k8s.io
---
# 在 Pod 中使用
apiVersion: v1
kind: Pod
metadata:
  name: app
  namespace: production
spec:
  serviceAccountName: app-sa
  containers:
  - name: app
    image: myapp:v1

网络策略 - Network Policy

默认拒绝所有流量

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-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  # 只允许来自 frontend 的流量
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

允许特定出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-and-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Egress
  egress:
  # 允许 DNS 查询
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
  # 允许访问数据库
  - to:
    - podSelector:
        matchLabels:
          app: mysql
    ports:
    - protocol: TCP
      port: 3306

跨命名空间访问

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-dev
  namespace: shared-services
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          env: dev
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080

完整的三层应用网络策略

# Frontend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 允许来自 Ingress Controller
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 80
  egress:
  # 允许访问 Backend
  - to:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 8080
  # 允许 DNS
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# Backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 只允许来自 Frontend
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # 允许访问数据库
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 3306
  # 允许 DNS
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# Database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 只允许来自 Backend
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 3306
  egress:
  # 只允许 DNS
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

Pod 安全

Security Context

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  # Pod 级别安全上下文
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:v1
    # 容器级别安全上下文
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 1000
      capabilities:
        drop:
        - ALL
        add:
        - NET_BIND_SERVICE
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: cache
      mountPath: /app/cache
  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

Pod Security Standards

Restricted(最严格)

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Baseline(基准)

apiVersion: v1
kind: Namespace
metadata:
  name: development
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

PodDisruptionBudget

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb
spec:
  minAvailable: 2  # 至少保留 2 个 Pod
  selector:
    matchLabels:
      app: critical-app
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb-percentage
spec:
  maxUnavailable: 25%  # 最多 25% 不可用
  selector:
    matchLabels:
      app: web-app

镜像安全

镜像扫描

# 使用 Trivy 扫描镜像
trivy image myapp:v1.0

# 扫描高危和严重漏洞
trivy image --severity HIGH,CRITICAL myapp:v1.0

# 输出为 JSON
trivy image -f json -o results.json myapp:v1.0

# 在 CI 中集成
# GitHub Actions
- name: Run Trivy scanner
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myapp:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'

镜像签名验证

# 使用 cosign 签名镜像
cosign sign --key cosign.key myapp:v1.0

# 验证镜像签名
cosign verify --key cosign.pub myapp:v1.0

# 在 Kubernetes 中强制验证
# 使用 Admission Controller

私有镜像仓库

# Harbor / Nexus 等私有仓库
apiVersion: v1
kind: Secret
metadata:
  name: registry-secret
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64-encoded-config>
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  imagePullSecrets:
  - name: registry-secret
  containers:
  - name: app
    image: harbor.example.com/myapp:v1.0

镜像策略

# ❌ 不要使用 latest 标签
image: myapp:latest

# ✅ 使用具体版本
image: myapp:v1.2.3

# ✅ 使用 SHA256
image: myapp@sha256:abc123...

# ✅ 限制镜像来源
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: harbor.company.com/production/myapp:v1.0  # 仅允许内部仓库
    imagePullPolicy: Always

Secret 管理

加密 Secret

# 启用 Secret 加密
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: <base64-encoded-32-byte-key>
    - identity: {}

外部 Secret 管理

# 使用 External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: app-secrets
  data:
  - secretKey: database-password
    remoteRef:
      key: myapp/database
      property: password

审计日志

启用审计

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有 Secret 操作
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets"]
# 记录所有删除操作
- level: RequestResponse
  verbs: ["delete", "deletecollection"]
# 记录所有 RBAC 变更
- level: RequestResponse
  resources:
  - group: "rbac.authorization.k8s.io"
    resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
# 元数据级别记录其他操作
- level: Metadata
  omitStages:
  - "RequestReceived"

审计日志分析

# 查看审计日志
kubectl logs -n kube-system kube-apiserver-master-1 | grep audit

# 使用 Falco 进行运行时安全监控
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace

最佳实践清单

1. 访问控制

  • ✅ 启用 RBAC
  • ✅ 遵循最小权限原则
  • ✅ 使用 ServiceAccount
  • ✅ 定期审查权限
  • ✅ 禁用匿名访问

2. 网络安全

  • ✅ 实施 Network Policy
  • ✅ 默认拒绝所有流量
  • ✅ 分层网络隔离
  • ✅ 使用 Ingress TLS
  • ✅ 限制 egress 流量

3. Pod 安全

  • ✅ 非 root 用户运行
  • ✅ 只读根文件系统
  • ✅ 禁止特权提升
  • ✅ Drop 所有 capabilities
  • ✅ 使用 seccomp/AppArmor

4. 镜像安全

  • ✅ 定期扫描漏洞
  • ✅ 使用官方镜像
  • ✅ 不使用 latest 标签
  • ✅ 签名验证
  • ✅ 使用私有仓库

5. Secret 管理

  • ✅ 加密 etcd 中的 Secret
  • ✅ 使用外部密钥管理
  • ✅ 定期轮换密钥
  • ✅ 限制 Secret 访问
  • ✅ 不提交 Secret 到代码库

6. 审计与合规

  • ✅ 启用审计日志
  • ✅ 集中日志管理
  • ✅ 实时安全监控
  • ✅ 定期安全评估
  • ✅ 漏洞管理流程

常用命令

# RBAC
kubectl auth can-i create pods --as=alice
kubectl auth can-i delete deployments --as=alice -n production
kubectl get roles,rolebindings -n production

# Network Policy
kubectl get networkpolicies -A
kubectl describe networkpolicy <name>

# Pod Security
kubectl get pod <name> -o yaml | grep -A 10 securityContext

# Secret
kubectl get secrets
kubectl create secret generic db-password --from-literal=password=secret

# 审计
kubectl logs -n kube-system kube-apiserver-master --tail=100 | grep audit

小结

安全是 Kubernetes 运维的重中之重:

核心原则

  • 纵深防御:多层安全措施
  • 最小权限:只授予必要权限
  • 零信任:验证所有访问
  • 持续监控:实时检测威胁

关键措施

  • RBAC:细粒度访问控制
  • Network Policy:网络隔离
  • Pod Security:容器安全加固
  • Image Security:镜像扫描和签名
  • Secret Management:密钥安全存储
  • Audit Logging:审计和合规

安全是一个持续的过程

  • 定期安全评估
  • 及时补丁更新
  • 安全培训
  • 事件响应计划

下一章我们将学习生产环境实践,构建高可用的 Kubernetes 集群。