Closed redbmk closed 9 months ago
ssl=True
(loading system certificates managed by OS) and certifi
(managing system certificates using Python package manager) support was added mainly to connect to public services with public certificates. The only preferred way to connect to private services with custom certificates is to pass custom SSLContext
object explicitly. There are also other options to secure connections (proxies, tunnels).
BTW, SSL_CERT_FILE
is not httpx
-specific. Looks like SSL_CERT_FILE/-DIR
vars are specific to OpenSSL.
>>> ssl.get_default_verify_paths()
DefaultVerifyPaths(cafile=None, capath='/usr/lib/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/lib/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/lib/ssl/certs')
The only thing that bothers me is that introduction of SSL_CERT_FILE/-DIR
in grpclib
would be a backward incompatible change because these vars may already be present in some production environments and they may break those configurations.
Would you be opposed to introducing a new environment variable specific to grpclib
that wouldn't introduce any breaking changes? Something like GRPCLIB_CA_BUNDLE
maybe, and then fallback to certifi
if that's not present, and None
otherwise? Or maybe having a public function that builds a context but lets you pass in the context?
I guess I'm not sure how common this use case is, so maybe it's not worth putting in custom code for it. In my case we are using a public endpoint with public certificates, but we have a corporate VPN that intercepts traffic and replaces the certs with ones we "trust" on our systems. We're encouraged to work on VPN as often as possible, but run into issues when specific CA bundles are used instead of the system ones.
We potentially run into issues not just with our own code (where we could create our own context) but with code from other libraries or applications. What we've done that works for the most part is create a custom CA bundle that combines the latest certifi
with our internal certs, so that most things work both on and off VPN, as long as we point the right environment variables at it. We've had to do this for requests
, httpx
, OpenSSL
, and node
, for example, and it works with grpc
, but there's not a simple out-of-box solution for grpclib
.
If this doesn't seem like a common enough situation and you're not comfortable with supporting anything other than certifi
out of the box, that makes sense to me. But I think ideally it'd be great if we didn't have to recreate the private methods from scratch (that could change over time and we could miss out on potentially important fixes), or access them directly (which could also change over time in a breaking way, but wouldn't be considered a breaking change because it's not a publicly exposed method).
@redbmk Implemented one more way to pass verify locations to a Channel
Now you can use environment variables or explicitly specify location of your certificates.
Libraries like
requests
andhttpx
support environment variables (e.g.REQUESTS_CA_BUNDLE
orSSL_CERT_FILE
, respectively) to allow for custom certificate authority bundles. I was hoping thatSSL_CERT_FILE
would work, though that appears to behttpx
-specific. Right now,grpclib
importscertifi
if it exists, and defaults to the system settings only ifcertifi
isn't installed.It would be cool to have the ability to pass an env to point to a custom CA bundle and/or tell it to use the system certs even if
certifi
is installed. I've found two workarounds, but neither are ideal.This one works by loading a specific CA bundle, but it also requires accessing a private field which could potentially change:
This one would use the system defaults, but requires a lot of boilerplate that should probably be updated whenever
grpclib
changes. This is essentially a copy of_get_default_ssl_context
, but removes thecafile
:You could also use the above instead of using
channel._ssl
, and passcafile=os.getenv("SSL_CERT_FILE")
intocreate_default_context