# Envoy Gateway 配置指南 ## 概述 Envoy Gateway 作为 API 统一入口,提供以下功能: - **JWT 身份验证**:所有 API 请求(除登录/注册)都需要有效的 JWT token - **CSRF 防护**:防止跨站点请求伪造攻击 - **速率限制**:防止 DDoS 攻击 - **TLS 加密**:所有通信都加密 - **负载均衡**:分担后端服务的流量 ## 架构 ``` ┌─────────────┐ │ Client │ └──────┬──────┘ │ HTTP/HTTPS (Port 80/443) │ ┌──────▼────────────────┐ │ Envoy Gateway │ │ ┌────────────────┐ │ │ │ JWT Validator │ │ ◄─── JWT Verification (offline) │ │ CSRF Filter │ │ │ │ Rate Limiter │ │ │ │ Router │ │ │ └────────────────┘ │ └────────┬─────────────┘ │ gRPC/HTTP ┌────┴────┬──────────┐ │ │ │ ┌───▼──┐ ┌──▼────┐ ┌──▼─────┐ │User │ │Order │ │User │ │API │ │API │ │RPC │ └──────┘ └───────┘ └────────┘ ``` ## 部署步骤 ### 1. 生成 TLS 证书 ```bash # 为 Envoy 生成自签名证书(生产环境应使用正式证书) kubectl create secret tls envoy-tls \ --cert=path/to/tls.crt \ --key=path/to/tls.key \ -n juwan # 或生成自签名证书(仅用于测试) openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt \ -days 365 -nodes -subj "/CN=api.juwan.local" kubectl create secret tls envoy-tls \ --cert=tls.crt \ --key=tls.key \ -n juwan ``` ### 2. 部署 Envoy Gateway ```bash # 应用 Envoy 配置 kubectl apply -f deploy/k8s/envoy-gateway.yaml # 查看部署状态 kubectl get pods -n juwan -l app=envoy-gateway kubectl get svc -n juwan envoy-gateway ``` ### 3. 配置 JWKS 端点 在 user-rpc 中暴露 JWKS 端点,供 Envoy 验证 JWT: #### 在 `app/users/rpc` 中添加 HTTP 路由(go-zero) 编辑 `app/users/rpc/internal/handler/` 或在 `main.go` 中: ```go // 在 rpc server 启动时,添加 HTTP 端点用于暴露 JWKS import ( "net/http" "juwan-backend/app/users/rpc/internal/utils" ) // 在 main 函数中 http.HandleFunc("/.well-known/jwks.json", func(w http.ResponseWriter, r *http.Request) { secretKey := os.Getenv("JWT_SECRET_KEY") if secretKey == "" { secretKey = "your-default-secret-key" } 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.Write([]byte(jwksJSON)) }) // 在单独的 goroutine 中启动 HTTP 服务器 go func() { http.ListenAndServe(":8080", nil) }() ``` **或使用 Echo 框架(更推荐)**: ```go // 在 main.go 中 import "github.com/labstack/echo/v4" e := echo.New() e.GET("/.well-known/jwks.json", func(c echo.Context) error { secretKey := os.Getenv("JWT_SECRET_KEY") jwksJSON, _ := utils.GenerateJWKSEndpoint(secretKey, "default-key-id") return c.JSONBlob(http.StatusOK, []byte(jwksJSON)) }) go func() { e.Start(":8080") }() ``` ### 4. 更新环境变量 在 K8s Secret 中配置 JWT_SECRET_KEY: ```yaml apiVersion: v1 kind: Secret metadata: name: jwt-secret namespace: juwan type: Opaque data: JWT_SECRET_KEY: "$(echo -n 'your-secret-key-change-this' | base64)" ``` ### 5. 验证 JWKS 端点 ```bash # 端口转发 kubectl port-forward -n juwan svc/user-rpc-svc 9001:9001 # 验证 JWKS 端点可访问 curl http://localhost:9001/.well-known/jwks.json ``` ## JWT 验证流程 ### 1. 登录获取 Token ```bash curl -X POST http://api.juwan.local/api/v1/users/login \ -H "Content-Type: application/json" \ -d '{ "username": "testuser", "password": "password123" }' # 响应: # { # "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "expires": 1708780800 # } ``` ### 2. 使用 Token 访问受保护资源 ```bash curl -H "Authorization: Bearer YOUR_TOKEN" \ https://api.juwan.local/api/v1/users/123 # Envoy 验证步骤: # 1. 从 Authorization header 提取 token # 2. 从 JWKS 端点获取公钥(缓存 5 分钟) # 3. 验证 token 签名 # 4. 检查 token 过期时间 # 5. 将验证后的用户信息添加到请求头(X-USER-ID) # 6. 转发请求到 user-api ``` ## CSRF 防护 ### 配置说明 Envoy 的 CSRF 过滤器检查: - 只对 POST/PUT/DELETE/PATCH 请求进行检查 - 检查 `Origin` 和 `Referer` header - 验证请求来自已知域名 ### 跨域请求配置 ```yaml # Envoy 配置中允许的来源 additional_origins: - exact: "https://admin.juwan.local" - exact: "https://web.juwan.local" ``` ## Token 黑名单检查(可选) 如果需要验证 token 未被撤销,可启用额外的 RPC 验证: ```yaml # envoy-gateway.yaml 中取消注释 - name: envoy.filters.http.ext_authz typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz grpc_service: envoy_grpc: cluster_name: user_rpc_cluster failure_mode_allow: false ``` 然后在 user-rpc 中实现 ValidateToken RPC: ```protobuf rpc ValidateToken(ValidateTokenReq) returns(ValidateTokenResp); ``` ## 故障排查 ### 1. JWT 验证失败 ```bash # 查看 Envoy 日志 kubectl logs -n juwan -l app=envoy-gateway -f # 验证 JWKS 端点是否可访问 kubectl exec -it -n juwan -- \ curl http://user-rpc-svc:9001/.well-known/jwks.json ``` ### 2. 无法连接到后端服务 ```bash # 验证服务发现 kubectl get endpoints -n juwan # 验证网络策略 kubectl get networkpolicy -n juwan # 测试连接 kubectl exec -it -n juwan -- \ curl http://user-api-svc:8888/health ``` ### 3. CSRF 错误 - 确保设置了 `Origin` 和 `Referer` header - 检查 `additional_origins` 配置是否包含你的域名 ## 性能优化 ### 1. JWKS 缓存 ```yaml cache_ttl: seconds: 300 # 缓存 5 分钟,减少 RPC 调用 ``` ### 2. 连接池 ```yaml http2_protocol_options: {} # 启用 HTTP/2 多路复用 ``` ### 3. 速率限制调整 根据实际流量调整令牌桶参数: ```yaml token_bucket: max_tokens: 10000 # 最大令牌数 tokens_per_fill: 10000 # 每次填充的令牌数 fill_interval: 1s # 填充间隔 ``` ## 监控和日志 ### 访问日志 ```bash # 查看访问日志 kubectl logs -n juwan -l app=envoy-gateway --follow # 格式包含: # - 请求时间、方法、路径 # - 响应状态码、字节数 # - 上游服务信息 ``` ### Prometheus 指标 Envoy 在 `:9901/stats` 暴露 Prometheus 指标: ```bash kubectl port-forward -n juwan svc/envoy-gateway 9901:9901 curl localhost:9901/stats | grep jwt ``` ## 生产环境检查清单 - [ ] 使用正式 TLS 证书(不是自签名) - [ ] 配置正确的 JWT_SECRET_KEY(强密码) - [ ] 启用 HTTPS(关闭 HTTP) - [ ] 配置网络策略限制访问 - [ ] 启用访问日志和监控 - [ ] 设置合理的速率限制 - [ ] 测试 token 过期和刷新流程 - [ ] 配置告警规则 ## 参考文档 - [Envoy JWT Authentication](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto) - [Envoy CSRF Protection](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/csrf/v3/csrf.proto) - [JWT RFC 7519](https://tools.ietf.org/html/rfc7519)