实战:从 GCE 元数据服务器获取服务间认证令牌)
Envoy GCP 认证过滤器gcp_authn实战从 GCE 元数据服务器获取服务间认证令牌【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读在微服务架构中服务之间需要相互通信当目标服务是私有服务并要求调用方携带访问凭据时服务间service-to-service认证就变得必不可少。Envoy 的envoy.filters.http.gcp_authnHTTP 过滤器解决了这一问题它从 Google Compute EngineGCE元数据服务器自动获取认证令牌identity token 或 access token并将令牌注入到转发请求的头部中从而让调用方无需在应用代码里手工处理令牌获取逻辑。读完本文你将掌握该过滤器的配置字段、完整的 YAML 配置示例、令牌获取与缓存机制以及源码层面的工作原理。过滤器概述与适用场景gcp_authn过滤器用于从 GCE 元数据服务器 获取认证令牌。其典型应用场景是多个服务组成的架构中服务彼此需要通信且目标服务是私有的、要求凭据才能访问此时需要服务到服务的认证authenticating service-to-service。该过滤器的工作方式是旁路式的它对请求头进行处理decodeHeaders 阶段如果成功获取到令牌就把令牌写入请求头再继续转发如果未能从认证服务器获取令牌则请求仍然会被发送到目标服务由目标服务在需要认证令牌时拒绝该请求。这一点从 gcp_authn_filter.cc 的实现可以确认当路由不存在、无法获取 audience 时过滤器只是记录统计并Continue不会拦截请求。过滤器配置说明该过滤器通过类型 URLtype.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig进行配置。完整的字段定义位于 gcp_authn.proto过滤器注册名envoy.filters.http.gcp_authn定义在 gcp_authn_filter.h。GcpAuthnFilterConfig主要包含以下核心字段字段类型必填说明http_uriconfig.core.v3.HttpUri否已废弃从 GCE 元数据服务器获取令牌的 HTTP URI。URL 格式为http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience[AUDIENCE]。该字段已标记废弃原因是它与 Google 认证库提供的 API 表面不一致控制面不应试图覆盖元数据服务器 URI集群与超时应改用独立的cluster与timeout字段配置。为保持向后兼容若未设置新的cluster/timeout字段仍会使用该字段中配置的 cluster 与 timeoutretry_policyconfig.core.v3.RetryPolicy否获取令牌失败时的重试策略并非所有数据平面都支持cache_configTokenCacheConfig否令牌缓存配置用于避免对同一请求重复查询 GCE 元数据服务器token_headerTokenHeader否指定将令牌写入哪个请求头。默认情况下不设置该字段令牌写入Authorization头格式为Authorization: Bearer token。若设置了token_metadata_key该字段不生效token_metadata_keystring否可选的动态元数据dynamic metadata键用于保存令牌。元数据以过滤器配置名作为命名空间优先级高于token_headerclusterstring否发送流量到 GCE 元数据服务器所用的集群。并非所有数据平面都支持数据平面也可以有自己的元数据服务器访问机制timeoutgoogle.protobuf.Duration否从 GCE 元数据服务器获取令牌的超时时间。校验规则要求0 timeout 4294967296saudienceAudience否定义认证服务。该字段覆盖集群typed_filter_metadata中的定义其中audience接收方服务信息默认通过目标集群的metadata字段提供typed_filter_metadata命名空间为envoy.filters.http.gcp_authn也可以在过滤器配置内联定义内联定义优先。在源码 gcp_authn_filter.cc 的retrieveAudience()中逻辑是先检查过滤器配置中是否包含audience有则直接使用否则从路由目标集群的typed_filter_metadata中查找并解包。令牌缓存配置TokenCacheConfigTokenCacheConfig用于避免对认证服务器此处即 GCE 元数据服务器进行冗余的重复查询。其唯一字段为字段类型默认值说明cache_sizegoogle.protobuf.UInt64Value0缓存条目数上限。最大为INT64_MAX受底层缓存实现约束。默认值 0即 proto3 默认值表示默认禁用缓存设置为其他值则启用缓存。校验规则 9223372036854775807缓存的具体实现见 token_cache.cc缓存键生成对Audience消息做 hash若存在客户端证书指纹用于 bound token再叠加指纹的 xxHash64见generateCacheKey()。防冲突校验命中缓存后会通过MessageDifferencer::Equals对Audience做深比较并比对指纹避免 hash 碰撞误命中。过期校验缓存条目带有expires_at过期时间查询时会叠加JwtVerify::kClockSkewInSecond时钟偏移若已过期则移除该条目并返回未命中。LRU 淘汰底层使用 LRU 缓存结构超过cache_size时淘汰最久未使用的条目。Audience 配置详解Audience消息gcp_authn.proto是接收方服务的 URL即调用方服务正在调用的目标服务。它通过集群的metadata字段提供给过滤器。除了基本的url外Audience还支持多种令牌获取模式且具有严格的优先级顺序字段说明优先级urlaudience URL用于获取unbound未绑定JWT最低access_token若设置过滤器获取unbound Access Token而非 JWT高于urlbound_jwt.url若设置过滤器获取bound JWT绑定客户端证书的 JWTURL 必填min_len: 1高于access_token、urlbound_access_token若设置过滤器获取bound Access Token高于bound_jwt、access_token、urliam_access_token若设置为指定服务账号获取 access token要求 audience 内联定义在过滤器配置中最高iam_access_token子消息包含account服务账号邮箱或唯一 ID 的模板字符串支持动态元数据例如my-sa-%DYNAMIC_METADATA(my_filter:tenant_project)%my-project.iam.gserviceaccount.comauthorization授权请求头值的模板字符串例如Bearer %DYNAMIC_METADATA(gcp_authn:token)%scopes可选的自定义 OAuth 作用域列表默认作用域为https://www.googleapis.com/auth/cloud-platform默认令牌生命周期为 1 小时源码 gcp_authn_client_impl.cc 中请求体默认写死lifetime: 3600s若未指定 scopes 则使用上述默认 scope。模板字符串在过滤器创建时通过Formatter::FormatterImpl解析见 gcp_authn_filter.cc请求到来时基于请求头与 streamInfo 解析出实际的 account 与 authorization。完整配置示例官方示例配置文件位于 gcp-authn-filter-configuration.yaml下面分别给出资源集群层配置与HTTP 过滤器链配置。资源Resource配置目标集群与元数据服务器集群static_resources: clusters: - name: cluster_0 # 指向模拟目标服务的集群其 typed metadata 中包含 audience 信息。 load_assignment: cluster_name: cluster_0 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 0.0.0.0 port_value: 8000 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: {} metadata: typed_filter_metadata: envoy.filters.http.gcp_authn: type: type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.Audience url: http://test.com # 用于访问 GCE 元数据服务器的集群 - name: gcp_authn type: STRICT_DNS connect_timeout: 5s dns_lookup_family: V4_ONLY load_assignment: cluster_name: gcp_authn endpoints: - lb_endpoints: - endpoint: address: socket_address: address: metadata.google.internal port_value: 80关键点目标集群cluster_0通过metadata.typed_filter_metadata.envoy.filters.http.gcp_authn提供Audience其中url: http://test.com表示目标服务地址。过滤器在请求路由到此集群时会从该元数据中读取 audience详见上文retrieveAudience()。元数据服务器集群gcp_authn采用STRICT_DNS类型解析metadata.google.internal端口 80并设置 5s 连接超时与V4_ONLYDNS 查询族。该集群名与过滤器配置中http_uri.cluster或新的cluster字段对应。HTTP 过滤器链配置static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 8000 filter_chains: - filters: - name: http typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: HTTP2 stat_prefix: config_test route_config: name: route_config_0 virtual_hosts: - name: integration domains: [*] routes: - match: prefix: / route: cluster: cluster_0 http_filters: - name: envoy.filters.http.gcp_authn typed_config: type: type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig http_uri: uri: http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience[AUDIENCE] cluster: gcp_authn timeout: 10s - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router关键点过滤器链中envoy.filters.http.gcp_authn必须位于envoy.filters.http.router之前以保证在路由转发前完成令牌注入。http_uri.uri使用 GCE 元数据服务器的 identity 端点模板[AUDIENCE]是占位符实际 audience 来自集群 metadata或过滤器内联audience客户端在发请求时会将其填入audience查询参数见 gcp_authn_client_impl.cc。http_uri.cluster: gcp_authn指向上一节定义的元数据服务器集群timeout: 10s表示获取令牌的超时。生产环境建议改用等价的cluster与timeout顶层字段http_uri已废弃。令牌获取流程与源码原理从 gcp_authn_filter.cc 与 gcp_authn_client_impl.cc 可以梳理出完整的处理链路请求头阶段decodeHeaders获取路由若路由不存在则直接Continue随后根据目标集群解析 audience对iam_access_token模式会解析模板得到 account 与 authorization对 bound 令牌模式会通过集群传输层套接字匹配器解析客户端证书指纹getClientCertFingerprint见 gcp_authn_filter.cc。查缓存若配置了令牌缓存先用 audience及指纹查缓存命中且未过期则直接注入令牌并Continue。异步取令牌未命中缓存时根据 audience 的令牌类型调用客户端相应方法fetchUnboundJwtGET.../default/identity?audienceurl返回 JWTfetchUnboundAccessTokenGET.../default/token返回 JSONaccess_tokenexpires_infetchBoundJwtGET.../default/identity?audienceurlbindCertificateFingerprint指纹其中指纹需要双重 URL 编码GCP 元数据服务器强制要求源码注释N.B.: double-URL-encoding is REQUIREDfetchBoundAccessTokenGET.../default/token?bindCertificateFingerprint指纹fetchIamAccessToken向iamcredentials.googleapis.com发送 POST 请求/v1/projects/-/serviceAccounts/account:generateAccessToken请求体为 JSON{scope: [...], lifetime: 3600s}携带模板解析出的Authorization头。 所有元数据服务器请求都会带上Metadata-Flavor: Google头并且不发送 X-Forwarded-ForGCP 元数据服务器会拒绝带该头的请求见 gcp_authn_client_impl.cc。响应解析JWT 直接按字符串解析并读取exp作为过期时间Access Token 从 JSON 中解析access_token与expires_in计算过期时刻IAM Access Token 从 JSON 解析accessToken与expireTime。注入请求头addTokenToRequest见 gcp_authn_filter.cc若配置了token_metadata_key将令牌写入 streamInfo 动态元数据命名空间为过滤器配置名不进请求头否则若配置了token_header写入name: value_prefixtoken否则默认写入Authorization: Bearer token。写缓存并继续解码onComplete令牌获取成功后插入缓存若启用随后调用continueDecoding()继续过滤器链失败则记录日志令牌不会被注入。请求取消onDestroy若请求在等待令牌时被销毁会取消正在进行的异步请求。此外若设置了retry_policy客户端会将其转换为路由级重试策略默认重试条件为5xx,gateway-error,connect-failure,reset并开启bufferBodyForRetry见 gcp_authn_client_impl.cc。统计指标过滤器会暴露以下计数器统计定义于 gcp_authn_filter.hretrieve_audience_failed从集群元数据解析 audience 失败次数empty_audienceaudience 已配置但未指定任何令牌类型url/access_token 等均为空的次数client_cert_fingerprint_calculated成功计算客户端证书指纹的次数。可在 Envoy 管理接口或 metrics 端点观测这些统计用于排查 audience 配置错误与 bound 令牌指纹问题。测试验证仓库为 gcp_authn 过滤器提供了完整的测试覆盖位于 test/extensions/filters/http/gcp_authn 目录gcp_authn_filter_test.cc过滤器单元测试audience 解析、令牌注入、缓存命中/未命中、各令牌类型分支、统计计数等gcp_authn_client_impl_test.cc客户端实现测试URL 构造、双重编码、响应解析、重试、错误处理gcp_authn_filter_integration_test.cc集成测试验证从过滤器配置到元数据服务器 mock 再到目标集群的端到端链路token_cache_test.cc令牌缓存查找、过期、指纹组合键等行为测试filter_config_test.cc 与 crypto_utils_test.cc配置构建与证书指纹计算测试。使用注意事项目标服务若不要求认证令牌未获取到令牌时请求仍会被正常转发由目标服务自行决定是否拒绝因此该过滤器是尽力注入而非强制拦截。生产配置应使用cluster/timeout顶层字段替代已废弃的http_uri内嵌配置http_uri仅保留用于向后兼容。若需绑定客户端证书的 bound 令牌必须确保目标集群配置了 TLS 客户端证书否则指纹计算失败会返回 500 本地响应bound_token_fingerprint_unavailable。iam_access_token模式要求 audience 内联定义在过滤器配置中不能只依赖集群 metadata否则返回 500iam_token_config_error。在高并发场景建议配置cache_config.cache_size 0以复用令牌、降低元数据服务器压力。令牌默认写入Authorization: Bearer token如需自定义请求头或写入动态元数据使用token_header或token_metadata_key。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考