tonic icon indicating copy to clipboard operation
tonic copied to clipboard

BrokenPipe Error Using TLS With Root Certificate

Open cobbinma opened this issue 1 year ago • 2 comments

Bug Report

Version

tonic = { version = "0.11", features = ["tls"] }
❯ cargo tree | grep tonic
│   └── tonic v0.11.0
├── tonic v0.11.0 (*)
├── tonic-health v0.11.0
│   └── tonic v0.11.0 (*)
├── tonic-reflection v0.11.0
│   └── tonic v0.11.0 (*)
│   │   └── tonic v0.11.0 (*)

Platform

Darwin 0349 23.2.0 Darwin Kernel Version 23.2.0: Wed Nov 15 21:53:34 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T8103 arm6

Description

We recently upgraded tonic to v0.11.0 from v0.8 and are now receiving 'broken pipe' errors when trying to send requests to a remote server using tls with the mac root certificate.

called `Result::unwrap()` on an `Err` value: Status { code: Unknown, message: "transport error", source: Some(tonic::transport::Error(Transport, hyper::Error(Io, Custom { kind: BrokenPipe, error: "stream closed because of a broken pipe" }))) }
let pem = std::fs::read_to_string("/etc/ssl/cert.pem")?;
let ca = Certificate::from_pem(pem);
endpoint = endpoint.tls_config(ClientTlsConfig::new().ca_certificate(ca))?;

https://jessitron.com/2022/11/02/make-https-work-on-grpc-in-rust-load-a-root-certificate-into-the-tls-config/

If I downgrade to tonic v0.8 I can make successful requests to the server.

I have also tried using the feature tls-roots but this did not help.

I realise this will be difficult to replicate. Please let me know if there's any more detail I can provide.

cobbinma avatar Mar 08 '24 11:03 cobbinma

I had a similar issue when connecting to a TLS url, but against an AWS registered hostname. It seems that the root certs aren't loaded by default so you need to handle that in the code yourself.

For me I needed to add the "tls-native-roots" feature (tls-root is deprecated from v0.12.2) then use the following code

let tls_config = ClientTlsConfig::new().with_native_roots();
if let Ok(endpoint) = Channel::from_shared(uri.to_string()) {
    match endpoint.tls_config(tls_config)?.connect().await {
        Ok(channel) => ...
        Err(e) => ...
}

Not sure if you found a resolution but I came across this issue while searching for solutions and thought it best to provide how I solved it.

AlistairEpic avatar Oct 11 '24 10:10 AlistairEpic

Thanks @AlistairEpic. Really appreciate you helping on this 👍

Unfortunately I could not get past the error even when upgrading tonic to v0.12 and using "tls-native-roots"

tonic = { version = "0.12.0", features = ["tls", "tls-native-roots"] }
tonic-health = "0.12.0"
tonic-reflection = "0.12.0"
    fn endpoint(&self, endpoint: &str) -> Result<Endpoint, anyhow::Error> {
        let mut endpoint = tonic::transport::Endpoint::from_str(
            &endpoint.to_string().replace("dns:///", "dns://"),
        )?;
        if toolkit_rs::env::is_local() {
            endpoint = endpoint.tls_config(ClientTlsConfig::new().with_native_roots())?;
        }

        Ok(endpoint)
    }
status: Unknown, message: "transport error", details: [], metadata: MetadataMap { headers: {} }: transport error: connection error: stream closed because of a broken pipe

cobbinma avatar Oct 15 '24 09:10 cobbinma