add:
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
# 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 <envoy-pod> -- \
|
||||
curl http://user-rpc-svc:9001/.well-known/jwks.json
|
||||
```
|
||||
|
||||
- [ ] 后端服务健康
|
||||
```bash
|
||||
kubectl exec -it -n juwan <envoy-pod> -- \
|
||||
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)
|
||||
Reference in New Issue
Block a user