安全架构深度剖析
概述
Kubernetes 安全架构涵盖身份认证(Authentication)、授权(Authorization)、准入控制(Admission Control)、网络策略(NetworkPolicy)等多个层次。本文深入剖析 Kubernetes 安全机制的工作原理。
安全分层架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Kubernetes 安全分层 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 7. 网络安全层 │ │ │ │ NetworkPolicy / CNI │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 6. 运行时安全 │ │ │ │ PodSecurityPolicy / PSA │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 5. 资源安全层 │ │ │ │ ResourceQuota / LimitRange │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 4. 准入控制层 │ │ │ │ Mutating + Validating Webhook │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 3. 授权层 │ │ │ │ RBAC / ABAC / Node / Webhook │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 2. 认证层 │ │ │ │ X509 / Token / OIDC / Webhook │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 1. API 安全层 │ │ │ │ TLS / 审计日志 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
|
认证 (Authentication)
认证方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 认证方式概览 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ X509 客户端证书 │ │ │ │ - kubeconfig 中的 client-certificate-data │ │ │ │ - kubelet 使用的 Kubelet Certificate Rotation │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Bearer Token │ │ │ │ - ServiceAccount Token │ │ │ │ - Bootstrap Token │ │ │ │ - 静态 Token 文件 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ OIDC (OpenID Connect) │ │ │ │ - 第三方身份提供商集成 │ │ │ │ - dex, Keycloak, Auth0 等 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Webhook Token Authentication │ │ │ │ - 外部认证服务验证 Token │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Anonymous Auth (匿名) │ │ │ │ - 启用: --anonymous-auth=true (默认) │ │ │ │ - 禁用: --anonymous-auth=false │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
|
ServiceAccount Token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| apiVersion: v1 kind: ServiceAccount metadata: name: my-sa namespace: default --- apiVersion: v1 kind: Secret metadata: name: my-sa-token-xxxxx annotations: kubernetes.io/service-account.name: my-sa type: kubernetes.io/service-account-token data: token: <base64 encoded JWT> ca.crt: <base64 encoded CA>
|
Token 格式
1 2 3 4 5 6 7 8 9
| { "iss": "kubernetes/serviceaccount", "kubernetes.io/serviceaccount/namespace": "default", "kubernetes.io/serviceaccount/secret.name": "my-sa-token-xxxxx", "kubernetes.io/serviceaccount/service-account.name": "my-sa", "kubernetes.io/serviceaccount/service-account.uid": "<uid>", "sub": "system:serviceaccount:default:my-sa", "aud": "https://kubernetes.default.svc" }
|
授权 (Authorization)
授权模式
1 2
| --authorization-mode=Node,RBAC
|
| 模式 |
说明 |
| AlwaysAllow |
允许所有请求(默认) |
| AlwaysDeny |
拒绝所有请求(测试用) |
| RBAC |
基于角色的访问控制(推荐) |
| ABAC |
基于属性的访问控制 |
| Node |
Node 授权器,kubelet 专用 |
| Webhook |
外部授权服务 |
RBAC 核心概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ RBAC 核心概念 │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Role │ │ RoleBinding │ │ Subject │ │ │ │ (角色) │────>│ (绑定) │<────│ (主体) │ │ │ │ │ │ │ │ │ │ │ │ rules: │ │ subjects: │ │ - User │ │ │ │ - verbs: │ │ - kind: │ │ - Group │ │ │ │ get,list │ │ ServiceAccount│ │ - ServiceAccount│ │ │ │ - resources: │ │ name: my-sa │ │ │ │ │ │ pods │ │ │ │ │ │ │ │ - apiGroups:│ │ roleRef: │ │ │ │ │ │ "" │ │ kind: Role │ │ │ │ │ └───────────────┘ │ name: pod-reader│ └───────────────┘ │ │ │ └───────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────┐ │ │ │ ClusterRole │ │ │ │ (集群角色) │ │ │ │ │ │ │ │ 区别: │ │ │ │ - 作用于集群 │ │ │ │ - 可绑定任意命名空间│ │ │ └───────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
|
PolicyRule 详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-reader namespace: default rules:
- apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"]
- apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"]
- apiGroups: [""] resources: ["pods"] resourceNames: ["my-pod"] verbs: ["get"]
- nonResourceURLs: ["/healthz", "/metrics"] verbs: ["get"]
|
准入控制 (Admission Control)
准入流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 准入控制流程 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Mutating 阶段 (修改) │ │ │ │ │ │ │ │ 1. NamespaceLifecycle - 检查命名空间存在 │ │ │ │ 2. LimitRanger - 设置默认值/限制 │ │ │ │ 3. ServiceAccount - 设置 SA │ │ │ │ 4. DefaultStorageClass - 添加默认存储类 │ │ │ │ 5. DefaultTolerationSeconds - 默认容忍时间 │ │ │ │ 6. MutatingWebhook - 调用自定义变异 webhook │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Validating 阶段 (验证) │ │ │ │ │ │ │ │ 1. ResourceQuota - 验证资源配额 │ │ │ │ 2. PodSecurity - 验证 Pod 安全标准 │ │ │ │ 3. LimitRanger - 验证资源限制 │ │ │ │ 4. ValidatingWebhook - 调用自定义验证 webhook │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 请求被持久化到 etcd │ └──────────────────────────────────────────────────────────────────────────────┘
|
常用准入插件
| 插件 |
类型 |
说明 |
| NamespaceLifecycle |
Validating |
防止创建已终止的命名空间 |
| LimitRanger |
Mutating |
设置默认值/资源限制 |
| ServiceAccount |
Mutating |
自动配置 ServiceAccount |
| DefaultStorageClass |
Mutating |
添加默认存储类 |
| ResourceQuota |
Validating |
验证资源配额 |
| PodSecurity |
Validating |
验证 Pod 安全标准 |
| NodeRestriction |
Validating |
限制 kubelet 的权限 |
AdmissionReview 请求格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| type AdmissionReview struct { TypeMeta Request *AdmissionRequest Response *AdmissionResponse }
type AdmissionRequest struct { UID types.UID Kind GroupVersionKind Resource GroupVersionResource Subresource string RequestKind *GroupVersionKind Name string Namespace string Operation Operation UserInfo authenticationv1.UserInfo Object runtime.Object OldObject runtime.Object DryRun *bool }
|
网络策略 (NetworkPolicy)
策略类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-ingress spec: podSelector: matchLabels: app: my-app policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 80
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress spec: podSelector: matchLabels: app: my-app policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: name: database ports: - protocol: TCP port: 5432 - to: - namespaceSelector: {} ports: - protocol: UDP port: 53
|
Pod 隔离模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Pod 隔离模式 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 无 NetworkPolicy │ │ │ │ │ │ │ │ Pod 可以接收/发送任意流量 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 有 Ingress NetworkPolicy │ │ │ │ │ │ │ │ 仅允许符合策略的入站流量 │ │ │ │ 默认拒绝其他入站流量 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 有 Egress NetworkPolicy │ │ │ │ │ │ │ │ 仅允许符合策略的出站流量 │ │ │ │ 默认拒绝其他出站流量 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
|
Pod 安全
PodSecurityContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| apiVersion: v1 kind: Pod spec: securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 supplementalGroups: [1000] containers: - name: app securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL add: - NET_BIND_SERVICE
|
SecurityContext 字段
| 字段 |
说明 |
| runAsUser |
运行用户 ID |
| runAsGroup |
运行组 ID |
| runAsNonRoot |
必须以非 root 运行 |
| fsGroup |
文件系统组 |
| supplementalGroups |
补充组 |
| allowPrivilegeEscalation |
禁止权限提升 |
| readOnlyRootFilesystem |
只读根文件系统 |
| capabilities |
Linux 能力 |
Secret 管理
Secret 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| apiVersion: v1 kind: Secret metadata: name: my-secret type: Opaque data: username: <base64> password: <base64> ---
apiVersion: v1 kind: Secret metadata: name: my-tls-secret type: kubernetes.io/tls data: tls.crt: <base64> tls.key: <base64> ---
apiVersion: v1 kind: Secret metadata: name: my-registry-secret type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: <base64>
|
外部 Secret 管理
| 方案 |
说明 |
| HashiCorp Vault |
通过 CSI Provider 集成 |
| AWS Secrets Manager |
通过 External Secrets Operator |
| GCP Secret Manager |
通过 External Secrets Operator |
| Azure Key Vault |
通过 CSI Provider |
审计日志 (Audit)
审计策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: audit.k8s.io/v1 kind: Policy rules:
- level: None verbs: ["get", "list", "watch"] resources: - group: "" resources: ["pods"]
- level: Metadata resources: - group: "" resources: ["secrets", "configmaps"]
- level: RequestResponse resources: - group: "networking.k8s.io" resources: ["ingresses"]
- level: Request
|
审计阶段
| 阶段 |
说明 |
| RequestReceived |
收到请求时 |
| ResponseStarted |
响应开始发送时 |
| ResponseComplete |
响应发送完成 |
| Panic |
发生 panic 时 |
关键代码路径
| 文件 |
说明 |
staging/src/k8s.io/apiserver/pkg/authentication/ |
认证 |
staging/src/k8s.io/apiserver/pkg/authorization/ |
授权 |
staging/src/k8s.io/apiserver/pkg/admission/ |
准入控制 |
plugin/pkg/auth/authorizer/rbac/ |
RBAC 授权器 |
pkg/kubelet/certificate/ |
Kubelet 证书轮换 |
pkg/api/podsecurity/ |
Pod 安全策略 |
面试题
基础题
1. Kubernetes 有哪些认证方式?
参考答案:
- X509 客户端证书:最常用
- Bearer Token:ServiceAccount JWT
- Bootstrap Token:集群引导
- OIDC:OpenID Connect
- Webhook:外部认证服务
- Anonymous:匿名访问
2. ServiceAccount 的工作原理是什么?
参考答案:
- 创建 ServiceAccount 时自动创建对应的 Token Secret
- Token 是一个 JWT,包含 namespace、name 等信息
- Pod 启动时 Token 自动挂载到
/var/run/secrets/kubernetes.io/serviceaccount/
- kubelet 通过 ServiceAccount 访问 API Server
3. RBAC 的核心概念有哪些?
参考答案:
- Role:命名空间级别的权限
- ClusterRole:集群级别的权限
- RoleBinding:将 Role 绑定到主体
- ClusterRoleBinding:将 ClusterRole 绑定到主体
- Subject:User、Group、ServiceAccount
中级题
4. 准入控制的两个阶段是什么?顺序如何?
参考答案:
| 阶段 |
顺序 |
作用 |
| Mutating |
先 |
修改请求内容 |
| Validating |
后 |
验证请求有效性 |
5. 如何限制 Pod 的权限?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| spec: securityContext: runAsNonRoot: true readOnlyRootFilesystem: true
spec: securityContext: seccompProfile: type: RuntimeDefault
spec: policyTypes: - Ingress - Egress
|
6. Secret 如何保证安全?
参考答案:
- 静态加密:etcd 存储加密
- RBAC:限制 Secret 访问权限
- Secret 轮换:定期更新
- 外部密钥管理:Vault、AWS Secrets Manager
- 禁止明文:使用 sealed-secrets
7. 如何配置审计日志?
参考答案:
1 2 3 4 5 6
| --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=100
|
高级题
8. AdmissionWebhook 的工作原理是什么?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| admissionReview := &admission.AdmissionReview{ Request: &admission.AdmissionRequest{ UID: types.UID(uuid.NewUUID()), Kind: gvk, Resource: gvr, Operation: admission.Operation(op), Object: runtime.RawExtension{Raw: body}, }, }
admissionReview.Response = &admission.AdmissionResponse{ UID: admissionReview.Request.UID, Allowed: true, Patch: patchBytes, }
|
9. 如何实现基于角色的权限委托?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: namespace-reader rules: - apiGroups: [""] resources: ["*"] verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: delegate-to-user namespace: target-ns subjects: - kind: User name: other-user roleRef: kind: ClusterRole name: namespace-reader
|
10. Kubelet 证书轮换是如何工作的?
参考答案:
- kubelet 启动时检查证书是否即将过期
- 如果即将过期,向 API Server 请求新证书
- API Server 使用 CSR (CertificateSigningRequest) 审批
- kubelet 获取签名后的证书
- 证书保存到本地,更新 kubeconfig
场景题
11. 如何实现多租户隔离?
参考答案:
- 命名空间隔离
- RBAC 权限控制
- ResourceQuota/LimitRange
- NetworkPolicy 网络隔离
- PodSecurity 安全策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| --- apiVersion: v1 kind: Namespace metadata: name: tenant-a labels: tenant: a --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all namespace: tenant-a spec: podSelector: {} policyTypes: [Ingress, Egress] --- apiVersion: v1 kind: ResourceQuota metadata: name: tenant-a-quota namespace: tenant-a spec: hard: requests.cpu: "10" requests.memory: 20Gi persistentvolumeclaims: "10"
|
12. 如何排查 RBAC 权限问题?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12
| kubectl auth whoami
kubectl auth can-i get pods --as=<user>
kubectl get rolebinding -A | grep <user> kubectl get clusterrolebinding | grep <user>
kubectl describe rolebinding <name> -n <ns>
|
13. 如何保护集群安全?
参考答案:
API Server 安全
传输加密
网络安全
运行时安全
密钥管理