You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloud Run容器通过Rust Tonic gRPC通信时遇证书未知颁发者错误

Cloud Run + Tonic gRPC 证书错误排查与示例

核心问题排查

  • 确认Cloud Run服务域名正确性:必须使用Cloud Run分配的官方域名格式 https://<service-name>-<project-hash>-<region>.a.run.app,禁止使用IP或未配置有效SSL证书的自定义域名。
  • 检查Tonic依赖特性:确保Cargo.toml中tonic的特性包含tls和tls-roots,这两个特性会自动引入rustls及Mozilla根证书集合(包含Google Trust Services根证书):
    tonic = { version = "0.9", features = ["tls", "tls-roots"] }
    
  • 避免手动配置CA证书:当使用Cloud Run官方域名时,tls-roots特性已包含验证所需的根证书,无需手动读取roots.pem,手动配置反而可能因证书文件不全导致验证失败。
  • 容器镜像根证书检查:如果使用极简镜像(如distroless),系统默认可能缺失根证书。此时要么依赖tonic的tls-roots特性自带证书,要么在镜像构建时添加CA证书包(例如Debian系镜像执行apt-get install -y ca-certificates)。

完整示例代码

服务端(Cloud Run部署)

服务端无需配置TLS,Cloud Run负载均衡会自动处理HTTPS终止,只需监听0.0.0.0:8080端口:

use tonic::transport::Server;
use my_proto::data_access_server::{DataAccess, DataAccessServer};
use my_proto::Response;

pub mod my_proto {
    tonic::include_proto("my_proto"); // 替换为你的proto文件名
}

#[derive(Default)]
pub struct MyDataAccessImpl;

#[tonic::async_trait]
impl DataAccess for MyDataAccessImpl {
    async fn some_method(
        &self,
        request: tonic::Request<my_proto::Request>,
    ) -> Result<tonic::Response<Response>, tonic::Status> {
        Ok(tonic::Response::new(Response {
            message: "Hello from Cloud Run".to_string(),
        }))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = ([0, 0, 0, 0], 8080).into();
    let service = DataAccessServer::new(MyDataAccessImpl);

    Server::builder()
        .add_service(service)
        .serve(addr)
        .await?;

    Ok(())
}

客户端(Cloud Run或本地)

直接使用DataAccessClient::connect即可,无需手动配置TLS:

use anyhow::Result;
use my_proto::data_access_client::DataAccessClient;
use my_proto::Request;

pub mod my_proto {
    tonic::include_proto("my_proto"); // 替换为你的proto文件名
}

#[tokio::main]
async fn main() -> Result<()> {
    // 替换为你的Cloud Run后端服务域名
    let backend_uri = "https://my-backend-service-xxxxxx-uc.a.run.app";

    let mut client = DataAccessClient::connect(backend_uri).await?;

    let request = tonic::Request::new(Request {
        input: "test".to_string(),
    });

    let response = client.some_method(request).await?;
    println!("Received: {}", response.into_inner().message);

    Ok(())
}

额外验证步骤

使用grpcurl测试后端服务的可访问性,排除代码外的问题:

grpcurl -d '{}' my-backend-service-xxxxxx-uc.a.run.app:443 grpc.health.v1.Health/Check

若该命令成功返回,则说明后端服务正常,问题出在客户端代码配置;若失败,检查域名正确性或Cloud Run服务状态。

内容的提问来源于stack exchange,提问作者wspeirs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:33:19