feat: add authz-adapter service and Envoy ext_authz integration

- Implemented authz-adapter deployment and service for Envoy gRPC authorization.
- Created PowerShell script to generate JWK for JWT authentication.
- Documented the integration of ext_authz with user-rpc.ValidateToken in ENVOY_EXT_AUTHZ_ADAPTER.md.
- Added comprehensive Envoy Gateway configuration guide with JWT authentication and access control in ENVOY_GATEWAY_GUIDE.md.
This commit is contained in:
wwweww
2026-02-26 06:08:35 +08:00
parent 60b6f40f9f
commit 659168fe32
30 changed files with 2093 additions and 3527 deletions
+138 -34
View File
@@ -21,6 +21,16 @@ data:
codec_type: AUTO
generate_request_id: true
use_remote_address: true
internal_address_config:
cidr_ranges:
- address_prefix: 10.0.0.0
prefix_len: 8
- address_prefix: 172.16.0.0
prefix_len: 12
- address_prefix: 192.168.0.0
prefix_len: 16
- address_prefix: 127.0.0.0
prefix_len: 8
route_config:
name: local_route
virtual_hosts:
@@ -33,31 +43,68 @@ data:
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:
prefix: /api/email
path: /api/users/login
route:
cluster: email_api_cluster
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/users/register
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/users
route:
cluster: user_api_cluster
timeout: 30s
- match:
path: /api/email/verification-code/send
route:
cluster: email_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: /
direct_response:
status: 404
body:
inline_string: "gateway route not found"
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
local TOKEN_COOKIE = "csrf_token"
local GUARD_COOKIE = "csrf_guard"
local TOKEN_HEADER = "x-csrf-token"
local GUARD_HEADER = "x-csrf-guard"
local TOKEN_HEADER = "xsrf-token"
local TOKEN_COOKIE = "__Host-XSRF-TOKEN"
local GUARD_COOKIE = "__Host-XSRF-GUARD"
local seeded = false
@@ -100,42 +147,41 @@ data:
local cookie_header = headers:get("cookie")
local cookies = split_cookie(cookie_header)
local csrf_token_cookie = cookies[TOKEN_COOKIE]
local csrf_guard_cookie = cookies[GUARD_COOKIE]
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", csrf_token_cookie == nil or csrf_token_cookie == "")
request_handle:streamInfo():dynamicMetadata():set("csrf", "need_set_guard_cookie", csrf_guard_cookie == nil or csrf_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 csrf_token_cookie == nil or csrf_token_cookie == "" then
csrf_token_cookie = build_token(headers:get("x-request-id"))
request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", csrf_token_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", csrf_token_cookie)
request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", token_cookie)
end
if csrf_guard_cookie == nil or csrf_guard_cookie == "" then
csrf_guard_cookie = build_token(headers:get("x-request-id"))
request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", csrf_guard_cookie)
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", csrf_guard_cookie)
request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", guard_cookie)
end
if is_safe_method(method) then
return
end
local csrf_token_header = headers:get(TOKEN_HEADER)
local csrf_guard_header = headers:get(GUARD_HEADER)
local token_header = headers:get(TOKEN_HEADER)
if csrf_token_header == nil or csrf_guard_header == nil then
if token_header == nil or token_header == "" then
request_handle:respond(
{[":status"] = "403", ["content-type"] = "application/json"},
'{"code":403,"message":"missing csrf headers"}'
'{"code":403,"message":"missing XSRF-TOKEN header"}'
)
return
end
if csrf_token_cookie == nil or csrf_guard_cookie == nil then
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"}'
@@ -143,10 +189,10 @@ data:
return
end
if csrf_token_header ~= csrf_token_cookie or csrf_guard_header ~= csrf_guard_cookie then
if token_header ~= token_cookie then
request_handle:respond(
{[":status"] = "403", ["content-type"] = "application/json"},
'{"code":403,"message":"csrf token mismatch"}'
'{"code":403,"message":"xsrf token mismatch"}'
)
return
end
@@ -164,17 +210,65 @@ data:
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=/; SameSite=Strict"
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=/; SameSite=Strict"
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":"MGUyMWE3ZDhjMTQ5ZDg1MWViOWU0MGM3OTE2NWVkYTBlOTE5ZWRkZDU1YjYzOGJjOWRiNzM0NTc4NDIyMjlkZQ","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:
path: "/api/users/login"
- match:
path: "/api/users/register"
- match:
path: "/api/email/verification-code/send"
- 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
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
@@ -193,6 +287,7 @@ data:
socket_address:
address: user-api-svc.juwan.svc.cluster.local
port_value: 8888
- name: email_api_cluster
connect_timeout: 2s
type: STRICT_DNS
@@ -207,6 +302,21 @@ data:
address: email-api-svc.juwan.svc.cluster.local
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-svc.juwan.svc.cluster.local
port_value: 9002
admin:
access_log_path: /tmp/admin_access.log
address:
@@ -233,6 +343,7 @@ spec:
labels:
app: envoy-gateway
spec:
serviceAccountName: envoy-gateway
containers:
- name: envoy
image: envoyproxy/envoy:v1.31-latest
@@ -260,13 +371,6 @@ spec:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy