# Envoy 配置完整清单 ## 📋 配置文件清单 ### 1. Proto 更新 - **文件**: [desc/rpc/users.proto](../../desc/rpc/users.proto) - **更改**: 添加了两个 RPC 方法 - `ValidateToken()`: 验证 token 是否有效(检查黑名单) - `CheckPermission()`: 检查用户权限 ### 2. Envoy 部署 - **配置文件**: [envoy.yaml](./envoy.yaml) - HTTP 监听器(端口 8080) - HTTPS 监听器(端口 8443) - JWT 验证过滤器 - CSRF 防护过滤器 - 速率限制(DDoS 防护) - 路由配置 - **K8s 部署**: [../k8s/envoy-gateway.yaml](../k8s/envoy-gateway.yaml) - 2 个副本 - 负载均衡器服务 - Service Account 和 RBAC - Network Policy - ConfigMap 用于配置管理 ### 3. 工具代码 - **JWKS 生成**: [app/users/rpc/internal/utils/jwks.go](../../app/users/rpc/internal/utils/jwks.go) - `GenerateJWKSFromSecret()`: 从 JWT 密钥生成 JWKS - `GenerateJWKSEndpoint()`: 生成 JSON 输出供 Envoy 使用 - `ExtractTokenMetadata()`: 提取 token 元数据 ### 4. Dockerfile - **文件**: [Dockerfile](./Dockerfile) - **用途**: 构建 Envoy 容器镜像 ### 5. 脚本 - **文件**: [generate-jwks.sh](./generate-jwks.sh) - **用途**: 快速生成 JWKS JSON 文件 ### 6. 文档 - **文件**: [ENVOY_CONFIG_GUIDE.md](./ENVOY_CONFIG_GUIDE.md) - **内容**: 详细的配置和部署指南 --- ## 🚀 快速部署步骤 ### 步骤 1: 生成 TLS 证书 ```bash # 测试环境:生成自签名证书 openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt \ -days 365 -nodes -subj "/CN=api.juwan.local" # 创建 K8s Secret kubectl create secret tls envoy-tls \ --cert=tls.crt \ --key=tls.key \ -n juwan ``` ### 步骤 2: 部署 Envoy Gateway ```bash # 应用部署文件 kubectl apply -f deploy/k8s/envoy-gateway.yaml # 验证部署 kubectl get pods -n juwan -l app=envoy-gateway kubectl get svc -n juwan envoy-gateway # 等待 LoadBalancer 获取外部 IP kubectl get svc -n juwan envoy-gateway -w ``` ### 步骤 3: 在 User RPC 中暴露 JWKS 端点 编辑 `app/users/rpc/rpcserver.go` 或 `main.go`: ```go package main import ( "http" "os" "juwan-backend/app/users/rpc/internal/utils" ) // 在启动 RPC server 前,添加 HTTP 端点 func setupJWKSEndpoint() { secretKey := os.Getenv("JWT_SECRET_KEY") if secretKey == "" { secretKey = "your-default-secret-key" } http.HandleFunc("/.well-known/jwks.json", func(w http.ResponseWriter, r *http.Request) { jwksJSON, err := utils.GenerateJWKSEndpoint(secretKey, "default-key-id") if err != nil { http.Error(w, "Failed to generate JWKS", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "public, max-age=300") // 缓存 5 分钟 w.Write([]byte(jwksJSON)) }) // 在独立的 goroutine 中启动 HTTP 服务器 go func() { http.ListenAndServe(":8080", nil) }() } func main() { setupJWKSEndpoint() // ... 其他 RPC 启动代码 ... } ``` ### 步骤 4: 更新 User RPC 配置 编辑 `app/users/rpc/etc/pb.yaml`: ```yaml Name: pb.rpc ListenOn: 0.0.0.0:9001 Prometheus: Host: 0.0.0.0 Port: 4001 Path: /metrics # ... 其他配置 ... Jwt: SecretKey: "${JWT_SECRET_KEY:your-secret-jwt-key-change-this-in-production}" Issuer: "juwan-user-rpc" ``` ### 步骤 5: 构建并推送容器镜像 ```bash # 构建 User API 镜像 docker build -t your-registry/user-api:latest ./app/users/api/ docker push your-registry/user-api:latest # 构建 User RPC 镜像 docker build -t your-registry/user-rpc:latest ./app/users/rpc/ docker push your-registry/user-rpc:latest # 构建 Envoy 镜像 docker build -f deploy/envoy/Dockerfile -t your-registry/envoy-gateway:latest . docker push your-registry/envoy-gateway:latest ``` ### 步骤 6: 更新 K8s 部署 更新 `deploy/k8s/service/user/user-api.yaml` 和 `user-rpc.yaml`,确保使用正确的镜像和环境变量。 --- ## 🧪 测试流程 ### 1. 登录获取 Token ```bash # 获取 Envoy 外部 IP ENVOY_IP=$(kubectl get svc -n juwan envoy-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') # 登录 curl -k -X POST "https://$ENVOY_IP:443/api/v1/users/login" \ -H "Content-Type: application/json" \ -d '{ "username": "testuser", "password": "password123" }' | jq . # 示例响应: # { # "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "expires": 1708780800 # } ``` ### 2. 使用 Token 访问受保护资源 ```bash TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." curl -k -X GET "https://$ENVOY_IP:443/api/v1/users/123" \ -H "Authorization: Bearer $TOKEN" | jq . ``` ### 3. 验证 CSRF 防护 ```bash # POST 请求必须有正确的 Origin/Referer curl -k -X POST "https://$ENVOY_IP:443/api/v1/users/logout" \ -H "Authorization: Bearer $TOKEN" \ -H "Origin: https://api.juwan.local" \ -H "Referer: https://api.juwan.local/" \ -H "Content-Type: application/json" \ -d '{"userId": 123}' ``` --- ## 📊 验证检查清单 - [ ] Envoy 容器运行正常 ```bash kubectl logs -n juwan -l app=envoy-gateway ``` - [ ] JWKS 端点可访问 ```bash kubectl exec -it -n juwan -- \ curl http://user-rpc-svc:9001/.well-known/jwks.json ``` - [ ] 后端服务健康 ```bash kubectl exec -it -n juwan -- \ curl http://user-api-svc:8888/health ``` - [ ] JWT 验证工作 ```bash # 不带 token 访问受保护资源应返回 401 curl -k https://api.juwan.local/api/v1/users/123 ``` - [ ] CSRF 防护生效 ```bash # 缺少 Origin header 的 POST 应被拒绝 curl -k -X POST https://api.juwan.local/api/v1/users/logout \ -H "Authorization: Bearer $TOKEN" ``` --- ## 🔧 配置调整 ### 修改 JWT 密钥 ```bash # 1. 更新 K8s Secret kubectl patch secret jwt-secret -n juwan \ -p '{"data":{"JWT_SECRET_KEY":"'$(echo -n 'new-secret-key' | base64)'"}}' # 2. 重启 User RPC 和 Envoy kubectl rollout restart deployment/user-rpc-svc -n juwan kubectl rollout restart deployment/envoy-gateway -n juwan ``` ### 调整 Envoy 速率限制 编辑 ConfigMap: ```bash kubectl edit cm envoy-config -n juwan ``` 修改 `token_bucket` 参数: ```yaml token_bucket: max_tokens: 5000 # 降低限制 tokens_per_fill: 5000 fill_interval: 1s ``` ### 添加信任的 CSRF 来源 编辑 ConfigMap: ```yaml additional_origins: - exact: "https://admin.juwan.local" - exact: "https://web.juwan.local" - prefix: "https://app.juwan.local" # 支持前缀匹配 ``` --- ## 📈 监控和日志 ### 查看 Envoy 统计 ```bash kubectl port-forward -n juwan svc/envoy-gateway 9901:9901 curl localhost:9901/stats | grep -E "(jwt_authn|csrf|http_ratelimit)" ``` ### 实时日志 ```bash kubectl logs -n juwan -l app=envoy-gateway -f # 查看特定日志行 kubectl logs -n juwan -l app=envoy-gateway | grep "401\|403" ``` ### 监控指标(集成 Prometheus) ```yaml # prometheus-scrape-config.yaml - job_name: 'envoy-gateway' static_configs: - targets: ['envoy-gateway.juwan.svc.cluster.local:9901'] metrics_path: '/stats/prometheus' ``` --- ## 📚 相关文件位置 ``` deploy/ ├── envoy/ │ ├── envoy.yaml ← Envoy 核心配置 │ ├── ENVOY_CONFIG_GUIDE.md ← 详细指南 │ ├── generate-jwks.sh ← JWKS 生成脚本 │ ├── Dockerfile ← Envoy 镜像 │ └── QUICK_REFERENCE.md ← 本文件 ├── k8s/ │ ├── envoy-gateway.yaml ← K8s 部署清单 │ └── secrets/jwt-secret.yaml ← JWT 密钥配置 └── script/ └── init-secrets.sh ← 初始化脚本 app/users/ ├── rpc/ │ ├── internal/utils/ │ │ ├── jwks.go ← JWKS 生成工具 │ │ └── jwt.go ← JWT 管理器 │ └── etc/pb.yaml ← RPC 配置 └── api/ └── etc/user-api.yaml ← API 配置 desc/ └── rpc/users.proto ← Proto 定义(已更新) ``` --- ## 🤔 常见问题 1. **Envoy 无法连接到后端服务** - 检查 K8s Service DNS: `user-api-svc.juwan.svc.cluster.local` - 验证 NetworkPolicy 允许流量 2. **JWT 验证失败** - 确保 JWT_SECRET_KEY 一致 - 检查 JWKS 端点是否可访问 - 查看 Envoy 日志: `grep "jwt_authn" envoy.log` 3. **CSRF 防护过于严格** - 在 `additional_origins` 中添加允许的来源 - 对于单页应用,确保发送 `Origin` header 4. **速率限制阻止正常流量** - 增加 `max_tokens` 和 `tokens_per_fill` - 针对特定客户端配置不同的限制 --- ## 📞 获取帮助 - 查看 [Envoy 官方文档](https://www.envoyproxy.io/docs) - 查看 [JWT 规范](https://tools.ietf.org/html/rfc7519) - 检查 [CSRF 防护最佳实践](https://owasp.org/www-community/attacks/csrf)