安全最佳实践
安全最佳实践
安全防护层次
┌────────────────────────────────────────┐
│ 镜像安全 │
│ (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 集群。