news 2026/9/16 17:43:01

gRPC C++ SSL 认证实战:基于 SslServerCredentials 与 SslCredentials 搭建 TLS 加密 RPC 服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gRPC C++ SSL 认证实战:基于 SslServerCredentials 与 SslCredentials 搭建 TLS 加密 RPC 服务

gRPC C++ SSL 认证实战:基于 SslServerCredentials 与 SslCredentials 搭建 TLS 加密 RPC 服务

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

导读

本文以 gRPC 官方 C++ 示例中的 Authentication Example(位于本仓库 src/third_party/grpc/dist/examples/cpp/auth/)为蓝本,完整讲解如何为 gRPC 服务端与客户端启用基于 SSL/TLS 的双向安全信道:服务端通过grpc::SslServerCredentials提供加密监听端口,客户端通过grpc::SslCredentials建立受信任的加密连接。读完本文,你将掌握 gRPC C++ 中 SSL 凭据的加载方式、证书信任链的组织方法,以及如何使用 Bazel 构建并运行一个端到端的 TLS 认证 gRPC 示例,并能将同样的模式迁移到自己的 RPC 服务中。

Overview:为什么需要 SSL 认证

SSL(Secure Sockets Layer)是一种广泛使用的加密协议,用于提供端到端的通信安全。在 gRPC 中,RPC 调用默认通过 HTTP/2 传输,虽然性能优秀,但明文信道上的数据与身份都可以被中间人窃听或篡改。为了对 RPC 流量进行加密并验证通信双方身份,gRPC C++ 提供了两种核心凭据类型:

  • grpc::SslServerCredentials:服务端使用,绑定到监听端口,对所有接入的连接启用 TLS 握手与证书校验;
  • grpc::SslCredentials:客户端使用,绑定到 Channel,向服务端发起 TLS 握手。

本示例使用预先创建好的公钥/私钥对来完成服务器端认证(Server Authentication),三份凭据文件分别为:

文件作用
localhost.crt服务器证书(含公钥),代表服务器的身份
localhost.key服务器私钥,仅服务端持有
root.crt证书颁发机构(CA)证书,用于校验服务器证书的可信性

三份文件都随示例存放在 src/third_party/grpc/dist/examples/cpp/auth/credentials/ 目录下。其中 root.crt 是自签 CA 证书,在真实生产环境中应替换为受信任 CA 签发的证书链。

端到端运行:构建并启动 TLS 加密的 HelloWorld 服务

构建前提

示例假设你已有一套可用的 gRPC C++ 构建环境,构建方式二选一:BazelCMake。无论采用哪种方式,都要在本目录(examples/cpp/auth)下执行构建命令,以确保程序能以相对路径正确读取凭据文件——这一点对示例能否运行至关重要,因为代码中加载证书走的就是相对路径(详见下文源码解析)。

本仓库随示例提供了完整的 Bazel 构建文件 src/third_party/grpc/dist/examples/cpp/auth/BUILD,它声明了两个二进制目标:

  • ssl_client:依赖 ssl_client.cc,并将credentials/root.crt作为运行期数据文件(data)打入;
  • ssl_server:依赖 ssl_server.cc,并将credentials/localhost.crtcredentials/localhost.key作为运行期数据文件打入。

两个目标都通过defines = ["BAZEL_BUILD"]开启 Bazel 构建宏,从而使源码切换到仓库根目录相对路径(examples/cpp/auth/credentials/...);若走 CMake 构建,则使用当前目录相对路径(credentials/...)。这一点在源码中通过#ifdef BAZEL_BUILD分支显式区分,后面会详细展开。

启动服务端

examples/cpp/auth目录下构建完成后,启动服务端,它将监听50051端口:

$ ./ssl_server

服务端启动后会打印监听地址(源码中通过absl::StrFormat("0.0.0.0:%d", port)构造绑定地址,默认端口 50051),随后进入server->Wait()阻塞等待,直到有线程负责触发关闭。

