# JWT Secret + ETCD Encryption Deployment Guide 完整的 JWT 认证系统部署指南,包括密钥管理、RBAC 权限控制和 ETCD 加密。 ## 部署顺序 ### 第1步:创建 Secret 和 RBAC(必需) 创建 JWT 秘钥和服务账户权限: ```bash kubectl apply -f deploy/k8s/secrets/jwt-secret.yaml ``` 验证创建成功: ```bash # 检查 Secret kubectl get secret jwt-secret -n juwan kubectl get secret jwt-secret -n juwan -o yaml # 检查 ServiceAccounts kubectl get sa user-rpc -n juwan kubectl get sa envoy-gateway -n juwan # 检查 RBAC 权限 kubectl get role jwt-secret-reader -n juwan kubectl get rolebinding -n juwan -l app=jwt-secret-reader ``` ### 第2步:更新 user-rpc 部署(依赖第1步) 已自动更新 `deploy/k8s/service/user/user-rpc.yaml`: - ✅ 更新 `serviceAccountName` 从 `find-endpoints` → `user-rpc` - ✅ 添加环境变量 `JWT_SECRET_KEY` 从 Secret `jwt-secret` 读取 应用更新: ```bash kubectl apply -f deploy/k8s/service/user/user-rpc.yaml ``` 验证部署: ```bash # 检查 ServiceAccount 已正确绑定 kubectl get deployment user-rpc -n juwan -o yaml | grep -A 5 serviceAccountName # 查看 Pod 是否以 user-rpc ServiceAccount 身份运行 kubectl get pod -n juwan -l app=user-rpc -o yaml | grep serviceAccount # 验证环境变量已注入 kubectl exec -it POD_NAME -n juwan -- env | grep JWT_SECRET_KEY ``` ### 第3步:更新 Envoy 网关部署(依赖第1步) 已自动更新 `deploy/k8s/envoy/envoy.yaml`: - ✅ 添加 `serviceAccountName: envoy-gateway` 到 Deployment spec 应用更新: ```bash kubectl apply -f deploy/k8s/envoy/envoy.yaml ``` 验证部署: ```bash # 检查 ServiceAccount 已正确绑定 kubectl get deployment envoy-gateway -n juwan -o yaml | grep -A 2 serviceAccountName # 检查 Pod 状态 kubectl get pod -n juwan -l app=envoy-gateway ``` ### 第4步:启用 ETCD 加密(强烈推荐用于生产环境) 这是一个集群级别的配置,需要在 Kubernetes 控制平面节点上执行。 **前提条件:** - 具有 Kubernetes 集群管理员权限 - 可以访问控制平面节点 - 备份 ETCD 数据库 **步骤:** 1. **生成加密密钥** ```bash head -c 32 /dev/urandom | base64 ``` 记录输出的 Base64 密钥。 2. **创建加密配置文件** 在控制平面节点上,创建 `/etc/kubernetes/encryption-config.yaml`: ```yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: - identity: {} ``` 替换 `` 为第1步生成的密钥。 3. **修改 kube-apiserver 配置** 在控制平面节点上,编辑 `/etc/kubernetes/manifests/kube-apiserver.yaml`: **添加参数:** ```yaml spec: containers: - name: kube-apiserver command: - kube-apiserver - --encryption-provider-config=/etc/kubernetes/encryption-config.yaml ``` **添加卷挂载:** ```yaml spec: containers: - name: kube-apiserver volumeMounts: - name: encryption-config mountPath: /etc/kubernetes readOnly: true volumes: - name: encryption-config hostPath: path: /etc/kubernetes type: DirectoryOrCreate ``` 4. **重启 kube-apiserver** 修改清单后,kubelet 会自动重启 kube-apiserver。检查状态: ```bash # 在控制平面节点 kubectl get pods -n kube-system | grep kube-apiserver # 监控重启过程 kubectl logs -n kube-system -l component=kube-apiserver -f ``` 5. **验证加密是否启用** 创建一个新 Secret 并检查它在 ETCD 中是否加密: ```bash # 创建测试 Secret kubectl create secret generic test-secret -n juwan --from-literal=key=value # 从 control plane 节点检查 ETCD 数据 # 如果数据不可读并包含加密标记,说明加密已启用 ``` 6. **保存加密密钥** ⚠️ **关键:将加密密钥安全地保存在离线存储中** - 密钥丢失后,无法解密 ETCD 中的数据 - 无法恢复任何 Secrets - 建议用密码管理工具(如 HashiCorp Vault)或 HSM 存储密钥 ### 第5步:验证整个系统 完整的验证清单: ```bash # 检查所有 Secrets 已创建 kubectl get secret -n juwan kubectl get secret jwt-secret -n juwan -o jsonpath='{.data.secret-key}' | base64 -d # 检查 ServiceAccounts 已创建 kubectl get sa -n juwan kubectl describe sa user-rpc -n juwan kubectl describe sa envoy-gateway -n juwan # 检查 RBAC 权限 kubectl get role -n juwan kubectl get rolebinding -n juwan kubectl describe role jwt-secret-reader -n juwan # 测试权限:user-rpc 可以读 jwt-secret kubectl auth can-i get secrets --as=system:serviceaccount:juwan:user-rpc --resource-name=jwt-secret -n juwan # 测试权限:envoy-gateway 可以读 jwt-secret kubectl auth can-i get secrets --as=system:serviceaccount:juwan:envoy-gateway --resource-name=jwt-secret -n juwan # 测试权限:其他 ServiceAccount 无法读取 kubectl auth can-i get secrets --as=system:serviceaccount:juwan:other-service -n juwan # 检查 Deployments 已正确配置 kubectl get deployment user-rpc -n juwan -o yaml | grep -A 2 serviceAccountName kubectl get deployment envoy-gateway -n juwan -o yaml | grep -A 2 serviceAccountName # 检查 Pods 是否已启动并运行 kubectl get pods -n juwan -l app=user-rpc kubectl get pods -n juwan -l app=envoy-gateway # 查看 JWT Secret 是否已挂载到 Pod kubectl exec -it $(kubectl get pod -n juwan -l app=user-rpc -o name | head -1) -n juwan -- env | grep JWT_SECRET_KEY ``` ## 监控和日志 ### 查看 Pod 日志 ```bash # user-rpc 日志 kubectl logs -n juwan -l app=user-rpc -f --all-containers=true # Envoy 日志 kubectl logs -n juwan -l app=envoy-gateway -f ``` ### 检查 Pod 事件 ```bash # 查看 Pod 创建和启动事件 kubectl describe pod -n juwan -l app=user-rpc kubectl describe pod -n juwan -l app=envoy-gateway ``` ### 权限问题排查 如果 Pod 无法读取 Secret: ```bash # 检查 Pod 使用的 ServiceAccount kubectl get pod POD_NAME -n juwan -o yaml | grep serviceAccountName # 检查 RBAC 绑定 kubectl get rolebinding -n juwan -o wide # 检查 Role 权限定义 kubectl get role jwt-secret-reader -n juwan -o yaml # 尝试用 Pod 的身份读取 Secret(需要 kubectl-user-impersonate 或类似工具) kubectl get secret jwt-secret --as=system:serviceaccount:juwan:user-rpc -n juwan ``` ## 安全最佳实践 ### 1. 密钥轮换 周期性更换 JWT 秘钥(建议每季度): ```bash # 1. 生成新密钥 NEW_KEY=$(head -c 32 /dev/urandom | base64) # 2. 更新 Secret kubectl create secret generic jwt-secret \ --from-literal=secret-key=$NEW_KEY \ --dry-run=client -o yaml | kubectl apply -f - # 3. 重启 Pods 以加载新密钥(滚动更新) kubectl rollout restart deployment/user-rpc -n juwan kubectl rollout restart deployment/envoy-gateway -n juwan # 4. 验证新 Pods 已启动并运行 kubectl rollout status deployment/user-rpc -n juwan kubectl rollout status deployment/envoy-gateway -n juwan # 5. 已颁发的旧令牌将变为无效 # 需要用户重新登录获取新令牌 ``` ### 2. 审计和监控 在生产环境中启用 Kubernetes 审计日志来跟踪 Secret 访问: ```yaml # kube-apiserver 审计策略示例 apiVersion: audit.k8s.io/v1 kind: Policy rules: # 记录 secret 资源的访问 - level: RequestResponse verbs: ["get", "list", "watch"] resources: ["secrets"] # 记录所有认证失败 - level: RequestResponse omitStages: - RequestReceived userGroups: ["system:unauthenticated"] - level: Metadata omitStages: - RequestReceived ``` ### 3. 网络策略 使用 NetworkPolicy 限制 Pods 之间的通信: ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: jwt-secret-access namespace: juwan spec: podSelector: matchLabels: app: jwt-secret-reader policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: user-rpc - podSelector: matchLabels: app: envoy-gateway ports: - protocol: TCP port: 443 # API Server ``` ## 灾难恢复 ### 备份 Secret 和 RBAC 配置 ```bash # 备份 JWT Secret kubectl get secret jwt-secret -n juwan -o yaml > jwt-secret-backup.yaml # 备份 RBAC 配置 kubectl get role jwt-secret-reader -n juwan -o yaml > jwt-role-backup.yaml kubectl get rolebinding -n juwan -l app=jwt-secret-reader -o yaml > jwt-rolebinding-backup.yaml # 加密备份文件 gpg --symmetric jwt-secret-backup.yaml ``` ### 恢复步骤 如果 Secret 被意外删除: ```bash # 从备份恢复 kubectl apply -f jwt-secret-backup.yaml # 重启 Pods 以重新加载 Secret kubectl rollout restart deployment/user-rpc -n juwan kubectl rollout restart deployment/envoy-gateway -n juwan ``` ## 常见问题 ### Q: Pod 无法启动,显示 "failed to pull secret" A: 检查: 1. Secret 是否存在:`kubectl get secret jwt-secret -n juwan` 2. ServiceAccount 是否绑定了 RBAC:`kubectl describe rolebinding -n juwan` 3. Secret 名称和命名空间是否正确 ### Q: 加密后如何验证 ETCD 中的数据已加密? A: 从 control plane 节点: ```bash # 直接读取 ETCD(如果配置了加密,数据应该不可读) sudo strings /var/lib/etcd/member/snap/db | grep -i secret ``` ### Q: 能否更改加密密钥而不重新创建 ETCD? A: 可以,但流程复杂: 1. 更新 encryption-config.yaml 中的新密钥 2. 将新密钥添加到提供程序列表(保持旧密钥) 3. 重启 kube-apiserver 4. 触发重新加密:`kubectl get all --all-namespaces -o json | kubectl apply -f -` ### Q: 如何在 Minikube 中启用 ETCD 加密? A: 参考 `ENCRYPTION.md` 中的 Minikube 特定说明部分。 ## 相关文件 - `jwt-secret.yaml` - Secret 和 RBAC 配置 - `ENCRYPTION.md` - ETCD 加密详细文档 - `README.md` - 快速参考指南 - `/deploy/k8s/service/user/user-rpc.yaml` - user-rpc Deployment 配置 - `/deploy/k8s/envoy/envoy.yaml` - Envoy 网关 Deployment 配置 ## 下一步 部署完成后: 1. **集成 JWT 验证到 RPC Handlers** - 实现 gRPC unary interceptor - 验证令牌有效性 - 处理令牌刷新逻辑 2. **集成 JWT 验证到 Envoy** - 扩展 Lua filter 进行令牌验证 - 返回 401(无效令牌)或 200(有效令牌) 3. **端到端测试** - 创建用户和登录 - 生成和验证 JWT - 测试令牌刷新和撤销 - 验证 ETCD 加密 4. **生产部署** - 启用审计日志 - 配置密钥轮换计划 - 建立备份和恢复流程 - 监控 Secret 访问