Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 89fc6f2

Browse filesBrowse files
authored
feat(iam): support an alternative env to decide if mtls should be enabled (#1945)
`CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE` is another endpoint that can be set in Gcloud CLI to enable Certificate Based Access. We should support it as well.
1 parent 4598454 commit 89fc6f2
Copy full SHA for 89fc6f2

4 files changed

+139-20Lines changed: 139 additions & 20 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎packages/google-auth/google/auth/environment_vars.py‎

Copy file name to clipboardExpand all lines: packages/google-auth/google/auth/environment_vars.py
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@
113113
"""Environment variable defining the location of Google API certificate config
114114
file."""
115115

116+
CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE = (
117+
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE"
118+
)
119+
"""Environment variable controlling whether to use client certificate or not.
120+
This variable is the fallback of GOOGLE_API_USE_CLIENT_CERTIFICATE."""
121+
122+
CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH = (
123+
"CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH"
124+
)
125+
"""Environment variable defining the location of Google API certificate config
126+
file. This variable is the fallback of GOOGLE_API_CERTIFICATE_CONFIG."""
127+
116128
GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES = (
117129
"GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES"
118130
)
Collapse file

‎packages/google-auth/google/auth/iam.py‎

Copy file name to clipboardExpand all lines: packages/google-auth/google/auth/iam.py
+7-16Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@
2222
import base64
2323
import http.client as http_client
2424
import json
25-
import os
2625

2726
from google.auth import _exponential_backoff
2827
from google.auth import _helpers
2928
from google.auth import credentials
3029
from google.auth import crypt
3130
from google.auth import exceptions
32-
from google.auth.transport import mtls
31+
from google.auth.transport import _mtls_helper
3332

3433
IAM_RETRY_CODES = {
3534
http_client.INTERNAL_SERVER_ERROR,
@@ -40,20 +39,12 @@
4039

4140
_IAM_SCOPE = ["https://www.googleapis.com/auth/iam"]
4241

43-
# 1. Determine if we should use mTLS.
44-
# Note: We only support automatic mTLS on the default googleapis.com universe.
45-
if hasattr(mtls, "should_use_client_cert"):
46-
use_client_cert = mtls.should_use_client_cert()
47-
else: # pragma: NO COVER
48-
# if unsupported, fallback to reading from env var
49-
use_client_cert = (
50-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() == "true"
51-
)
52-
53-
# 2. Construct the template domain using the library's DEFAULT_UNIVERSE_DOMAIN constant.
54-
# This ensures that the .replace() calls in the classes will work correctly.
55-
if use_client_cert:
56-
# We use the .mtls. prefix only for the default universe template
42+
# Determine if we should use mTLS.
43+
if (
44+
hasattr(_mtls_helper, "check_use_client_cert")
45+
and _mtls_helper.check_use_client_cert()
46+
):
47+
# Construct the template domain using the library's DEFAULT_UNIVERSE_DOMAIN constant.
5748
_IAM_DOMAIN = f"iamcredentials.mtls.{credentials.DEFAULT_UNIVERSE_DOMAIN}"
5849
else:
5950
_IAM_DOMAIN = f"iamcredentials.{credentials.DEFAULT_UNIVERSE_DOMAIN}"
Collapse file

‎packages/google-auth/google/auth/transport/_mtls_helper.py‎

Copy file name to clipboardExpand all lines: packages/google-auth/google/auth/transport/_mtls_helper.py
+20-3Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,14 @@ def _get_cert_config_path(certificate_config_path=None):
151151
if env_path is not None and env_path != "":
152152
certificate_config_path = env_path
153153
else:
154-
certificate_config_path = CERTIFICATE_CONFIGURATION_DEFAULT_PATH
154+
env_path = environ.get(
155+
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH,
156+
None,
157+
)
158+
if env_path is not None and env_path != "":
159+
certificate_config_path = env_path
160+
else:
161+
certificate_config_path = CERTIFICATE_CONFIGURATION_DEFAULT_PATH
155162

156163
certificate_config_path = path.expanduser(certificate_config_path)
157164
if not path.exists(certificate_config_path):
@@ -452,13 +459,23 @@ def check_use_client_cert():
452459
Returns:
453460
bool: Whether the client certificate should be used for mTLS connection.
454461
"""
455-
use_client_cert = getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE")
462+
use_client_cert = getenv(environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE)
463+
if use_client_cert is None or use_client_cert == "":
464+
use_client_cert = getenv(
465+
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
466+
)
467+
456468
# Check if the value of GOOGLE_API_USE_CLIENT_CERTIFICATE is set.
457469
if use_client_cert:
458470
return use_client_cert.lower() == "true"
459471
else:
460472
# Check if the value of GOOGLE_API_CERTIFICATE_CONFIG is set.
461-
cert_path = getenv("GOOGLE_API_CERTIFICATE_CONFIG")
473+
cert_path = getenv(environment_vars.GOOGLE_API_CERTIFICATE_CONFIG)
474+
if cert_path is None:
475+
cert_path = getenv(
476+
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH
477+
)
478+
462479
if cert_path:
463480
try:
464481
with open(cert_path, "r") as f:
Collapse file

‎packages/google-auth/tests/transport/test__mtls_helper.py‎

Copy file name to clipboardExpand all lines: packages/google-auth/tests/transport/test__mtls_helper.py
+100-1Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from OpenSSL import crypto
2020
import pytest # type: ignore
2121

22-
from google.auth import exceptions
22+
from google.auth import environment_vars, exceptions
2323
from google.auth.transport import _mtls_helper
2424

2525
CERT_MOCK_VAL = b"cert"
@@ -681,6 +681,37 @@ def test_env_variable_file_does_not_exist(self, mock_path_exists):
681681
returned_path = _mtls_helper._get_cert_config_path()
682682
assert returned_path is None
683683

684+
def test_cert_config_path_precedence(self):
685+
# GOOGLE_API_CERTIFICATE_CONFIG takes precedence
686+
google_path = "/path/to/google/config"
687+
cloudsdk_path = "/path/to/cloudsdk/config"
688+
689+
with mock.patch.dict(
690+
os.environ,
691+
{
692+
environment_vars.GOOGLE_API_CERTIFICATE_CONFIG: google_path,
693+
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH: cloudsdk_path,
694+
},
695+
):
696+
with mock.patch("os.path.exists", return_value=True):
697+
assert _mtls_helper._get_cert_config_path() == google_path
698+
699+
def test_cert_config_path_fallback(self):
700+
# Fallback to CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH if GOOGLE_API_CERTIFICATE_CONFIG is unset
701+
cloudsdk_path = "/path/to/cloudsdk/config"
702+
703+
with mock.patch.dict(
704+
os.environ,
705+
{
706+
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH: cloudsdk_path
707+
},
708+
):
709+
if environment_vars.GOOGLE_API_CERTIFICATE_CONFIG in os.environ:
710+
del os.environ[environment_vars.GOOGLE_API_CERTIFICATE_CONFIG]
711+
712+
with mock.patch("os.path.exists", return_value=True):
713+
assert _mtls_helper._get_cert_config_path() == cloudsdk_path
714+
684715
@mock.patch.dict(
685716
os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": "path/to/config/file"}
686717
)
@@ -811,6 +842,74 @@ def test_config_file_not_found(self, mock_file):
811842
def test_no_env_vars_set(self):
812843
assert _mtls_helper.check_use_client_cert() is False
813844

845+
def test_use_client_cert_precedence(self):
846+
# GOOGLE_API_USE_CLIENT_CERTIFICATE takes precedence
847+
with mock.patch.dict(
848+
os.environ,
849+
{
850+
environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE: "true",
851+
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE: "false",
852+
},
853+
):
854+
assert _mtls_helper.check_use_client_cert() is True
855+
856+
with mock.patch.dict(
857+
os.environ,
858+
{
859+
environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE: "false",
860+
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE: "true",
861+
},
862+
):
863+
assert _mtls_helper.check_use_client_cert() is False
864+
865+
def test_use_client_cert_fallback(self):
866+
# Fallback to CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE if GOOGLE_API_USE_CLIENT_CERTIFICATE is unset
867+
with mock.patch.dict(
868+
os.environ,
869+
{environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE: "true"},
870+
):
871+
# Ensure GOOGLE_API_USE_CLIENT_CERTIFICATE is not set
872+
if environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE in os.environ:
873+
del os.environ[environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE]
874+
assert _mtls_helper.check_use_client_cert() is True
875+
876+
with mock.patch.dict(
877+
os.environ,
878+
{environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE: "false"},
879+
):
880+
if environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE in os.environ:
881+
del os.environ[environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE]
882+
assert _mtls_helper.check_use_client_cert() is False
883+
884+
@mock.patch("builtins.open", autospec=True)
885+
def test_check_use_client_cert_config_fallback(self, mock_file):
886+
# Test fallback for config file when determining if client cert should be used
887+
cloudsdk_path = "/path/to/cloudsdk/config"
888+
889+
mock_file.side_effect = mock.mock_open(
890+
read_data='{"cert_configs": {"workload": "exists"}}'
891+
)
892+
893+
with mock.patch.dict(
894+
os.environ,
895+
{
896+
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH: cloudsdk_path
897+
},
898+
):
899+
if environment_vars.GOOGLE_API_CERTIFICATE_CONFIG in os.environ:
900+
del os.environ[environment_vars.GOOGLE_API_CERTIFICATE_CONFIG]
901+
if environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE in os.environ:
902+
del os.environ[environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE]
903+
if (
904+
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
905+
in os.environ
906+
):
907+
del os.environ[
908+
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
909+
]
910+
911+
assert _mtls_helper.check_use_client_cert() is True
912+
814913

815914
class TestMtlsHelper:
816915
@mock.patch.object(_mtls_helper, "call_client_cert_callback")

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.