Files
juwan-backend/deploy/envoy/ENVOY_CONFIG_GUIDE.md
T
wwweww fdbcde13b2 add:
2026-02-23 20:36:21 +08:00

321 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <envoy-pod> -- \
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 <envoy-pod> -- \
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)