启动客户端

另开一个终端,运行客户端:

$ ./ssl_client

如果一切顺利,客户端会输出:

Greeter received: Hello world

这表示客户端已通过 TLS 信道向服务端成功发起SayHelloRPC:客户端发送名字world,服务端返回Hello world,整个过程在 SSL 加密连接上完成。

服务端源码剖析:用 SslServerCredentials 绑定加密监听端口

服务端核心逻辑位于 ssl_server.cc,其关键步骤如下:

第一步:加载服务端证书与私钥。服务端通过LoadStringFromFile(定义于 helper.cc,其声明见 helper.h)将 PEM 格式文件读取为字符串:

grpc::SslServerCredentialsOptions::PemKeyCertPair key_cert_pair = { LoadStringFromFile(kServerKeyPath), LoadStringFromFile(kServerCertPath)};

PemKeyCertPair内部是一个字符串对,顺序为私钥在前、证书在后,这是 gRPC 定义好的字段次序,使用时不要颠倒。

第二步:组装SslServerCredentialsOptions将密钥证书对压入pem_key_cert_pairs列表——该字段是向量类型,意味着服务端可以一次性提供多对证书(例如配置 SNI 或轮换证书),本示例仅提供一对:

grpc::SslServerCredentialsOptions ssl_options; ssl_options.pem_key_cert_pairs.emplace_back(key_cert_pair);

第三步:以 SSL 凭据绑定监听地址。grpc::SslServerCredentials(ssl_options)传给ServerBuilder::AddListeningPort,该端口上的所有连接即强制走 TLS:

builder.AddListeningPort(server_address, grpc::SslServerCredentials(ssl_options)); builder.RegisterService(&service); std::unique_ptr<Server> server(builder.BuildAndStart());

服务实现采用 gRPC 的Callback APIGreeter::CallbackServiceServerUnaryReactor):SayHello收到请求后拼接"Hello " + name前缀写入响应,随后通过context->DefaultReactor()->Finish(Status::OK)完成这次一元 RPC。

证书路径的构建差异。源码中根据构建方式区分了两组路径常量:

#ifdef BAZEL_BUILD constexpr char kServerCertPath[] = "examples/cpp/auth/credentials/localhost.crt"; constexpr char kServerKeyPath[] = "examples/cpp/auth/credentials/localhost.key"; #else constexpr char kServerCertPath[] = "credentials/localhost.crt"; constexpr char kServerKeyPath[] = "credentials/localhost.key"; #endif

这解释了 README 中"必须在示例目录下运行"的要求:CMake 构建时相对路径基于当前工作目录解析,若在仓库根目录运行会找不到证书并触发helper.cc中的abort()

客户端源码剖析:用 SslCredentials 建立受信任的 TLS 信道

客户端核心逻辑位于 ssl_client.cc,同样分为三步:

第一步:加载 CA 根证书。客户端读取root.crt作为信任锚:

grpc::SslCredentialsOptions ssl_options; ssl_options.pem_root_certs = LoadStringFromFile(kRootCertificate);

pem_root_certs是客户端校验服务端证书的根证书集合。本示例中root.crt正是签发localhost.crt的 CA,因此服务端证书可被验证通过;若 CA 不匹配,TLS 握手将失败。

第二步:以 SSL 凭据创建 Channel。目标地址默认为localhost:50051(端口同样由ABSL_FLAG(uint16_t, port, 50051, ...)定义,可用--port覆盖):

GreeterClient greeter( grpc::CreateChannel(target_str, grpc::SslCredentials(ssl_options)));

第三步:发起 RPC 并等待结果。客户端用异步 stub发起SayHello,通过mutex + condition_variable同步等待回调完成:

stub_->async()->SayHello(&context, &request, &reply, &mu, &cv, &done, &status { status = std::move(s); std::lock_guard<std::mutex> lock(mu); done = true; cv.notify_one(); });

