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

7.9 KiB
Raw Blame History

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 证书

# 为 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

# 应用 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 中:

// 在 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 框架(更推荐)

// 在 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

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 端点

# 端口转发
kubectl port-forward -n juwan svc/user-rpc-svc 9001:9001

# 验证 JWKS 端点可访问
curl http://localhost:9001/.well-known/jwks.json

JWT 验证流程

1. 登录获取 Token

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 访问受保护资源

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 请求进行检查
  • 检查 OriginReferer header
  • 验证请求来自已知域名

跨域请求配置

# Envoy 配置中允许的来源
additional_origins:
  - exact: "https://admin.juwan.local"
  - exact: "https://web.juwan.local"

Token 黑名单检查(可选)

如果需要验证 token 未被撤销,可启用额外的 RPC 验证:

# 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

rpc ValidateToken(ValidateTokenReq) returns(ValidateTokenResp);

故障排查

1. JWT 验证失败

# 查看 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. 无法连接到后端服务

# 验证服务发现
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 错误

  • 确保设置了 OriginReferer header
  • 检查 additional_origins 配置是否包含你的域名

性能优化

1. JWKS 缓存

cache_ttl:
  seconds: 300  # 缓存 5 分钟,减少 RPC 调用

2. 连接池

http2_protocol_options: {}  # 启用 HTTP/2 多路复用

3. 速率限制调整

根据实际流量调整令牌桶参数:

token_bucket:
  max_tokens: 10000        # 最大令牌数
  tokens_per_fill: 10000   # 每次填充的令牌数
  fill_interval: 1s        # 填充间隔

监控和日志

访问日志

# 查看访问日志
kubectl logs -n juwan -l app=envoy-gateway --follow

# 格式包含:
# - 请求时间、方法、路径
# - 响应状态码、字节数
# - 上游服务信息

Prometheus 指标

Envoy 在 :9901/stats 暴露 Prometheus 指标:

kubectl port-forward -n juwan svc/envoy-gateway 9901:9901
curl localhost:9901/stats | grep jwt

生产环境检查清单

  • 使用正式 TLS 证书(不是自签名)
  • 配置正确的 JWT_SECRET_KEY(强密码)
  • 启用 HTTPS(关闭 HTTP
  • 配置网络策略限制访问
  • 启用访问日志和监控
  • 设置合理的速率限制
  • 测试 token 过期和刷新流程
  • 配置告警规则

参考文档