13

I want to create a grpc channel to a source that I trust, but whose certificate I lack. Setting up a secure channel with default credentials fails:

import gprc
ssh_channel = grpc.secure_channel(<gprc url>, grpc.ssl_channel_credentials())
grpc.channel_ready_future(ssh_channel).result()

Results in:

E1017 10:05:15.783011100   11539 ssl_transport_security.cc:1229] Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED.
E1017 10:05:16.846366639   11539 ssl_transport_security.cc:1229] Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED.
E1017 10:05:18.688887874   11539 ssl_transport_security.cc:1229] Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED.
E1017 10:05:21.557399186   11539 ssl_transport_security.cc:1229] Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED.

I know this is possible, since e.g. in Java one would do the following:

import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
...
sslContext = GrpcSslContexts.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
channel = NettyChannelBuilder.forAddress(<gprc url>, 443).sslContext(sslContext).build();

However I haven't found any similar way for Python. The documentation of grpc.secure_channel also describes an option argument, that according to the documentation is:

An optional list of key-value pairs (channel args in gRPC Core runtime) to configure the channel.

A reference to channel args here does not provide any help either. Any ideas?

UPDATE: (19/01/14):

There is an open pull request to add this option in the Python code, but it seems stuck in a PR for months now: https://github.com/grpc/grpc/pull/12656

user2416984
  • 941
  • 1
  • 11
  • 18

1 Answers1

6

You may have to fetch the certificate from the site in a separate step. If it can be a one-off, just use your browser and save the cert somewhere convenient. Otherwise, see How can I retrieve the TLS/SSL peer certificate of a remote host using python?.

In my case I saved the cert with my browser and did the following (I needed to override the target name with the one in the cert as it was self-signed and the domain name didn't match):

with open(cert_path, 'rb') as f:
    cert_bytes = f.read()

credentials = grpc.ssl_channel_credentials(cert_bytes)
# Deal with cert being self-signed:
cert_cn = "cn.from.cert.com" # or parse it out of the cert data
options = (('grpc.ssl_target_name_override', cert_cn,),)

channnel = grpc.secure_channel(target, credentials, options)
Martin Stone
  • 12,682
  • 2
  • 39
  • 53
  • 2
    This doesn't work for me, as the network contains a proxy server with a different domain name. I would rather prefer an option that allows ignoring ssl certificate just as is possible in Java. – user2416984 Nov 12 '18 at 08:03
  • Hi. Have you found solution you wanted? – emil14 Apr 07 '21 at 16:21