ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

深入解析 gRPC EndpointInfo 手握手器:连接端点信息的采集与授权消费链路

深入解析 gRPC EndpointInfo 手握手器:连接端点信息的采集与授权消费链路 深入解析 gRPC EndpointInfo 手握手器连接端点信息的采集与授权消费链路【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc导读在 gRPC 的握手Handshake阶段连接的对端与本地地址信息是安全授权如 RBAC、审计与排障的重要输入。本文以 gRPC C 核心库中 endpoint_info 目录为切入点剖析EndpointInfo数据结构的定位、EndpointInfoHandshaker的实现细节以及端点地址如何通过ChannelArgs一路传递到授权评估模块evaluate_args.cc。读完本文你将掌握 gRPC 握手框架的扩展方式、端点信息采集的完整调用链以及如何基于源码与测试验证这一机制。EndpointInfo连接端点的信息载体根据 endpoint_info/AGENTS.md 的说明本目录承载的是EndpointInfo类——一个包含连接本地端点local endpoint与远端端点remote/peer endpoint信息的数据结构。它的核心价值在于为握手器handshaker提供一种便捷的方式来访问连接双方的地址信息。从源码结构看该目录的实际实现由两个文件构成endpoint_info_handshaker.h声明端点信息相关的两个 ChannelArgs 键以及注册函数RegisterEndpointInfoHandshakerendpoint_info_handshaker.cc实现EndpointInfoHandshaker与EndpointInfoHandshakerFactory完成地址采集与写入。需要说明的是目录内并未单独存放名为endpoint_info.h的类定义文件EndpointInfo的实际实现被内联在EndpointInfoHandshaker及其工厂类中这一点在阅读源码时需要留意。握手框架EndpointInfo 所处的执行环境要理解 EndpointInfo 手握手器先要了解它所依附的 gRPC 握手框架。在 src/core/handshaker/AGENTS.md 中握手框架被描述为“在客户端发送首个请求之前对连接执行初始握手的可插拔机制”典型用途包括 HTTP CONNECT客户端侧与各类安全初始化TLS、ALTS 等。框架的核心抽象在 handshaker.h 中定义Handshakerhandshaker.h单个握手操作的抽象基类通过DoHandshake执行具体握手通过name()标识自身HandshakeManagerhandshaker.h按加入顺序串行调用一组 handshaker前一个完成后将HandshakerArgs传递给下一个HandshakerArgshandshaker.h在 handshaker 之间流转的输入/输出参数结构包含endpointgrpc_endpoint指针、argsChannelArgs、read_buffer、exit_early、deadline等成员。关键在于HandshakerArgs.args是一个贯穿整个握手链的可变ChannelArgs——每个 handshaker 都可以向其中写入或改写键值对。EndpointInfo 手握手器正是利用这一点把端点地址以 ChannelArgs 的形式注入到后续流程中。EndpointInfoHandshaker 实现解析地址写入的核心逻辑EndpointInfoHandshaker::DoHandshake 是整个机制的入口其实现非常简洁void DoHandshake( HandshakerArgs* args, absl::AnyInvocablevoid(absl::Status) on_handshake_done) override { args-args args-args .Set(GRPC_ARG_ENDPOINT_LOCAL_ADDRESS, grpc_endpoint_get_local_address(args-endpoint.get())) .Set(GRPC_ARG_ENDPOINT_PEER_ADDRESS, grpc_endpoint_get_peer(args-endpoint.get())); InvokeOnHandshakeDone(args, std::move(on_handshake_done), absl::OkStatus()); }它做了两件事从当前连接的grpc_endpoint对象中提取地址本地地址通过grpc_endpoint_get_local_address获取远端对端地址通过grpc_endpoint_get_peer获取将结果写入args-argsChannelArgs的两个键中这两个键在 endpoint_info_handshaker.h 中定义// Set by the handshaker to indicate the local address of the endpoint. #define GRPC_ARG_ENDPOINT_LOCAL_ADDRESS grpc.internal.endpoint_local_address // Set by the handshaker to indicate the peer address of the endpoint. #define GRPC_ARG_ENDPOINT_PEER_ADDRESS grpc.internal.endpoint_peer_address随后立即以absl::OkStatus()完成握手InvokeOnHandshakeDone即该手握手器不消费也不改写任何字节流只是纯信息采集不会阻塞或延迟后续握手。优先级与执行时机EndpointInfoHandshaker由工厂类EndpointInfoHandshakerFactory创建其Priority()返回 HandshakerPriority::kSecurityHandshakers源码注释明确要求“必须在 kTCPConnectHandshakers 之后执行”。参考 handshaker_factory.h 中定义的优先级枚举握手链的执行顺序为优先级含义适用侧kPreTCPConnectHandshakersTCP 连接建立之前主要客户端kTCPConnectHandshakers实际建立 TCP 连接主要客户端kHTTPConnectHandshakers实际建立 HTTP CONNECT主要客户端kReadAheadSecurityHandshakers连接建立后、安全握手前主要服务端kSecurityHandshakers连接建立后的安全握手客户端与服务端kTemporaryHackDoNotUseEndpointWrappingHandshakers临时端点包装勿用—对比 tcp_connect_handshaker.cc 中返回的kTCPConnectHandshakers优先级可以确认EndpointInfo 手握手器在TCP 连接已经建立之后、安全握手TLS/ALTS同优先级阶段采集地址因此拿到的grpc_endpoint已经处于可查询地址的就绪状态。客户端与服务端双侧注册RegisterEndpointInfoHandshaker 同时将工厂注册到客户端与服务端两种握手类型void RegisterEndpointInfoHandshaker(CoreConfiguration::Builder* builder) { builder-handshaker_registry()-RegisterHandshakerFactory( HANDSHAKER_CLIENT, std::make_uniqueEndpointInfoHandshakerFactory()); builder-handshaker_registry()-RegisterHandshakerFactory( HANDSHAKER_SERVER, std::make_uniqueEndpointInfoHandshakerFactory()); }这意味着无论客户端发起连接还是服务端接受连接其握手链中都会包含这一个手握手器。该注册函数的实际调用点位于插件注册中心 grpc_plugin_registry.cc属于 gRPC 核心配置CoreConfiguration初始化的一部分随库启动自动生效无需用户额外配置。数据流向从 grpc_endpoint 到授权决策采集到的两个地址以字符串形式写入 ChannelArgs 后真正的消费方是 gRPC 的安全授权模块。以 evaluate_args.cc 为例EvaluateArgs::PerChannelArgs::PerChannelArgs(grpc_auth_context* auth_context, const ChannelArgs args) { // ... 从 auth_context 提取 transport_security_type、spiffe_id、uri_sans 等 local_address ParseEndpointUri( args.GetString(GRPC_ARG_ENDPOINT_LOCAL_ADDRESS).value_or()); peer_address ParseEndpointUri( args.GetString(GRPC_ARG_ENDPOINT_PEER_ADDRESS).value_or()); }授权评估器在构造评估参数时会从 ChannelArgs 中按GRPC_ARG_ENDPOINT_LOCAL_ADDRESS与GRPC_ARG_ENDPOINT_PEER_ADDRESS两个键读取地址字符串缺失时回退为空串再通过ParseEndpointUri解析为结构化的地址对象。ParseEndpointUrievaluate_args.cc的解析逻辑说明了地址字符串的格式约定先按 URI 语法解析取出 path 部分调用SplitHostPort切分 host 与 port用SimpleAtoi将端口转为整型用StringToSockaddr尝试将地址解析为 IPv4/IPv6 的 socket 地址结构。由此可推断grpc_endpoint_get_peer/grpc_endpoint_get_local_address返回的地址字符串形如ipv4:1.2.3.4:123或ipv6:[2001:0db8:...]:456这与测试代码中的输入格式完全吻合。解析后的本地/远端地址会被用于 RBAC基于角色的访问控制授权匹配即 gRPC 的授权策略可以依据“连接来自哪个对端地址、落在哪个本地端口”等维度做出放行或拒绝的决策。测试验证如何确认端点信息链路正确仓库中的测试用例为上述行为提供了直接验证evaluate_args_test_util.h 提供了两个测试辅助方法将端点地址写入 ChannelArgsvoid SetLocalEndpoint(absl::string_view local_uri) { args_ args_.Set(GRPC_ARG_ENDPOINT_LOCAL_ADDRESS, local_uri); } void SetPeerEndpoint(absl::string_view peer_uri) { args_ args_.Set(GRPC_ARG_ENDPOINT_PEER_ADDRESS, peer_uri); }evaluate_args_test.cc 展示了典型用法例如util_.SetLocalEndpoint(ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456)与util_.SetPeerEndpoint(ipv4:255.255.255.255:123)authorization_matchers_test.cc 中大量使用SetLocalEndpoint/SetPeerEndpoint来构造授权匹配场景覆盖 IPv4、IPv6 与非法地址等边界情况例如ipv6:[1:2::3::]:456这类格式错误的输入用于验证授权匹配器的解析与容错行为。此外构建系统层面test/core/test_util/BUILD 中引用了//src/core:endpoint_info_handshaker目标说明测试工具链与 EndpointInfo 手握手器之间的依赖关系是显式声明的。小结EndpointInfo 在 gRPC 安全体系中的位置回顾整条链路EndpointInfo 的设计体现了 gRPC 握手框架“可插拔、职责单一”的架构思想采集EndpointInfoHandshaker在 TCP 连接建立后、安全握手阶段从grpc_endpoint提取本地与对端地址传递地址以ChannelArgs键值对grpc.internal.endpoint_local_address/grpc.internal.endpoint_peer_address随握手链流转消费授权评估模块从 ChannelArgs 中读取地址并解析为结构化数据支撑 RBAC 授权决策。对于希望在 gRPC 中获取连接端点信息的开发者而言这一机制提供了明确的参考范式只需在握手链中挂载一个与EndpointInfoHandshaker同构的采集器即可让连接元数据随握手过程自然沉淀到ChannelArgs供后续任意环节消费。相关实现细节可进一步参阅 endpoint_info_handshaker.cc、handshaker.h 与 evaluate_args.cc。【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表