尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Envoy 外部授权过滤器(ext_authz)完全指南:gRPC/HTTP 授权服务接入、路由级控制与安全加固

Envoy 外部授权过滤器(ext_authz)完全指南:gRPC/HTTP 授权服务接入、路由级控制与安全加固 Envoy 外部授权过滤器ext_authz完全指南gRPC/HTTP 授权服务接入、路由级控制与安全加固【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy外部授权External Authorization是 Envoy 将请求鉴权决策外包给独立授权服务的核心机制HTTP 过滤器会调用外部 gRPC 或 HTTP 服务判断请求是否被授权未授权请求将收到403 (Forbidden)响应。本文以 HTTP ext_authz 过滤器文档 为主干结合仓库中的完整示例配置、proto API 定义与 C 源码实现系统讲解如何接入授权服务、转发请求体、做路由级控制、基于动态元数据条件激活并梳理统计指标、动态元数据、运行时开关、追踪与日志等运维要素帮助你在生产环境安全、正确地落地 ext_authz。ext_authz 过滤器是什么ext_authz 过滤器会在请求处理流程中调用一个外部 gRPC 或 HTTP 服务由该服务决定请求是否被授权。核心行为如下授权服务返回允许Allow时请求继续在过滤链中向下处理授权服务返回拒绝Deny时Envoy 直接返回403 (Forbidden)还可以向授权服务发送附加的自定义元数据并把授权服务返回的元数据向 upstream 或 downstream 传播。该过滤器使用类型 URLtype.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz配置完整字段定义见 api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto。传递给授权服务的请求内容由 CheckRequest 协议定义它是 ext_authz 过滤器与授权服务之间的契约。Envoy 同时提供网络过滤器连接级与 HTTP 过滤器请求级两种形态本文聚焦 HTTP 过滤器形态。网络过滤器形态的配置可参考 docs/root/configuration/listeners/network_filters/ext_authz_filter.rst。推荐部署位置与失败语义架构概览文档 docs/root/intro/arch_overview/security/ext_authz_filter.rst 给出了两条关键实践建议将 ext_authz 放在过滤链的第一个位置确保请求在被其他过滤器处理之前就完成鉴权避免后置过滤器处理未授权请求。注意这条建议与下文路由缓存清除风险的安全注意事项需要配合权衡——若放在首位且后续过滤器不会清空路由缓存则风险最低。授权服务不可用时的行为由failure_mode_allow决定true失败放行fail open请求被允许继续处理false默认值失败拒绝请求被拦截。外部授权服务的集群既可以静态配置也可以通过 CDSCluster Discovery Service动态下发。failure_mode_allow的默认值为false即服务不可用时默认拒绝请求fail closed这对多数鉴权场景是更安全的选择。接入 gRPC 授权服务以下配置来自仓库示例 docs/root/configuration/http/http_filters/_include/ext-authz-grpc-filter.yaml完整展示了 gRPC 形态的接入方式。首先看过滤器本体示例第 26-35 行http_filters: - 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: ext-authz # Default is 200ms; override if your server needs e.g. warmup time. timeout: 0.5s include_peer_certificate: true - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router关键参数说明grpc_service.envoy_grpc.cluster_name指定承载授权服务的集群名Envoy 通过该集群发起 gRPC 调用timeout授权调用的超时时间注释明确标注默认值是 200ms示例中为需要预热时间的服务覆盖为0.5sinclude_peer_certificate设为true时把 downstream 的 peer 证书如有包含进 CheckRequest便于授权服务基于 mTLS 客户端证书做决策。gRPC 模式使用 Envoy 内置 gRPC client 通过 HTTP/2 与授权服务通信因此对应集群必须启用 HTTP/2示例第 41-56 行clusters: - name: ext-authz type: STATIC typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: ext-authz endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 10003该集群通过explicit_http_config.http2_protocol_options显式启用 HTTP/2将授权请求发往127.0.0.1:10003的授权服务实例。配置中的upstream_com集群是演示用 upstream通过 LOGICAL_DNS 解析upstream.com并启用 TLS实际使用时替换为你的目标服务。转发 HTTP 请求体给授权服务ext_authz 的一个独特能力是把 HTTP 请求体作为 CheckRequest 的一部分发送给 gRPC 授权服务。示例 docs/root/configuration/http/http_filters/_include/ext-authz-grpc-body-filter.yaml 展示了相关配置第 26-36 行http_filters: - 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: ext-authz with_request_body: max_request_bytes: 1024 allow_partial_message: true pack_as_bytes: true - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Routerwith_request_body对应 proto 中的BufferSettings包含三个核心字段字段示例值作用max_request_bytes1024最多缓存并转发的请求体字节数上限allow_partial_messagetrue请求体超过上限时是否允许仅发送截断后的部分内容false时超限请求将被拒绝pack_as_bytestrue是否以原始字节raw bytes方式携带请求体请求体在 CheckRequest 中的承载方式与pack_as_bytes直接相关默认情况下pack_as_bytes为false请求体以 UTF-8 字符串形式放入AttributeContext.HttpRequest.body字段当pack_as_bytes设为true时请求体以原始字节放入AttributeContext.HttpRequest.raw_body字段此时body字段为空。二进制内容如文件上传必须使用pack_as_bytes: true才能无损传输。需要注意上述配置位于全局过滤器级在 ext_authz.proto 中ExtAuthzPerRoute.CheckSettings还提供了路由级的with_request_body字段可覆盖全局设置且全局与路由级二者只能配置其一可用于对特定路由精细化控制是否转发请求体。接入 HTTP 授权服务当授权服务以普通 HTTP 接口而非 gRPC暴露时使用http_service配置。完整示例见 docs/root/configuration/http/http_filters/_include/ext-authz-http-filter.yaml第 26-36 行http_filters: - name: envoy.filters.http.ext_authz typed_config: type: type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz http_service: server_uri: uri: 127.0.0.1:10003 cluster: ext-authz timeout: 0.25s failure_mode_allow: false include_peer_certificate: true - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.RouterHTTP 模式与 gRPC 模式的关键差异http_service.server_uri以uri指定授权服务地址cluster指定承载集群timeout设置单次授权请求超时示例为0.25sHTTP 授权服务集群无需启用 HTTP/2示例第 41-53 行中集群类型为LOGICAL_DNS负载均衡策略为ROUND_ROBIN未设置 HTTP/2 协议选项clusters: - name: ext-authz type: LOGICAL_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: ext-authz endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 10003HTTP 模式下Envoy 把请求属性编码为 HTTP 头如x-envoy-original-path、方法、Host 等发给授权服务授权服务以 HTTP 状态码表达决策200 OK允许、403 Forbidden拒绝。注意 HTTP 模式不支持请求体转发with_request_body仅适用于 gRPC 模式需要基于请求体内容做决策的场景应选用 gRPC 形态。Per-Route 配置虚拟主机级上下文与按路由开关ext_authz 支持在虚拟主机virtual host和路由route级别做细粒度配置。示例 docs/root/configuration/http/http_filters/_include/ext-authz-routes-filter.yaml第 15-38 行展示了两种用法在虚拟主机级添加额外上下文并对/static前缀路由禁用过滤器route_config: name: local_route virtual_hosts: - name: local_service domains: [*] typed_per_filter_config: envoy.filters.http.ext_authz: type: type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute check_settings: context_extensions: virtual_host: local_service routes: - match: prefix: /static route: cluster: ext-authz 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: / route: cluster: ext-authz两个核心配置点虚拟主机级check_settings.context_extensions把自定义键值对示例中的virtual_host: local_service注入 CheckRequest 的context_extensions字段授权服务可据此识别请求来自哪个虚拟主机实现多租户区分路由级disabled: true对/static前缀路由直接禁用 ext_authz静态资源请求免鉴权其余/前缀路由仍走授权检查。ExtAuthzPerRoute是路由级配置的类型其完整字段包括disabled、check_settings、路由级with_request_body等定义在 api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto。使用 per-route 配置时请务必阅读下文安全注意事项评估路由缓存清除带来的提权风险。基于动态元数据的条件激活ExtensionWithMatcher 推荐方案当需要根据前置过滤器如 Lua写入的动态元数据dynamic metadata条件性地调用 ext_authz 时官方文档明确推荐使用ExtensionWithMatcher而非filter_enabled_metadata字段。两者的本质区别ExtensionWithMatcher在过滤器实例化之前评估匹配条件只有 matcher 判定需要执行时过滤器才被创建和调用是元数据条件调用的推荐方案filter_enabled_metadata在过滤器实例化之后才被评估。如果 HttpFilter 配置中标记了disabled: true过滤器根本不会被实例化此时filter_enabled_metadata完全不生效。完整示例见 docs/root/configuration/http/http_filters/_include/ext-authz-extension-with-matcher.yaml第 26-83 行。整体思路Lua 过滤器负责决策ext_authz 负责执行。第一步Lua 过滤器检查请求路径并把结果写入动态元数据http_filters: # Lua filter sets dynamic metadata that controls whether ext_authz runs. - name: envoy.filters.http.lua typed_config: type: type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua default_source_code: inline_string: | function envoy_on_request(request_handle) -- Set metadata to conditionally enable ext_authz. -- For example, enable auth for requests to /secure paths. local path request_handle:headers():get(:path) if string.match(path, ^/secure) then request_handle:streamInfo():dynamicMetadata():set(envoy.filters.http.ext_authz, require_auth, true) else request_handle:streamInfo():dynamicMetadata():set(envoy.filters.http.ext_authz, require_auth, false) end end第二步用ExtensionWithMatcher包裹 ext_authzmatcher 读取上述元数据决定是否调用# ExtensionWithMatcher wraps ext_authz and conditionally invokes it based on dynamic metadata. - name: ext-authz-with-matcher typed_config: type: type.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher extension_config: 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: ext-authz timeout: 0.5s include_peer_certificate: true # The xds matcher evaluates dynamic metadata to decide whether to invoke ext_authz. # We use matcher_list with custom_match because DynamicMetadataInput returns a custom # MetadataMatchData type that requires a custom matcher and not exact_match_map. xds_matcher: matcher_list: matchers: - predicate: single_predicate: input: name: envoy.matching.inputs.dynamic_metadata typed_config: type: type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DynamicMetadataInput filter: envoy.filters.http.ext_authz path: - key: require_auth custom_match: name: envoy.matching.matchers.metadata_matcher typed_config: type: type.googleapis.com/envoy.extensions.matching.input_matchers.metadata.v3.Metadata value: string_match: exact: false # When require_auth is false, skip ext_authz. on_match: action: name: skip typed_config: type: type.googleapis.com/envoy.extensions.filters.common.matcher.action.v3.SkipFilter - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router执行逻辑归纳如下DynamicMetadataInputfilter 为envoy.filters.http.ext_authzpath 键为require_auth读取 Lua 写入的元数据当require_auth为false时matcher 命中on_match执行SkipFilteractionext_authz 被跳过当require_auth为true或元数据缺失时ext_authz 正常被调用。示例注释特别说明由于DynamicMetadataInput返回的是自定义的MetadataMatchData类型这里必须使用matcher_listcustom_matchmetadata_matcher组合而不能使用exact_match_map。这一模式把决策逻辑Lua与鉴权执行ext_authz清晰解耦并确保 ext_authz 只在真正需要时才被实例化减少不必要的授权调用开销。安全注意事项路由缓存清除导致鉴权绕过官方文档以醒目方式attention 块警告了一个安全风险使用 per-route ext_authz 配置时过滤链中位于 ext_authz 之后的过滤器如果清除了路由缓存route cache可能导致提权漏洞——请求绕过授权检查。风险成因ext_authz 经常承载认证与授权决策直接影响访问控制。当 ext_authz 运行之后路由缓存被清除请求可能被重新路由到授权要求不同的端点从而完全绕过已执行的鉴权检查。文档给出的脆弱配置示例不要照抄到生产环境http_filters: - name: envoy.filters.http.ext_authz typed_config: type: type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz # ... ext_authz config ... - name: envoy.filters.http.lua typed_config: type: type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua inline_code: | function envoy_on_request(request_handle) -- This clears the route cache after ext_authz has run. request_handle:clearRouteCache() -- The request may now match a different route with different authorization requirements. end在此示例中如果初始路由将 ext_authz 配置为禁用而路由缓存清除后重新计算的路由匹配要求授权则请求将完全绕过授权检查。更完整的风险说明、受影响过滤器清单与通用缓解策略参见文档中引用的过滤路由变更安全注意事项章节arch_overview_http_filters_route_mutation。生产环境排查时优先保证 per-route ext_authz 场景下后置过滤器不清除路由缓存或使用上文推荐的ExtensionWithMatcher等条件激活方式收敛过滤器实例化范围。统计指标HTTP ext_authz 过滤器在cluster.route target cluster.ext_authz.命名空间下输出统计指标。这些指标在源码 source/extensions/filters/http/ext_authz/ext_authz.h 的ALL_EXT_AUTHZ_FILTER_STATS宏中定义文档表格中的核心计数器如下名称类型说明okCounter授权服务返回允许Allow的总响应数errorCounter联系外部服务出错的总次数deniedCounter授权服务返回拒绝Denied的总响应数disabledCounter因过滤器被禁用而未调用外部服务即放行的请求总数failure_mode_allowedCounter因failure_mode_allow为true而被放行的错误响应总数invalidCounter因无效的 header 或 query 参数变更而被拒绝的响应总数omitted_response_headersCounter因 header map 约束ext_authz 拒绝丢弃了部分响应头 的响应总数request_header_limits_reachedCounter因无法应用全部 header 变更而发送本地回复的请求总数response_header_limits_reachedCounter因无法应用全部 header 变更而发送本地回复的响应总数从源码看过滤器还额外定义了ignored_dynamic_metadata、filter_state_name_collision、shadow_denied、shadow_error等计数器后者服务于 shadow mode 场景与文档表格形成互补说明统计体系在持续演进。通过admin端点的/stats接口即可按命名空间查询这些指标用于监控授权服务健康状况与放行/拒绝比例。动态元数据输出ext_authz 支持以不透明的google.protobuf.Struct形式输出动态元数据dynamic metadata供下游过滤器、访问日志等消费。三种来源gRPC 授权服务仅当CheckResponse包含非空的dynamic_metadata字段时才会输出动态元数据。授权服务可把决策相关的结构化信息如用户角色、限流配额放在该字段中回传HTTP 授权服务仅当授权服务返回的响应头中存在与配置的dynamic_metadata_from_headers匹配的响应头时才会输出。每个匹配的响应头都会生成一条动态元数据——key 为响应头名value 为响应头值。dynamic_metadata_from_headers是AuthorizationResponse的字段定义在 api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto耗时记录HTTP 与 gRPC 两种模式都支持名为ext_authz_duration的动态元数据字段记录完成一次授权请求所耗毫秒数若请求未完成该字段不会被填充。运行时控制ext_authz 支持运行时Runtime控制启停比例通过filter_enabled字段的runtime_key类型为config.core.v3.RuntimeFractionalPercent配置过滤器生效的请求比例。典型用法是设置runtime_key: envoy.filters.http.ext_authz.enabled然后在运行时配置中动态调整百分比实现授权检查的灰度发布如先 10% 流量启用、观察后逐步放量无需重启 Envoy。追踪Tracingext_authz span 保持父 span 的采样状态在追踪后端中要么同时看到父 span 与子 ext_authz span要么两者都看不到。这意味着 ext_authz 不会独立改变采样决策避免因授权调用导致追踪采样率失真便于把授权耗时纳入整体链路分析。日志Logging与 FilterState 字段当emit_filter_state_stats设为true时ext_authz 会暴露latency_us、bytesSent、bytesReceived三个字段供 CEL 表达式与访问日志格式化使用filter_state[envoy.filters.http.ext_authz].latency_us%FILTER_STATE(envoy.filters.http.ext_authz:FIELD:latency_us)%%FILTER_STATE(envoy.filters.http.ext_authz:FIELD:bytesSent)%%FILTER_STATE(envoy.filters.http.ext_authz:FIELD:bytesReceived)%官方文档特别注明bytesSent与bytesReceived仅在使用 Envoy 内置 gRPC client 类型即grpc_service.envoy_grpc形态时才填充若使用 Google gRPC clientgoogle_grpc这两个字段不会更新。实现上这些字段由源码 source/extensions/filters/http/ext_authz/ext_authz.h 中的ExtAuthzLoggingInfoFilterState 对象承载它与emit_filter_state_stats开关联动。latency_us可用于在访问日志中输出授权环节耗时是定位鉴权性能瓶颈的直接手段。总结与选型建议综合本文内容接入 ext_authz 时的关键决策点可归纳为协议形态需要基于请求体内容做鉴权决策 → 选 gRPC 模式配合with_request_body仅需请求头/属性 → HTTP 模式更轻量失败语义默认failure_mode_allow: falsefail closed对可用性敏感、鉴权失败可容忍的场景再考虑truefail open作用范围全局过滤链配置 虚拟主机/路由级ExtAuthzPerRoute覆盖disabled、context_extensions、路由级with_request_body条件激活需要按动态元数据条件触发时优先ExtensionWithMatcherSkipFilter避免filter_enabled_metadata在过滤器未实例化时失效的坑安全基线per-route 场景务必警惕后置过滤器清除路由缓存导致的鉴权绕过尽量把 ext_authz 置于过滤链前端并保持路由缓存稳定可观测性用好cluster.route target cluster.ext_authz.命名空间下的计数器、ext_authz_duration动态元数据以及emit_filter_state_stats暴露的 FilterState 字段持续监控授权链路。所有配置示例均可从仓库 docs/root/configuration/http/http_filters/_include/ 目录下的ext-authz-*.yaml文件中获取完整版本结合 ext_authz.proto 的字段注释与 ext_authz.h 的实现细节即可在生产环境快速落地并持续调优。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表