fix: clean shit
在原始配置基础上重新应用限流功能,恢复丢失的路由和服务依赖。
This commit is contained in:
@@ -38,8 +38,6 @@ services:
|
|||||||
rl-redis:
|
rl-redis:
|
||||||
image: redis:${REDIS_VERSION:-8}
|
image: redis:${REDIS_VERSION:-8}
|
||||||
container_name: ${REDIS_CONTAINER_NAME:-rl-redis-dev-server}
|
container_name: ${REDIS_CONTAINER_NAME:-rl-redis-dev-server}
|
||||||
profiles:
|
|
||||||
- infra
|
|
||||||
ports:
|
ports:
|
||||||
- "6380:6379"
|
- "6380:6379"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -86,42 +84,62 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
|
|
||||||
envoy-gateway:
|
envoy-gateway:
|
||||||
build:
|
image: envoyproxy/envoy:v1.31-latest
|
||||||
context: ../deploy/dev/envoy
|
container_name: juwan-envoy-gateway
|
||||||
image: envoy-gateway:latest
|
restart: unless-stopped
|
||||||
container_name: ${ENVOY_GATEWAY_CONTAINER_NAME:-envoy-gateway-dev-server}
|
command:
|
||||||
|
- /usr/local/bin/envoy
|
||||||
|
- -c
|
||||||
|
- /etc/envoy/envoy.yaml
|
||||||
|
- --log-level
|
||||||
|
- info
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "18080:8080"
|
||||||
- "9901:9901"
|
volumes:
|
||||||
|
- ./envoy.yaml:/etc/envoy/envoy.yaml:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
authz-adapter:
|
authz-adapter:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
required: false
|
users-api:
|
||||||
user-api:
|
condition: service_started
|
||||||
|
player-api:
|
||||||
|
condition: service_started
|
||||||
|
game-api:
|
||||||
|
condition: service_started
|
||||||
|
shop-api:
|
||||||
|
condition: service_started
|
||||||
|
order-api:
|
||||||
|
condition: service_started
|
||||||
|
wallet-api:
|
||||||
|
condition: service_started
|
||||||
|
community-api:
|
||||||
|
condition: service_started
|
||||||
|
objectstory-api:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
required: false
|
|
||||||
email-api:
|
email-api:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
required: false
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
ratelimit:
|
ratelimit:
|
||||||
image: ratelimit:latest
|
image: envoyproxy/ratelimit:05c08d03
|
||||||
container_name: rl-service
|
container_name: rl-service
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
command: /bin/ratelimit
|
||||||
environment:
|
environment:
|
||||||
- REDIS_SOCKET_TYPE=tcp
|
- REDIS_SOCKET_TYPE=tcp
|
||||||
- REDIS_URL=rl-redis:6379
|
- REDIS_URL=rl-redis:6379
|
||||||
- USE_STATSD=false
|
- USE_STATSD=false
|
||||||
- RUNTIME_ROOT=/data
|
- RUNTIME_ROOT=/data
|
||||||
- RUNTIME_SUBDIRECTORY=ratelimit
|
- RUNTIME_SUBDIRECTORY=ratelimit
|
||||||
- RUNTIME_WATCH_ROOT=true # 热重载
|
- RUNTIME_WATCH_ROOT=true
|
||||||
- LOG_LEVEL=debug
|
- LOG_LEVEL=debug
|
||||||
volumes:
|
volumes:
|
||||||
- ./rls/ratelimit.yaml:/data/ratelimit/config/ratelimit.yaml:ro
|
- ./rls/ratelimit.yaml:/data/ratelimit/config/ratelimit.yaml:ro
|
||||||
ports:
|
ports:
|
||||||
- "8081:8081"
|
- "18081:8081"
|
||||||
- "6070:6070"
|
- "16070:6070"
|
||||||
|
depends_on:
|
||||||
|
rl-redis:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
# ==================== RPC 层 ====================
|
# ==================== RPC 层 ====================
|
||||||
user-rpc:
|
user-rpc:
|
||||||
|
|||||||
+77
-4
@@ -14,6 +14,7 @@ static_resources:
|
|||||||
codec_type: AUTO
|
codec_type: AUTO
|
||||||
generate_request_id: true
|
generate_request_id: true
|
||||||
use_remote_address: true
|
use_remote_address: true
|
||||||
|
xff_num_trusted_hops: 1
|
||||||
route_config:
|
route_config:
|
||||||
name: local_route
|
name: local_route
|
||||||
virtual_hosts:
|
virtual_hosts:
|
||||||
@@ -36,6 +37,11 @@ static_resources:
|
|||||||
route:
|
route:
|
||||||
cluster: user_api_cluster
|
cluster: user_api_cluster
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
|
rate_limits:
|
||||||
|
- actions:
|
||||||
|
- generic_key:
|
||||||
|
descriptor_value: login
|
||||||
|
- remote_address: {}
|
||||||
typed_per_filter_config:
|
typed_per_filter_config:
|
||||||
envoy.filters.http.ext_authz:
|
envoy.filters.http.ext_authz:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
@@ -46,6 +52,11 @@ static_resources:
|
|||||||
route:
|
route:
|
||||||
cluster: user_api_cluster
|
cluster: user_api_cluster
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
|
rate_limits:
|
||||||
|
- actions:
|
||||||
|
- generic_key:
|
||||||
|
descriptor_value: register
|
||||||
|
- remote_address: {}
|
||||||
typed_per_filter_config:
|
typed_per_filter_config:
|
||||||
envoy.filters.http.ext_authz:
|
envoy.filters.http.ext_authz:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
@@ -76,6 +87,11 @@ static_resources:
|
|||||||
route:
|
route:
|
||||||
cluster: email_api_cluster
|
cluster: email_api_cluster
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
|
rate_limits:
|
||||||
|
- actions:
|
||||||
|
- generic_key:
|
||||||
|
descriptor_value: forgot_password_send
|
||||||
|
- remote_address: {}
|
||||||
typed_per_filter_config:
|
typed_per_filter_config:
|
||||||
envoy.filters.http.ext_authz:
|
envoy.filters.http.ext_authz:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
@@ -86,6 +102,11 @@ static_resources:
|
|||||||
route:
|
route:
|
||||||
cluster: email_api_cluster
|
cluster: email_api_cluster
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
|
rate_limits:
|
||||||
|
- actions:
|
||||||
|
- generic_key:
|
||||||
|
descriptor_value: verify_code_send
|
||||||
|
- remote_address: {}
|
||||||
typed_per_filter_config:
|
typed_per_filter_config:
|
||||||
envoy.filters.http.ext_authz:
|
envoy.filters.http.ext_authz:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
@@ -307,14 +328,37 @@ static_resources:
|
|||||||
body:
|
body:
|
||||||
inline_string: gateway route not found
|
inline_string: gateway route not found
|
||||||
|
|
||||||
|
access_log:
|
||||||
|
- name: envoy.access_loggers.stdout
|
||||||
|
typed_config:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
|
||||||
|
log_format:
|
||||||
|
json_format:
|
||||||
|
start_time: "%START_TIME%"
|
||||||
|
method: "%REQ(:METHOD)%"
|
||||||
|
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
|
||||||
|
protocol: "%PROTOCOL%"
|
||||||
|
authority: "%REQ(:AUTHORITY)%"
|
||||||
|
user_agent: "%REQ(USER-AGENT)%"
|
||||||
|
request_id: "%REQ(X-REQUEST-ID)%"
|
||||||
|
response_code: "%RESPONSE_CODE%"
|
||||||
|
response_flags: "%RESPONSE_FLAGS%"
|
||||||
|
bytes_received: "%BYTES_RECEIVED%"
|
||||||
|
bytes_sent: "%BYTES_SENT%"
|
||||||
|
duration_ms: "%DURATION%"
|
||||||
|
upstream_cluster: "%UPSTREAM_CLUSTER%"
|
||||||
|
upstream_host: "%UPSTREAM_HOST%"
|
||||||
|
upstream_service_time_ms: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
|
||||||
|
route_name: "%ROUTE_NAME%"
|
||||||
|
|
||||||
http_filters:
|
http_filters:
|
||||||
- name: envoy.filters.http.lua
|
- name: envoy.filters.http.lua
|
||||||
typed_config:
|
typed_config:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
|
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
|
||||||
inline_code: |
|
inline_code: |
|
||||||
local TOKEN_HEADER = "xsrf-token"
|
local TOKEN_HEADER = "xsrf-token"
|
||||||
local TOKEN_COOKIE = "XSRF-TOKEN"
|
local TOKEN_COOKIE = "__Host-XSRF-TOKEN"
|
||||||
local GUARD_COOKIE = "XSRF-GUARD"
|
local GUARD_COOKIE = "__Host-XSRF-GUARD"
|
||||||
|
|
||||||
local seeded = false
|
local seeded = false
|
||||||
|
|
||||||
@@ -420,14 +464,14 @@ static_resources:
|
|||||||
if metadata["need_set_token_cookie"] == true and token_value ~= nil and token_value ~= "" then
|
if metadata["need_set_token_cookie"] == true and token_value ~= nil and token_value ~= "" then
|
||||||
response_handle:headers():add(
|
response_handle:headers():add(
|
||||||
"set-cookie",
|
"set-cookie",
|
||||||
TOKEN_COOKIE .. "=" .. token_value .. "; Path=/; Max-Age=7200; SameSite=Strict"
|
TOKEN_COOKIE .. "=" .. token_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
if metadata["need_set_guard_cookie"] == true and guard_value ~= nil and guard_value ~= "" then
|
if metadata["need_set_guard_cookie"] == true and guard_value ~= nil and guard_value ~= "" then
|
||||||
response_handle:headers():add(
|
response_handle:headers():add(
|
||||||
"set-cookie",
|
"set-cookie",
|
||||||
GUARD_COOKIE .. "=" .. guard_value .. "; Path=/; Max-Age=7200; SameSite=Strict; HttpOnly"
|
GUARD_COOKIE .. "=" .. guard_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure; HttpOnly"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -539,6 +583,20 @@ static_resources:
|
|||||||
cluster_name: authz_adapter_cluster
|
cluster_name: authz_adapter_cluster
|
||||||
timeout: 0.5s
|
timeout: 0.5s
|
||||||
|
|
||||||
|
- name: envoy.filters.http.ratelimit
|
||||||
|
typed_config:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
|
||||||
|
domain: api
|
||||||
|
failure_mode_deny: false
|
||||||
|
rate_limited_as_resource_exhausted: true
|
||||||
|
enable_x_ratelimit_headers: DRAFT_VERSION_03
|
||||||
|
rate_limit_service:
|
||||||
|
transport_api_version: V3
|
||||||
|
grpc_service:
|
||||||
|
envoy_grpc:
|
||||||
|
cluster_name: ratelimit_cluster
|
||||||
|
timeout: 0.2s
|
||||||
|
|
||||||
- name: envoy.filters.http.router
|
- name: envoy.filters.http.router
|
||||||
typed_config:
|
typed_config:
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
|
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
|
||||||
@@ -685,6 +743,21 @@ static_resources:
|
|||||||
address: authz-adapter
|
address: authz-adapter
|
||||||
port_value: 9002
|
port_value: 9002
|
||||||
|
|
||||||
|
- name: ratelimit_cluster
|
||||||
|
connect_timeout: 0.25s
|
||||||
|
type: STRICT_DNS
|
||||||
|
lb_policy: ROUND_ROBIN
|
||||||
|
http2_protocol_options: {}
|
||||||
|
load_assignment:
|
||||||
|
cluster_name: ratelimit_cluster
|
||||||
|
endpoints:
|
||||||
|
- lb_endpoints:
|
||||||
|
- endpoint:
|
||||||
|
address:
|
||||||
|
socket_address:
|
||||||
|
address: ratelimit
|
||||||
|
port_value: 8081
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
access_log_path: /tmp/admin.log
|
access_log_path: /tmp/admin.log
|
||||||
address:
|
address:
|
||||||
|
|||||||
@@ -1,626 +0,0 @@
|
|||||||
static_resources:
|
|
||||||
listeners:
|
|
||||||
- name: ingress_http
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: 0.0.0.0
|
|
||||||
port_value: 8080
|
|
||||||
filter_chains:
|
|
||||||
- filters:
|
|
||||||
- name: envoy.filters.network.http_connection_manager
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
|
|
||||||
stat_prefix: ingress_http
|
|
||||||
codec_type: AUTO
|
|
||||||
generate_request_id: true
|
|
||||||
use_remote_address: true
|
|
||||||
xff_num_trusted_hops: 1
|
|
||||||
route_config:
|
|
||||||
name: local_route
|
|
||||||
virtual_hosts:
|
|
||||||
- name: juwan_services
|
|
||||||
domains: [ "*" ]
|
|
||||||
routes:
|
|
||||||
- match:
|
|
||||||
path: /healthz
|
|
||||||
direct_response:
|
|
||||||
status: 200
|
|
||||||
body:
|
|
||||||
inline_string: ok
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/login
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
rate_limits:
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: login
|
|
||||||
- remote_address: {}
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/register
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
rate_limits:
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: register
|
|
||||||
- generic_key:
|
|
||||||
descriptor_key: "period"
|
|
||||||
descriptor_value: "minute"
|
|
||||||
- remote_address: {}
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/forgot-password
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/reset-password
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/forgot-password/send
|
|
||||||
route:
|
|
||||||
cluster: email_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
rate_limits:
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: forgot_password_send
|
|
||||||
- generic_key:
|
|
||||||
descriptor_key: "period"
|
|
||||||
descriptor_value: "minute"
|
|
||||||
- remote_address: {}
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: forgot_password_send
|
|
||||||
- generic_key:
|
|
||||||
descriptor_key: "period"
|
|
||||||
descriptor_value: "hour"
|
|
||||||
- remote_address: {}
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/users
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/shop
|
|
||||||
route:
|
|
||||||
cluster: shop_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/player
|
|
||||||
route:
|
|
||||||
cluster: player_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/games
|
|
||||||
route:
|
|
||||||
cluster: game_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/games
|
|
||||||
headers:
|
|
||||||
- name: :method
|
|
||||||
exact_match: GET
|
|
||||||
route:
|
|
||||||
cluster: game_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
path: /api/v1/email/verification-code/send
|
|
||||||
route:
|
|
||||||
cluster: email_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
rate_limits:
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: verify_code_send
|
|
||||||
- generic_key:
|
|
||||||
descriptor_key: "period"
|
|
||||||
descriptor_value: "minute"
|
|
||||||
- remote_address: {}
|
|
||||||
- actions:
|
|
||||||
- generic_key:
|
|
||||||
descriptor_value: verify_code_send
|
|
||||||
- generic_key:
|
|
||||||
descriptor_key: "period"
|
|
||||||
descriptor_value: "hour"
|
|
||||||
- remote_address: {}
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/wallet
|
|
||||||
route:
|
|
||||||
cluster: wallet_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/players
|
|
||||||
route:
|
|
||||||
cluster: player_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/orders
|
|
||||||
route:
|
|
||||||
cluster: order_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/email
|
|
||||||
route:
|
|
||||||
cluster: email_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/auth
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/upload
|
|
||||||
route:
|
|
||||||
cluster: objectstory_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/files
|
|
||||||
route:
|
|
||||||
cluster: objectstory_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
typed_per_filter_config:
|
|
||||||
envoy.filters.http.ext_authz:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
|
||||||
disabled: true
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/email
|
|
||||||
route:
|
|
||||||
cluster: email_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1/game
|
|
||||||
route:
|
|
||||||
cluster: game_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1
|
|
||||||
route:
|
|
||||||
cluster: user_api_cluster
|
|
||||||
timeout: 30s
|
|
||||||
|
|
||||||
- match:
|
|
||||||
prefix: /
|
|
||||||
direct_response:
|
|
||||||
status: 404
|
|
||||||
body:
|
|
||||||
inline_string: gateway route not found
|
|
||||||
access_log:
|
|
||||||
- name: envoy.access_loggers.stdout
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
|
|
||||||
log_format:
|
|
||||||
json_format:
|
|
||||||
start_time: "%START_TIME%"
|
|
||||||
method: "%REQ(:METHOD)%"
|
|
||||||
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
|
|
||||||
protocol: "%PROTOCOL%"
|
|
||||||
authority: "%REQ(:AUTHORITY)%"
|
|
||||||
user_agent: "%REQ(USER-AGENT)%"
|
|
||||||
request_id: "%REQ(X-REQUEST-ID)%"
|
|
||||||
response_code: "%RESPONSE_CODE%"
|
|
||||||
response_flags: "%RESPONSE_FLAGS%"
|
|
||||||
bytes_received: "%BYTES_RECEIVED%"
|
|
||||||
bytes_sent: "%BYTES_SENT%"
|
|
||||||
duration_ms: "%DURATION%"
|
|
||||||
upstream_cluster: "%UPSTREAM_CLUSTER%"
|
|
||||||
upstream_host: "%UPSTREAM_HOST%"
|
|
||||||
upstream_service_time_ms: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
|
|
||||||
route_name: "%ROUTE_NAME%"
|
|
||||||
http_filters:
|
|
||||||
- name: envoy.filters.http.lua
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
|
|
||||||
inline_code: |
|
|
||||||
local TOKEN_HEADER = "xsrf-token"
|
|
||||||
local TOKEN_COOKIE = "__Host-XSRF-TOKEN"
|
|
||||||
local GUARD_COOKIE = "__Host-XSRF-GUARD"
|
|
||||||
|
|
||||||
local seeded = false
|
|
||||||
|
|
||||||
local function seed_random()
|
|
||||||
if seeded then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
seeded = true
|
|
||||||
math.randomseed(os.time())
|
|
||||||
end
|
|
||||||
|
|
||||||
local function split_cookie(header)
|
|
||||||
local out = {}
|
|
||||||
if not header then
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
for pair in string.gmatch(header, "([^;]+)") do
|
|
||||||
local key, value = string.match(pair, "^%s*([^=]+)=?(.*)$")
|
|
||||||
if key ~= nil and value ~= nil then
|
|
||||||
out[string.lower(key)] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local function is_safe_method(method)
|
|
||||||
return method == "GET" or method == "HEAD" or method == "OPTIONS"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function build_token(request_id)
|
|
||||||
seed_random()
|
|
||||||
local rnd = tostring(math.random(100000, 999999))
|
|
||||||
local rid = request_id or "rid"
|
|
||||||
return tostring(os.time()) .. "-" .. rid .. "-" .. rnd
|
|
||||||
end
|
|
||||||
|
|
||||||
function envoy_on_request(request_handle)
|
|
||||||
local headers = request_handle:headers()
|
|
||||||
local method = headers:get(":method")
|
|
||||||
|
|
||||||
local cookie_header = headers:get("cookie")
|
|
||||||
local cookies = split_cookie(cookie_header)
|
|
||||||
local token_cookie = cookies[string.lower(TOKEN_COOKIE)]
|
|
||||||
local guard_cookie = cookies[string.lower(GUARD_COOKIE)]
|
|
||||||
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "need_set_token_cookie", token_cookie == nil or token_cookie == "")
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "need_set_guard_cookie", guard_cookie == nil or guard_cookie == "")
|
|
||||||
|
|
||||||
if token_cookie == nil or token_cookie == "" then
|
|
||||||
token_cookie = build_token(headers:get("x-request-id"))
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", token_cookie)
|
|
||||||
else
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", token_cookie)
|
|
||||||
end
|
|
||||||
|
|
||||||
if guard_cookie == nil or guard_cookie == "" then
|
|
||||||
guard_cookie = build_token(headers:get("x-request-id"))
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", guard_cookie)
|
|
||||||
else
|
|
||||||
request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", guard_cookie)
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_safe_method(method) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local token_header = headers:get(TOKEN_HEADER)
|
|
||||||
|
|
||||||
if token_header == nil or token_header == "" then
|
|
||||||
request_handle:respond(
|
|
||||||
{[":status"] = "403", ["content-type"] = "application/json"},
|
|
||||||
'{"code":403,"message":"missing XSRF-TOKEN header"}'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if token_cookie == nil or token_cookie == "" or guard_cookie == nil or guard_cookie == "" then
|
|
||||||
request_handle:respond(
|
|
||||||
{[":status"] = "403", ["content-type"] = "application/json"},
|
|
||||||
'{"code":403,"message":"missing csrf cookies"}'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if token_header ~= token_cookie then
|
|
||||||
request_handle:respond(
|
|
||||||
{[":status"] = "403", ["content-type"] = "application/json"},
|
|
||||||
'{"code":403,"message":"xsrf token mismatch"}'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function envoy_on_response(response_handle)
|
|
||||||
local metadata = response_handle:streamInfo():dynamicMetadata():get("csrf")
|
|
||||||
if metadata == nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local token_value = metadata["token_value"]
|
|
||||||
local guard_value = metadata["guard_value"]
|
|
||||||
|
|
||||||
if metadata["need_set_token_cookie"] == true and token_value ~= nil and token_value ~= "" then
|
|
||||||
response_handle:headers():add(
|
|
||||||
"set-cookie",
|
|
||||||
TOKEN_COOKIE .. "=" .. token_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if metadata["need_set_guard_cookie"] == true and guard_value ~= nil and guard_value ~= "" then
|
|
||||||
response_handle:headers():add(
|
|
||||||
"set-cookie",
|
|
||||||
GUARD_COOKIE .. "=" .. guard_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure; HttpOnly"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
- name: envoy.filters.http.jwt_authn
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
|
|
||||||
providers:
|
|
||||||
juwan_user_jwt:
|
|
||||||
issuer: juwan-user-rpc
|
|
||||||
from_cookies:
|
|
||||||
- JToken
|
|
||||||
local_jwks:
|
|
||||||
inline_string: '{"keys":[{"kty":"oct","k":"TUdVeU1XRTNaRGhqTVRRNVpEZzFNV1ZpT1dVME1HTTNPVEUyTldWa1lUQmxPVEU1WldSa1pEVTFZall6T0dKak9XUmlOek0wTlRjNE5ESXlNamxrWlE","alg":"HS256","use":"sig","kid":"juwan-hs256-1"}]}'
|
|
||||||
forward: false
|
|
||||||
claim_to_headers:
|
|
||||||
- header_name: x-auth-user-id
|
|
||||||
claim_name: UserId
|
|
||||||
- header_name: x-auth-is-admin
|
|
||||||
claim_name: IsAdmin
|
|
||||||
rules:
|
|
||||||
- match:
|
|
||||||
path: /healthz
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1
|
|
||||||
headers:
|
|
||||||
- name: :method
|
|
||||||
exact_match: OPTIONS
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/login
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/register
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/forgot-password
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/reset-password
|
|
||||||
- match:
|
|
||||||
path: /api/v1/auth/forgot-password/send
|
|
||||||
- match:
|
|
||||||
path: /api/v1/email/verification-code/send
|
|
||||||
- match:
|
|
||||||
prefix: /api/v1
|
|
||||||
requires:
|
|
||||||
provider_name: juwan_user_jwt
|
|
||||||
- match:
|
|
||||||
prefix: /api/users
|
|
||||||
requires:
|
|
||||||
provider_name: juwan_user_jwt
|
|
||||||
- match:
|
|
||||||
prefix: /api/email
|
|
||||||
requires:
|
|
||||||
provider_name: juwan_user_jwt
|
|
||||||
|
|
||||||
- name: envoy.filters.http.ext_authz
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
|
|
||||||
transport_api_version: V3
|
|
||||||
failure_mode_allow: false
|
|
||||||
with_request_body:
|
|
||||||
max_request_bytes: 8192
|
|
||||||
allow_partial_message: true
|
|
||||||
grpc_service:
|
|
||||||
envoy_grpc:
|
|
||||||
cluster_name: authz_adapter_cluster
|
|
||||||
timeout: 0.5s
|
|
||||||
|
|
||||||
# RLS 全局过滤器
|
|
||||||
- name: envoy.filters.http.ratelimit
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
|
|
||||||
domain: api
|
|
||||||
failure_mode_deny: false
|
|
||||||
rate_limited_as_resource_exhausted: true
|
|
||||||
enable_x_ratelimit_headers: DRAFT_VERSION_03
|
|
||||||
rate_limit_service:
|
|
||||||
transport_api_version: V3
|
|
||||||
grpc_service:
|
|
||||||
envoy_grpc:
|
|
||||||
cluster_name: ratelimit_cluster
|
|
||||||
timeout: 0.2s
|
|
||||||
|
|
||||||
- name: envoy.filters.http.router
|
|
||||||
typed_config:
|
|
||||||
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
|
|
||||||
|
|
||||||
clusters:
|
|
||||||
- name: user_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: user_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: user-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: email_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: email_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: email-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: shop_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: shop_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: shop-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: game_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: game_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: game-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: objectstory_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: objectstory_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: objectstory-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: wallet_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: wallet_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: wallet-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: order_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: order_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: order-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: player_api_cluster
|
|
||||||
connect_timeout: 2s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: player_api_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: player-api
|
|
||||||
port_value: 8888
|
|
||||||
|
|
||||||
- name: authz_adapter_cluster
|
|
||||||
connect_timeout: 0.5s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
http2_protocol_options: { }
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: authz_adapter_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: authz-adapter
|
|
||||||
port_value: 9002
|
|
||||||
|
|
||||||
# RLS 集群
|
|
||||||
- name: ratelimit_cluster
|
|
||||||
connect_timeout: 0.25s
|
|
||||||
type: STRICT_DNS
|
|
||||||
lb_policy: ROUND_ROBIN
|
|
||||||
http2_protocol_options: {}
|
|
||||||
load_assignment:
|
|
||||||
cluster_name: ratelimit_cluster
|
|
||||||
endpoints:
|
|
||||||
- lb_endpoints:
|
|
||||||
- endpoint:
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: ratelimit # RLS 地址
|
|
||||||
port_value: 8081 # RLS gRPC 端口
|
|
||||||
|
|
||||||
admin:
|
|
||||||
access_log_path: /tmp/admin_access.log
|
|
||||||
address:
|
|
||||||
socket_address:
|
|
||||||
address: 0.0.0.0
|
|
||||||
port_value: 9901
|
|
||||||
Reference in New Issue
Block a user