status.ok()则返回服务端回复的消息,否则打印错误码与错误信息并返回"RPC failed"——这为排查握手失败(如证书校验不通过)提供了直观的反馈入口。

服务契约:helloworld.proto 中的 Greeter 服务

本示例的 RPC 契约定义在 src/third_party/grpc/dist/examples/protos/helloworld.proto,属于 gRPC 入门经典的helloworld包:

syntax = "proto3"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {} rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }

该 proto 除了演示用的一元 RPCSayHello,还声明了服务端流式SayHelloStreamReply与双向流式SayHelloBidiStream。在 Bazel 构建中,该 proto 经由//examples/protos:helloworld_cc_grpc目标生成 C++ 桩代码,服务端与客户端源码中Greeter::CallbackServiceGreeter::NewStubGreeter::Stub等类型均来自这份生成代码。

凭据文件说明与生产环境迁移建议

示例随附的三份凭据文件都是为本地演示预生成的(证书 CN 为localhost,有效期延续至 2119 年,仅用于示例)。迁移到生产环境时,请牢记以下几点:

  1. 私钥绝不外泄localhost.key必须严格保密,只能存放在服务端,任何形式的提交、分发都意味着凭据泄露;
  2. 替换为可信证书链:用正式 CA(或公司内部 PKI)签发的证书替换localhost.crt/localhost.key,并让客户端持有对应的root.crt(或 CA 证书链);
  3. 证书与密钥格式:gRPC 读取的是 PEM 格式字符串,服务端的PemKeyCertPair次序固定为(私钥,证书),客户端的pem_root_certs可包含多张 PEM 编码的 CA 证书;
  4. 双向认证扩展:如需客户端也向服务端证明身份(mTLS),可在服务端SslServerCredentialsOptions中配置pem_root_certs并开启客户端证书校验,客户端则在SslCredentialsOptions中补充自己的pem_private_keypem_cert_chain——本示例是单向服务器认证,这部分作为延伸方向供读者自行探索。

小结

gRPC C++ 的 SSL 认证模式非常清晰:服务端把「证书+私钥」封装进SslServerCredentialsOptions并通过SslServerCredentials绑定监听端口,客户端把「CA 根证书」封装进SslCredentialsOptions并通过SslCredentials创建 Channel,二者组合即形成一条端到端加密、服务器身份可验证的 RPC 信道。本示例的三步源码流程(加载文件 → 组装 Options → 传入 Builder/CreateChannel)可直接复用到任何 gRPC C++ 服务中;运行示例时只需记住:examples/cpp/auth目录下构建、分终端启动ssl_serverssl_client,即可看到客户端输出Greeter received: Hello world

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 17:41:52

Python状态机驱动CNC G代码解析与模拟校验

简介&#xff1a;一个用Python实现的简单CNC状态机项目&#xff0c;面向自动化控制初学者、Python开发者及对G代码解析感兴趣的编程爱好者。项目通过解析G代码指令&#xff0c;模拟机床在等待、移动、切割等状态间的流转&#xff0c;帮助读者理解状态机模型在真实工业场景中的应…

作者头像 李华
网站建设 2026/9/16 17:38:00

从Docker启动到自建工具:Agent Zero AI智能体框架完整指南

从Docker启动到自建工具&#xff1a;Agent Zero AI智能体框架完整指南 【免费下载链接】agent-zero Agent Zero AI framework 项目地址: https://gitcode.com/GitHub_Trending/ag/agent-zero 想让 AI 自己查资料、跑任务、记住上次聊到哪&#xff1f;Agent Zero 是开源A…

作者头像 李华
网站建设 2026/9/16 17:36:22

抖音合集批量下载工具:3 步跑通 douyin-downloader 无水印下载

抖音合集批量下载工具&#xff1a;3 步跑通 douyin-downloader 无水印下载 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallba…

作者头像 李华