add:
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user