aboutsummaryrefslogtreecommitdiff
path: root/google
diff options
context:
space:
mode:
authorarithmetic1728 <58957152+arithmetic1728@users.noreply.github.com>2020-08-27 14:05:30 -0700
committerGitHub <noreply@github.com>2020-08-27 14:05:30 -0700
commitc0c995f3de237a2346b59797ee7c4d44ff2a197c (patch)
treee63b7688cbbff802ba769c39d8bf0a610e2538cc /google
parentae27b49468c5c3db99d0550af9066ca43cb0dda7 (diff)
downloadgoogle-auth-library-python-c0c995f3de237a2346b59797ee7c4d44ff2a197c.tar.gz
feat: add GOOGLE_API_USE_CLIENT_CERTIFICATE support (#592)
Diffstat (limited to 'google')
-rw-r--r--google/auth/environment_vars.py6
-rw-r--r--google/auth/transport/grpc.py57
-rw-r--r--google/auth/transport/requests.py26
-rw-r--r--google/auth/transport/urllib3.py27
4 files changed, 92 insertions, 24 deletions
diff --git a/google/auth/environment_vars.py b/google/auth/environment_vars.py
index 9c1367f..46a8926 100644
--- a/google/auth/environment_vars.py
+++ b/google/auth/environment_vars.py
@@ -53,3 +53,9 @@ the system falls back to the old variable.
GCE_METADATA_IP = "GCE_METADATA_IP"
"""Environment variable providing an alternate ip:port to be used for ip-only
GCE metadata requests."""
+
+GOOGLE_API_USE_CLIENT_CERTIFICATE = "GOOGLE_API_USE_CLIENT_CERTIFICATE"
+"""Environment variable controlling whether to use client certificate or not.
+
+The default value is false. Users have to explicitly set this value to true
+in order to use client certificate to establish a mutual TLS channel."""
diff --git a/google/auth/transport/grpc.py b/google/auth/transport/grpc.py
index 13234a3..ab7d0db 100644
--- a/google/auth/transport/grpc.py
+++ b/google/auth/transport/grpc.py
@@ -17,9 +17,11 @@
from __future__ import absolute_import
import logging
+import os
import six
+from google.auth import environment_vars
from google.auth import exceptions
from google.auth.transport import _mtls_helper
@@ -96,6 +98,9 @@ def secure_authorized_channel(
This creates a channel with SSL and :class:`AuthMetadataPlugin`. This
channel can be used to create a stub that can make authorized requests.
+ Users can configure client certificate or rely on device certificates to
+ establish a mutual TLS channel, if the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ variable is explicitly set to `true`.
Example::
@@ -138,7 +143,9 @@ def secure_authorized_channel(
ssl_credentials=regular_ssl_credentials)
Option 2: create a mutual TLS channel by calling a callback which returns
- the client side certificate and the key::
+ the client side certificate and the key (Note that
+ `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+ set to `true`)::
def my_client_cert_callback():
code_to_load_client_cert_and_key()
@@ -155,7 +162,9 @@ def secure_authorized_channel(
Option 3: use application default SSL credentials. It searches and uses
the command in a context aware metadata file, which is available on devices
- with endpoint verification support.
+ with endpoint verification support (Note that
+ `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+ set to `true`).
See https://cloud.google.com/endpoint-verification/docs/overview::
try:
@@ -174,7 +183,8 @@ def secure_authorized_channel(
ssl_credentials=default_ssl_credentials)
Option 4: not setting ssl_credentials and client_cert_callback. For devices
- without endpoint verification support, a regular TLS channel is created;
+ without endpoint verification support or `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable is not `true`, a regular TLS channel is created;
otherwise, a mutual TLS channel is created, however, the call should be
wrapped in a try/except block in case of malformed context aware metadata.
@@ -205,13 +215,15 @@ def secure_authorized_channel(
This argument is mutually exclusive with client_cert_callback;
providing both will raise an exception.
If ssl_credentials and client_cert_callback are None, application
- default SSL credentials will be used.
+ default SSL credentials are used if `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable is explicitly set to `true`, otherwise one way TLS
+ SSL credentials are used.
client_cert_callback (Callable[[], (bytes, bytes)]): Optional
callback function to obtain client certicate and key for mutual TLS
connection. This argument is mutually exclusive with
ssl_credentials; providing both will raise an exception.
- If ssl_credentials and client_cert_callback are None, application
- default SSL credentials will be used.
+ This argument does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable is explicitly set to `true`.
kwargs: Additional arguments to pass to :func:`grpc.secure_channel`.
Returns:
@@ -235,16 +247,21 @@ def secure_authorized_channel(
# If SSL credentials are not explicitly set, try client_cert_callback and ADC.
if not ssl_credentials:
- if client_cert_callback:
+ use_client_cert = os.getenv(
+ environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+ )
+ if use_client_cert == "true" and client_cert_callback:
# Use the callback if provided.
cert, key = client_cert_callback()
ssl_credentials = grpc.ssl_channel_credentials(
certificate_chain=cert, private_key=key
)
- else:
+ elif use_client_cert == "true":
# Use application default SSL credentials.
adc_ssl_credentils = SslCredentials()
ssl_credentials = adc_ssl_credentils.ssl_credentials
+ else:
+ ssl_credentials = grpc.ssl_channel_credentials()
# Combine the ssl credentials and the authorization credentials.
composite_credentials = grpc.composite_channel_credentials(
@@ -257,17 +274,29 @@ def secure_authorized_channel(
class SslCredentials:
"""Class for application default SSL credentials.
- For devices with endpoint verification support, a device certificate will be
- automatically loaded and mutual TLS will be established.
+ The behavior is controlled by `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment
+ variable whose default value is `false`. Client certificate will not be used
+ unless the environment variable is explicitly set to `true`. See
+ https://google.aip.dev/auth/4114
+
+ If the environment variable is `true`, then for devices with endpoint verification
+ support, a device certificate will be automatically loaded and mutual TLS will
+ be established.
See https://cloud.google.com/endpoint-verification/docs/overview.
"""
def __init__(self):
- # Load client SSL credentials.
- metadata_path = _mtls_helper._check_dca_metadata_path(
- _mtls_helper.CONTEXT_AWARE_METADATA_PATH
+ use_client_cert = os.getenv(
+ environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
)
- self._is_mtls = metadata_path is not None
+ if use_client_cert != "true":
+ self._is_mtls = False
+ else:
+ # Load client SSL credentials.
+ metadata_path = _mtls_helper._check_dca_metadata_path(
+ _mtls_helper.CONTEXT_AWARE_METADATA_PATH
+ )
+ self._is_mtls = metadata_path is not None
@property
def ssl_credentials(self):
diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py
index 4f5af7d..9a2f3af 100644
--- a/google/auth/transport/requests.py
+++ b/google/auth/transport/requests.py
@@ -19,6 +19,7 @@ from __future__ import absolute_import
import functools
import logging
import numbers
+import os
import time
try:
@@ -40,6 +41,7 @@ from requests.packages.urllib3.util.ssl_ import (
) # pylint: disable=ungrouped-imports
import six # pylint: disable=ungrouped-imports
+from google.auth import environment_vars
from google.auth import exceptions
from google.auth import transport
import google.auth.transport._mtls_helper
@@ -249,13 +251,18 @@ class AuthorizedSession(requests.Session):
credentials' headers to the request and refreshing credentials as needed.
This class also supports mutual TLS via :meth:`configure_mtls_channel`
- method. If client_cert_callback is provided, client certificate and private
+ method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable must be explicitly set to `true`, otherwise it does
+ nothing. Assume the environment is set to `true`, the method behaves in the
+ following manner:
+ If client_cert_callback is provided, client certificate and private
key are loaded using the callback; if client_cert_callback is None,
application default SSL credentials will be used. Exceptions are raised if
there are problems with the certificate, private key, or the loading process,
so it should be called within a try/except block.
- First we create an :class:`AuthorizedSession` instance and specify the endpoints::
+ First we set the environment variable to `true`, then create an :class:`AuthorizedSession`
+ instance and specify the endpoints::
regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
@@ -343,9 +350,11 @@ class AuthorizedSession(requests.Session):
def configure_mtls_channel(self, client_cert_callback=None):
"""Configure the client certificate and key for SSL connection.
- If client certificate and key are successfully obtained (from the given
- client_cert_callback or from application default SSL credentials), a
- :class:`_MutualTlsAdapter` instance will be mounted to "https://" prefix.
+ The function does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE` is
+ explicitly set to `true`. In this case if client certificate and key are
+ successfully obtained (from the given client_cert_callback or from application
+ default SSL credentials), a :class:`_MutualTlsAdapter` instance will be mounted
+ to "https://" prefix.
Args:
client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
@@ -358,6 +367,13 @@ class AuthorizedSession(requests.Session):
google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
creation failed for any reason.
"""
+ use_client_cert = os.getenv(
+ environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+ )
+ if use_client_cert != "true":
+ self._is_mtls = False
+ return
+
try:
import OpenSSL
except ImportError as caught_exc:
diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py
index 3742f1a..209fc51 100644
--- a/google/auth/transport/urllib3.py
+++ b/google/auth/transport/urllib3.py
@@ -17,6 +17,7 @@
from __future__ import absolute_import
import logging
+import os
import warnings
# Certifi is Mozilla's certificate bundle. Urllib3 needs a certificate bundle
@@ -45,6 +46,7 @@ except ImportError as caught_exc: # pragma: NO COVER
import six
import urllib3.exceptions # pylint: disable=ungrouped-imports
+from google.auth import environment_vars
from google.auth import exceptions
from google.auth import transport
@@ -202,13 +204,18 @@ class AuthorizedHttp(urllib3.request.RequestMethods):
credentials' headers to the request and refreshing credentials as needed.
This class also supports mutual TLS via :meth:`configure_mtls_channel`
- method. If client_cert_callback is provided, client certificate and private
+ method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable must be explicitly set to `true`, otherwise it does
+ nothing. Assume the environment is set to `true`, the method behaves in the
+ following manner:
+ If client_cert_callback is provided, client certificate and private
key are loaded using the callback; if client_cert_callback is None,
application default SSL credentials will be used. Exceptions are raised if
there are problems with the certificate, private key, or the loading process,
so it should be called within a try/except block.
- First we create an :class:`AuthorizedHttp` instance and specify the endpoints::
+ First we set the environment variable to `true`, then create an :class:`AuthorizedHttp`
+ instance and specify the endpoints::
regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
@@ -282,9 +289,13 @@ class AuthorizedHttp(urllib3.request.RequestMethods):
def configure_mtls_channel(self, client_cert_callback=None):
"""Configures mutual TLS channel using the given client_cert_callback or
- application default SSL credentials. Returns True if the channel is
- mutual TLS and False otherwise. Note that the `http` provided in the
- constructor will be overwritten.
+ application default SSL credentials. The behavior is controlled by
+ `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable.
+ (1) If the environment variable value is `true`, the function returns True
+ if the channel is mutual TLS and False otherwise. The `http` provided
+ in the constructor will be overwritten.
+ (2) If the environment variable is not set or `false`, the function does
+ nothing and it always return False.
Args:
client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
@@ -300,6 +311,12 @@ class AuthorizedHttp(urllib3.request.RequestMethods):
google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
creation failed for any reason.
"""
+ use_client_cert = os.getenv(
+ environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+ )
+ if use_client_cert != "true":
+ return False
+
try:
import OpenSSL
except ImportError as caught_exc: