Skip to content

Commit 4748760

Browse files
feat: auto-enable mTLS when supported certificates are detected (#2472)
Signed-off-by: Radhika Agrawal <agrawalradhika@google.com> Co-authored-by: Daniel Sanche <d.sanche14@gmail.com>
1 parent a40cc89 commit 4748760

File tree

26 files changed

+2885
-305
lines changed

26 files changed

+2885
-305
lines changed

gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,20 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
279279
client_options = cast(client_options_lib.ClientOptions, client_options)
280280

281281
# Create SSL credentials for mutual TLS if needed.
282-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in ("true", "false"):
283-
raise ValueError("Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`")
284-
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
282+
283+
# Check if google-auth version supports should_use_client_cert for automatic
284+
# mTLS enablement
285+
if hasattr(mtls,"should_use_client_cert"):
286+
use_client_cert = mtls.should_use_client_cert()
287+
else: # pragma: NO COVER
288+
# if unsupported, fallback to reading from env var
289+
use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower()
290+
if use_client_cert_str not in ("true", "false"):
291+
raise ValueError(
292+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
293+
" either `true` or `false`"
294+
)
295+
use_client_cert = use_client_cert_str == "true"
285296

286297
client_cert_source_func = None
287298
is_mtls = False

gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,9 @@ def test_{{ service.client_name|snake_case }}_client_options(client_class, trans
278278

279279
# Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
280280
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}):
281-
with pytest.raises(ValueError):
282-
client = client_class(transport=transport_name)
281+
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
282+
with pytest.raises(ValueError):
283+
client = client_class(transport=transport_name)
283284

284285
# Check the case quota_project_id is provided
285286
options = client_options.ClientOptions(quota_project_id="octopus")

gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,32 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
183183

184184
_DEFAULT_UNIVERSE = "googleapis.com"
185185

186+
@staticmethod
187+
def _use_client_cert_effective():
188+
"""Returns whether client certificate should be used for mTLS if the
189+
google-auth version supports should_use_client_cert automatic mTLS enablement.
190+
191+
Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var.
192+
193+
Returns:
194+
bool: whether client certificate should be used for mTLS
195+
Raises:
196+
ValueError: (If using a version of google-auth without should_use_client_cert and
197+
GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.)
198+
"""
199+
# check if google-auth version supports should_use_client_cert for automatic mTLS enablement
200+
if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER
201+
return mtls.should_use_client_cert()
202+
else: # pragma: NO COVER
203+
# if unsupported, fallback to reading from env var
204+
use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower()
205+
if use_client_cert_str not in ("true", "false"):
206+
raise ValueError(
207+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
208+
" either `true` or `false`"
209+
)
210+
return use_client_cert_str == "true"
211+
186212
@classmethod
187213
def from_service_account_info(cls, info: dict, *args, **kwargs):
188214
"""Creates an instance of this client using the provided credentials
@@ -297,16 +323,14 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
297323
DeprecationWarning)
298324
if client_options is None:
299325
client_options = client_options_lib.ClientOptions()
300-
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
326+
use_client_cert = {{ service.client_name }}._use_client_cert_effective()
301327
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
302-
if use_client_cert not in ("true", "false"):
303-
raise ValueError("Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`")
304328
if use_mtls_endpoint not in ("auto", "never", "always"):
305329
raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`")
306330

307331
# Figure out the client cert source to use.
308332
client_cert_source = None
309-
if use_client_cert == "true":
333+
if use_client_cert:
310334
if client_options.client_cert_source:
311335
client_cert_source = client_options.client_cert_source
312336
elif mtls.has_default_client_cert_source():
@@ -336,14 +360,12 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
336360
google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT
337361
is not any of ["auto", "never", "always"].
338362
"""
339-
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower()
363+
use_client_cert = {{ service.client_name }}._use_client_cert_effective()
340364
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
341365
universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
342-
if use_client_cert not in ("true", "false"):
343-
raise ValueError("Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`")
344366
if use_mtls_endpoint not in ("auto", "never", "always"):
345367
raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`")
346-
return use_client_cert == "true", use_mtls_endpoint, universe_domain_env
368+
return use_client_cert, use_mtls_endpoint, universe_domain_env
347369

348370
@staticmethod
349371
def _get_client_cert_source(provided_cert_source, use_cert_flag):

0 commit comments

Comments
 (0)