Added certifi support, documented secure channels

This commit is contained in:
Vladimir Magamedov 2020-06-23 23:03:03 +03:00
parent 74f29128e3
commit e64a0c49ef
6 changed files with 52 additions and 1 deletions

View File

@ -45,9 +45,34 @@ There are two ways to call RPC methods:
See reference docs for all method types and for the
:py:class:`~grpclib.client.Stream` methods and attributes.
Secure Channels
~~~~~~~~~~~~~~~
Here is how to establish a secure connection to a public gRPC server:
.. code-block:: python3
channel = Channel(host, port, ssl=True)
^^^^^^^^
In this case ``grpclib`` uses system CA certificates. But ``grpclib`` has also
a built-in support for a certifi_ package which contains actual Mozilla's
collection of CA certificates. All you need is to install it and keep it
updated -- this is a more favorable way than relying on system CA certificates:
.. code-block:: console
$ pip3 install certifi
``grpclib`` also allows you to use a custom SSL configuration by providing a
:py:class:`~python:ssl.SSLContext` object. We have a simple mTLS auth example
in our code repository to illustrate how this works.
Reference
~~~~~~~~~
.. automodule:: grpclib.client
:members: Channel, Stream, UnaryUnaryMethod, UnaryStreamMethod,
StreamUnaryMethod, StreamStreamMethod
.. _certifi: https://github.com/certifi/python-certifi

View File

@ -706,7 +706,17 @@ class Channel:
if _ssl is None:
raise RuntimeError('SSL is not supported.')
ctx = _ssl.create_default_context(purpose=_ssl.Purpose.SERVER_AUTH)
try:
import certifi
except ImportError:
cafile = None
else:
cafile = certifi.where()
ctx = _ssl.create_default_context(
purpose=_ssl.Purpose.SERVER_AUTH,
cafile=cafile,
)
ctx.options |= (_ssl.OP_NO_TLSv1 | _ssl.OP_NO_TLSv1_1)
ctx.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20')
ctx.set_alpn_protocols(['h2'])

View File

@ -1,3 +1,4 @@
-r ../setup.txt
protobuf
googleapis-common-protos
certifi

View File

@ -4,6 +4,7 @@
#
# pip-compile requirements/runtime.in
#
certifi==2020.6.20
googleapis-common-protos==1.51.0
h2==3.1.1
hpack==3.0.0

View File

@ -6,6 +6,7 @@
#
async-timeout==3.0.1
attrs==19.3.0 # via pytest
certifi==2020.6.20
coverage==5.0.3 # via pytest-cov
faker==4.0.0
googleapis-common-protos==1.51.0

View File

@ -36,3 +36,16 @@ async def test_concurrent_connect(loop):
replies = await asyncio.gather(*tasks)
assert replies == reps
po.assert_called_once_with(ANY, '127.0.0.1', 50051, ssl=None)
def test_default_ssl_context():
certifi_channel = Channel(ssl=True)
with patch.dict('sys.modules', {'certifi': None}):
system_channel = Channel(ssl=True)
certifi_certs = certifi_channel._ssl.get_ca_certs(binary_form=True)
system_certs = system_channel._ssl.get_ca_certs(binary_form=True)
assert certifi_certs
assert system_certs
assert certifi_certs != system_certs