ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Envoy RBAC 过滤器解析:基于策略与匹配树的双重访问控制实现

Envoy RBAC 过滤器解析:基于策略与匹配树的双重访问控制实现 Envoy RBAC 过滤器解析基于策略与匹配树的双重访问控制实现【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoyEnvoy 的 RBACRole Based Access Control过滤器在代理进程内完成请求是否被授权的判定无需依赖外部授权服务。它可以作为网络过滤器或 HTTP 过滤器挂载也可两者同时配置基于策略Policy列表或 xDS 匹配 APIMatcher做准入决策并支持影子Shadow模式用于灰度验证新规则。读懂本文后你将掌握 RBAC 两种挂载形态的行为差异、Policy 的 permission/principal 匹配语义、匹配树可用的输入集合、影子策略的统计输出以及 CEL 条件表达式如何扩展策略表达能力并能从源码层面理解判定—拒绝—打点—写动态元数据的完整调用链。两种过滤器形态网络层断开连接 vs HTTP 层返回 403RBAC 过滤器检查的是传入请求是否被授权。与外部授权External Authorization不同RBAC 的判定发生在 Envoy 进程内部依据的是过滤器配置中的一组策略而不是远程 RPC 的响应。这一点在架构文档 rbac_filter.rst 中有明确说明。它有两种挂载形态且判定失败后的处理完全不同网络过滤器envoy.filters.network.rbac判定粒度是连接。若连接被判定为未授权Envoy 直接关闭该连接HTTP 过滤器envoy.filters.http.rbac判定粒度是请求。若请求被判定为未授权Envoy 以403 (Forbidden)响应拒绝该请求连接本身不受影响。两者可以同时配置形成先连接级粗粒度拦截、再请求级细粒度拦截的两层防线。从源码看这一行为差异体现在两个过滤器各自的实现里HTTP 过滤器 rbac_filter.cc 中当强制引擎enforced engine判定拒绝时过滤器调用sendLocalReply(Http::Code::Forbidden, RBAC: access denied, ...)返回本地 403 响应并返回StopIteration同时把判定结果写入名为envoy.filters.http.rbac的动态元数据命名空间网络过滤器 rbac_filter.cc 中拒绝分支则调用callbacks_-connection().close(Network::ConnectionCloseType::NoFlush, rbac_deny_close)直接断开连接并把策略 ID 记入connection_termination_details。此外网络层还有一个delay_deny选项配置后拒绝决策会延迟指定毫秒数才真正断开连接见 rbac_filter.cc 中基于 dispatcher 定时器的实现。更细节的行为差异还可以从源码结构看网络过滤器的强制检查支持CONTINUOUS与一次性两种执行类型——持续模式下每次onData都会重新执行 RBAC 检查一次性模式则只在首次数据到达时检查一次rbac_filter.cc。这为长连接上动态变化的匹配条件例如基于 FilterState 的策略提供了重新评估的入口。两种形态的完整配置参考分别位于网络过滤器配置network_filters/rbac_filter.rstHTTP 过滤器配置http_filters/rbac_filter.rstPolicy 模型permissions 与 principals 的与或非组合RBAC 的核心配置模型定义在 api/envoy/config/rbac/v3/rbac.proto。顶层消息config.rbac.v3.RBAC包含两个关键字段action策略匹配时执行的动作。所有动作要么放行要么拒绝请求常见取值为ALLOW当且仅当存在一个匹配的策略时放行请求deny-by-default 语义DENY当且仅当存在一个匹配的策略时拒绝请求allow-by-default 语义;LOG放行所有请求当至少一个策略匹配时在envoy.common共享命名空间的access_log_hint中置为true提示访问日志应记录该请求。policies从策略名到策略的映射。proto 注释明确说明匹配发生当且仅当至少一个策略与请求匹配且策略按策略名的字典序评估。每个策略由一个Permission列表和一个Principal列表组成Permission权限描述请求的动作例如 HTTP 请求的方法与路径。多个 permission 之间是OR语义——只要有一个 permission 匹配权限维度即满足要对所有动作都匹配使用单个any: true的 permission。Principal主体描述下游客户端的身份例如下游客户端证书的 URI SAN。多个 principal 之间同样是OR语义要对所有下游都匹配使用单个any: true的 principal。策略匹配条件其 permissions 与 principals 在同一时刻都满足权限与身份是 AND 关系各自内部是 OR 关系。Permission支持的具体类型包括any、authorized_nodes、destination_port、header、url_path、metadata、filter_state等Principal支持any、direct_remote_ip、remote_ip经代理协议推断的地址、authenticated携带principal_name、certificate证书 SAN 匹配、sourced_metadata等子选项、metadata、filter_state、namespace以及自定义 principal 扩展等。proto 文件本身给出了一段完整的示例配置rbac.proto 的注释其中包含两个策略action: ALLOW policies: service-admin: permissions: - any: true principals: - authenticated: principal_name: exact: cluster.local/ns/default/sa/admin - authenticated: principal_name: exact: cluster.local/ns/default/sa/superuser product-viewer: permissions: - and_rules: rules: - header: name: :method string_match: exact: GET - url_path: prefix: /products # ...destination_port 80/443 等条件这段示例展示了and_rules的嵌套能力product-viewer策略要求方法为 GET且路径以 /products 开头即 permission 内部可以用and_rules表达多个子条件的 AND 组合而顶层多个 permission 仍是 OR 关系。authenticated.principal_name则体现了对 Kubernetes 风格 SPIFFE 身份cluster.local/ns/...这类身份字符串的精确匹配。Matcher用 xDS 匹配树替代策略列表除了策略列表RBAC 过滤器也可以用 xDS 匹配 APIxds.type.matcher.v3.Matcher来配置判定规则。HTTP 过滤器的配置消息 RBAC 同时提供两组字段message RBAC { // 主策略作用于全局所有传入请求。 // * 若缺省则不做任何 RBAC 强制检查 // * 若设置但为空则拒绝所有请求。 config.rbac.v3.RBAC rules 1; // 匹配树。未匹配任何 matcher 的请求将被拒绝。 // * 若缺省则不做任何 RBAC 强制检查 // * 若设置但为空则拒绝所有请求。 xds.type.matcher.v3.Matcher matcher 4; // 影子策略 / 影子匹配器见下文 Shadow 一节 config.rbac.v3.RBAC shadow_rules 2; xds.type.matcher.v3.Matcher shadow_matcher 5; string rules_stat_prefix 6; string shadow_rules_stat_prefix 3; bool track_per_rule_stats 7; }几个必须注意的配置语义rules与matcher同时配置时rules被忽略proto 注释明确写出shadow_rules与shadow_matcher同理。缺省与设置但为空是两回事字段缺省表示该过滤器不执行任何强制检查字段设置但内容为空则表示所有请求都被拒绝。HTTP 过滤器的 per-route 覆盖由 RBACPerRoute 提供路由级配置若缺省rbac字段则该路由上 RBAC 策略被禁用。匹配树可用的输入matching input随过滤器形态而异架构文档的结论是网络输入对 RBAC 网络过滤器和 HTTP 过滤器都可用HTTP 输入仅在 HTTP 过滤器中可用。源码给出了精确的白名单HTTP 过滤器的允许输入集合在 rbac_filter.cc 的allowed_inputs_set_中静态定义包括网络输入DestinationIPInput、DestinationPortInput、SourceIPInput、SourcePortInput、DirectSourceIPInput、ServerNameInput、NetworkNamespaceInput、SSL 输入UriSanInput、DnsSanInput、SubjectInput、HttpRequestHeaderMatchInputHTTP 头输入、DynamicMetadataInput、FilterStateInput以及HttpAttributesCelMatchInput网络过滤器的白名单在 rbac_filter.cc仅包含网络/SSL 类输入与FilterStateInput不含 HTTP 头输入——因为连接级检查时请求头尚不可用这与HTTP 输入仅在 HTTP 过滤器中可用的文档描述完全一致。白名单之外的输入在配置加载时即被拒绝performDataInputValidation返回InvalidArgumentError(RBAC HTTP filter cannot match on ...)/RBAC network filter cannot match ...属于启动期校验错误。另外架构文档还特别提示RBAC matcher 扩展RBAC matcher extensions与 xDS 匹配 API 不兼容即Principal.custom这类 RBAC 自定义扩展不能与Matcher形态混用。Shadow Policy 与 Shadow Matcher先观测、后强制的灰度路径生产环境上线一条新 RBAC 规则前最大的风险是误判导致合法流量被拒。Envoy 的解决方案是影子Shadow模式过滤器可以额外配置一份shadow_rules或shadow_matcher影子引擎对每个请求做同样的评估但不拒绝任何请求只产生统计和日志。架构文档rbac_filter.rst 的 Shadow Policy and Shadow Matcher 一节原话是影子策略不产生任何效果即不拒绝请求只发出统计并记录结果这正是上线前测试规则的理想手段。HTTP 过滤器中的影子求值逻辑在 rbac_filter.cc 的evaluateShadowEngine中影子引擎存在时无论强制引擎判定结果如何都会先执行一次handleAction允许时递增shadow_allowed计数拒绝时递增shadow_denied计数若track_per_rule_stats开启且命中了具体策略还会为策略 ID 递增incPolicyShadowAllowed/incPolicyShadowDenied计数器同时把影子引擎的结果allowed/denied字符串与命中的策略 ID 写入动态元数据字段名由shadow_rules_stat_prefix决定前缀供访问日志引用。配合rules_stat_prefix/shadow_rules_stat_prefix两个前缀字段当同一监听器上配置多个 RBAC 过滤器实例时各自的统计可以通过不同前缀区分避免计数器互相污染。ConditionCEL 条件表达式扩展策略匹配在预定义的 permission 与 principal 之外策略还可以携带一个可选的授权条件用通用表达式语言Common Expression Language, CEL书写。该条件是策略匹配必须额外满足的一个子句。架构文档给出的示例是检查请求路径是否以/v1/开头call_expr: function: startsWith args: - select_expr: operand: ident_expr: name: request field: path - const_expr: string_value: /v1/这段表达式使用 CEL 检查checked expression的 AST 形式对request.path调用startsWith参数为常量字符串/v1/。在 HTTP 过滤器场景下request即请求上下文request.path对应请求路径。CEL 条件的表达力来自 Envoy 提供的一组请求属性。架构文档指向 请求属性文档Envoy 提供大量请求属性供策略使用且大多数属性是可选的——缺失时会按属性类型提供默认值。CEL 支持对属性和 map 做存在性检查例如has(request.referer)用于判断请求是否携带 Referer 头。这意味着 CEL 条件可以覆盖 permission/principal 无法直接表达的复杂组合逻辑时间窗口、头部存在性、元数据键值判断等而预定义的 permission/principal 则保留了声明式、易审计的配置风格两者互补。共享判定引擎HTTP 与网络过滤器如何复用同一套策略从源码结构看HTTP 与网络 RBAC 过滤器共享同一个判定引擎抽象Filters::Common::RBAC::RoleBasedAccessControlEngineengine.h核心接口是virtual bool handleAction(const Network::Connection connection, const Envoy::Http::RequestHeaderMap headers, StreamInfo::StreamInfo info, std::string* effective_policy_id) const PURE;handleAction接收下游连接用于提取动作/身份如地址、TLS 证书、HTTP 请求头网络过滤器场景下传空 map、StreamInfo携带动态元数据等附加信息返回布尔判定结果并通过输出参数effective_policy_id回填命中的策略名。引擎的具体实现策略列表引擎、匹配树引擎位于 source/extensions/filters/common/rbac 及其matchers/、principals/子目录中HTTP 过滤器的配置类在构造时分别调用createEngine与createShadowEngine生成强制引擎和影子引擎rbac_filter.cc并支持 per-route 覆盖——RoleBasedAccessControlFilterConfig::engine()会先尝试解析路由级配置路由级存在时优先使用路由级引擎rbac_filter.h。以 HTTP 过滤器为例一次请求的完整判定链是decodeHeaders触发先evaluateShadowEngine若配置了影子规则再evaluateEnforcedEngine强制引擎handleAction判定允许 → 递增allowed计数、按需递增 per-rule 计数返回Continue让请求继续向后传播判定拒绝 → 调用sendLocalReply(403, RBAC: access denied)返回详情中携带命中的策略 IDresponseDetail(log_policy_id)递增denied计数返回StopIteration无论允许还是拒绝判定结果与有效策略 ID 都会写入envoy.filters.http.rbac动态元数据命名空间可在访问日志中直接引用。统计与动态元数据观测 RBAC 判定结果RBAC 过滤器的观测面有三层均能在源码中得到印证计数器allowed、denied、shadow_allowed、shadow_denied四个基础计数器HTTP 侧见 rbac_filter.cc 的stats().shadow_allowed_.inc()等调用配合rules_stat_prefix前缀区分多实例。per-rule 计数器配置track_per_rule_stats: true后每个命中的策略 ID 都会暴露独立的允许/拒绝计数incPolicyAllowed/incPolicyDenied/incPolicyShadowAllowed/incPolicyShadowDenied可以精确回答这条新规则拦截了多少流量。动态元数据HTTP 过滤器把判定结果写入envoy.filters.http.rbac命名空间字段包括引擎结果allowed/denied与有效策略 ID网络过滤器则把影子结果写入同名命名空间、并把拒绝原因写入连接的connection_termination_details。这些信息都可以接入访问日志格式如%DYNAMIC_METADATA(...)%实现逐请求的审计。小结与延伸阅读Envoy 的 RBAC 过滤器把授权判定做进了代理进程内envoy.filters.network.rbac以连接为粒度、拒绝即断连envoy.filters.http.rbac以请求为粒度、拒绝即 403规则表达上提供Policypermission AND principal与Matcher 匹配树两种互不混用的形态再用 CEL 条件补足复杂逻辑上线策略上则以 shadow rules/matcher 的只观测不拦截能力支撑灰度验证并辅以 per-rule 统计与动态元数据实现全链路可观测。进一步阅读建议架构文档rbac_filter.rstHTTP 过滤器完整配置rbac_filter.rst网络过滤器完整配置rbac_filter.rst请求属性CEL 条件可用attributes.rstRBAC 公共 protorbac.proto共享判定引擎实现source/extensions/filters/common/rbac【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进