Skip to content
This repository was archived by the owner on Nov 29, 2023. It is now read-only.

Commit 21bff87

Browse files
feat: implement mtls env variables mentioned in aip.dev/auth/4114 (#39)
This PR was generated using Autosynth. 🌈 Synth log will be available here: https://source.cloud.google.com/results/invocations/eb7165ef-a82f-4002-b64d-f55176216eb7/targets - [ ] To automatically regenerate this PR, check this box.
1 parent c9cc68b commit 21bff87

File tree

6 files changed

+402
-298
lines changed

6 files changed

+402
-298
lines changed

google/cloud/bigquery/reservation_v1/services/reservation_service/async_client.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,19 @@ def __init__(
112112
client_options (ClientOptions): Custom options for the client. It
113113
won't take effect if a ``transport`` instance is provided.
114114
(1) The ``api_endpoint`` property can be used to override the
115-
default endpoint provided by the client. GOOGLE_API_USE_MTLS
115+
default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT
116116
environment variable can also be used to override the endpoint:
117117
"always" (always use the default mTLS endpoint), "never" (always
118-
use the default regular endpoint, this is the default value for
119-
the environment variable) and "auto" (auto switch to the default
120-
mTLS endpoint if client SSL credentials is present). However,
121-
the ``api_endpoint`` property takes precedence if provided.
122-
(2) The ``client_cert_source`` property is used to provide client
123-
SSL credentials for mutual TLS transport. If not provided, the
124-
default SSL credentials will be used if present.
118+
use the default regular endpoint) and "auto" (auto switch to the
119+
default mTLS endpoint if client certificate is present, this is
120+
the default value). However, the ``api_endpoint`` property takes
121+
precedence if provided.
122+
(2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
123+
is "true", then the ``client_cert_source`` property can be used
124+
to provide client certificate for mutual TLS transport. If
125+
not provided, the default SSL client certificate will be used if
126+
present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
127+
set, no client certificate will be used.
125128
126129
Raises:
127130
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport

google/cloud/bigquery/reservation_v1/services/reservation_service/client.py

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#
1717

1818
from collections import OrderedDict
19+
from distutils import util
1920
import os
2021
import re
2122
from typing import Callable, Dict, Sequence, Tuple, Type, Union
@@ -27,6 +28,7 @@
2728
from google.api_core import retry as retries # type: ignore
2829
from google.auth import credentials # type: ignore
2930
from google.auth.transport import mtls # type: ignore
31+
from google.auth.transport.grpc import SslCredentials # type: ignore
3032
from google.auth.exceptions import MutualTLSChannelError # type: ignore
3133
from google.oauth2 import service_account # type: ignore
3234

@@ -244,16 +246,19 @@ def __init__(
244246
client_options (ClientOptions): Custom options for the client. It
245247
won't take effect if a ``transport`` instance is provided.
246248
(1) The ``api_endpoint`` property can be used to override the
247-
default endpoint provided by the client. GOOGLE_API_USE_MTLS
249+
default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT
248250
environment variable can also be used to override the endpoint:
249251
"always" (always use the default mTLS endpoint), "never" (always
250-
use the default regular endpoint, this is the default value for
251-
the environment variable) and "auto" (auto switch to the default
252-
mTLS endpoint if client SSL credentials is present). However,
253-
the ``api_endpoint`` property takes precedence if provided.
254-
(2) The ``client_cert_source`` property is used to provide client
255-
SSL credentials for mutual TLS transport. If not provided, the
256-
default SSL credentials will be used if present.
252+
use the default regular endpoint) and "auto" (auto switch to the
253+
default mTLS endpoint if client certificate is present, this is
254+
the default value). However, the ``api_endpoint`` property takes
255+
precedence if provided.
256+
(2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
257+
is "true", then the ``client_cert_source`` property can be used
258+
to provide client certificate for mutual TLS transport. If
259+
not provided, the default SSL client certificate will be used if
260+
present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
261+
set, no client certificate will be used.
257262
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
258263
The client info used to send a user-agent string along with
259264
API requests. If ``None``, then default info will be used.
@@ -269,25 +274,43 @@ def __init__(
269274
if client_options is None:
270275
client_options = ClientOptions.ClientOptions()
271276

272-
if client_options.api_endpoint is None:
273-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never")
277+
# Create SSL credentials for mutual TLS if needed.
278+
use_client_cert = bool(
279+
util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))
280+
)
281+
282+
ssl_credentials = None
283+
is_mtls = False
284+
if use_client_cert:
285+
if client_options.client_cert_source:
286+
import grpc # type: ignore
287+
288+
cert, key = client_options.client_cert_source()
289+
ssl_credentials = grpc.ssl_channel_credentials(
290+
certificate_chain=cert, private_key=key
291+
)
292+
is_mtls = True
293+
else:
294+
creds = SslCredentials()
295+
is_mtls = creds.is_mtls
296+
ssl_credentials = creds.ssl_credentials if is_mtls else None
297+
298+
# Figure out which api endpoint to use.
299+
if client_options.api_endpoint is not None:
300+
api_endpoint = client_options.api_endpoint
301+
else:
302+
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
274303
if use_mtls_env == "never":
275-
client_options.api_endpoint = self.DEFAULT_ENDPOINT
304+
api_endpoint = self.DEFAULT_ENDPOINT
276305
elif use_mtls_env == "always":
277-
client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT
306+
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
278307
elif use_mtls_env == "auto":
279-
has_client_cert_source = (
280-
client_options.client_cert_source is not None
281-
or mtls.has_default_client_cert_source()
282-
)
283-
client_options.api_endpoint = (
284-
self.DEFAULT_MTLS_ENDPOINT
285-
if has_client_cert_source
286-
else self.DEFAULT_ENDPOINT
308+
api_endpoint = (
309+
self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT
287310
)
288311
else:
289312
raise MutualTLSChannelError(
290-
"Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always"
313+
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always"
291314
)
292315

293316
# Save or instantiate the transport.
@@ -311,10 +334,9 @@ def __init__(
311334
self._transport = Transport(
312335
credentials=credentials,
313336
credentials_file=client_options.credentials_file,
314-
host=client_options.api_endpoint,
337+
host=api_endpoint,
315338
scopes=client_options.scopes,
316-
api_mtls_endpoint=client_options.api_endpoint,
317-
client_cert_source=client_options.client_cert_source,
339+
ssl_channel_credentials=ssl_credentials,
318340
quota_project_id=client_options.quota_project_id,
319341
client_info=client_info,
320342
)

google/cloud/bigquery/reservation_v1/services/reservation_service/transports/grpc.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# limitations under the License.
1616
#
1717

18+
import warnings
1819
from typing import Callable, Dict, Optional, Sequence, Tuple
1920

2021
from google.api_core import grpc_helpers # type: ignore
@@ -23,7 +24,6 @@
2324
from google.auth import credentials # type: ignore
2425
from google.auth.transport.grpc import SslCredentials # type: ignore
2526

26-
2727
import grpc # type: ignore
2828

2929
from google.cloud.bigquery.reservation_v1.types import reservation
@@ -74,6 +74,7 @@ def __init__(
7474
channel: grpc.Channel = None,
7575
api_mtls_endpoint: str = None,
7676
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
77+
ssl_channel_credentials: grpc.ChannelCredentials = None,
7778
quota_project_id: Optional[str] = None,
7879
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
7980
) -> None:
@@ -94,14 +95,16 @@ def __init__(
9495
ignored if ``channel`` is provided.
9596
channel (Optional[grpc.Channel]): A ``Channel`` instance through
9697
which to make calls.
97-
api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
98-
provided, it overrides the ``host`` argument and tries to create
98+
api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint.
99+
If provided, it overrides the ``host`` argument and tries to create
99100
a mutual TLS channel with client SSL credentials from
100101
``client_cert_source`` or applicatin default SSL credentials.
101-
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A
102-
callback to provide client SSL certificate bytes and private key
103-
bytes, both in PEM format. It is ignored if ``api_mtls_endpoint``
104-
is None.
102+
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]):
103+
Deprecated. A callback to provide client SSL certificate bytes and
104+
private key bytes, both in PEM format. It is ignored if
105+
``api_mtls_endpoint`` is None.
106+
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
107+
for grpc channel. It is ignored if ``channel`` is provided.
105108
quota_project_id (Optional[str]): An optional project to use for billing
106109
and quota.
107110
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -124,6 +127,11 @@ def __init__(
124127
# If a channel was explicitly provided, set it.
125128
self._grpc_channel = channel
126129
elif api_mtls_endpoint:
130+
warnings.warn(
131+
"api_mtls_endpoint and client_cert_source are deprecated",
132+
DeprecationWarning,
133+
)
134+
127135
host = (
128136
api_mtls_endpoint
129137
if ":" in api_mtls_endpoint
@@ -154,6 +162,23 @@ def __init__(
154162
scopes=scopes or self.AUTH_SCOPES,
155163
quota_project_id=quota_project_id,
156164
)
165+
else:
166+
host = host if ":" in host else host + ":443"
167+
168+
if credentials is None:
169+
credentials, _ = auth.default(
170+
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
171+
)
172+
173+
# create a new channel. The provided one is ignored.
174+
self._grpc_channel = type(self).create_channel(
175+
host,
176+
credentials=credentials,
177+
credentials_file=credentials_file,
178+
ssl_credentials=ssl_channel_credentials,
179+
scopes=scopes or self.AUTH_SCOPES,
180+
quota_project_id=quota_project_id,
181+
)
157182

158183
self._stubs = {} # type: Dict[str, Callable]
159184

@@ -219,13 +244,6 @@ def grpc_channel(self) -> grpc.Channel:
219244
This property caches on the instance; repeated calls return
220245
the same channel.
221246
"""
222-
# Sanity check: Only create a new channel if we do not already
223-
# have one.
224-
if not hasattr(self, "_grpc_channel"):
225-
self._grpc_channel = self.create_channel(
226-
self._host, credentials=self._credentials,
227-
)
228-
229247
# Return the channel from cache.
230248
return self._grpc_channel
231249

google/cloud/bigquery/reservation_v1/services/reservation_service/transports/grpc_asyncio.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
# limitations under the License.
1616
#
1717

18+
import warnings
1819
from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple
1920

2021
from google.api_core import gapic_v1 # type: ignore
2122
from google.api_core import grpc_helpers_async # type: ignore
23+
from google import auth # type: ignore
2224
from google.auth import credentials # type: ignore
2325
from google.auth.transport.grpc import SslCredentials # type: ignore
2426

@@ -116,6 +118,7 @@ def __init__(
116118
channel: aio.Channel = None,
117119
api_mtls_endpoint: str = None,
118120
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
121+
ssl_channel_credentials: grpc.ChannelCredentials = None,
119122
quota_project_id=None,
120123
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
121124
) -> None:
@@ -137,14 +140,16 @@ def __init__(
137140
are passed to :func:`google.auth.default`.
138141
channel (Optional[aio.Channel]): A ``Channel`` instance through
139142
which to make calls.
140-
api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
141-
provided, it overrides the ``host`` argument and tries to create
143+
api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint.
144+
If provided, it overrides the ``host`` argument and tries to create
142145
a mutual TLS channel with client SSL credentials from
143146
``client_cert_source`` or applicatin default SSL credentials.
144-
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A
145-
callback to provide client SSL certificate bytes and private key
146-
bytes, both in PEM format. It is ignored if ``api_mtls_endpoint``
147-
is None.
147+
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]):
148+
Deprecated. A callback to provide client SSL certificate bytes and
149+
private key bytes, both in PEM format. It is ignored if
150+
``api_mtls_endpoint`` is None.
151+
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
152+
for grpc channel. It is ignored if ``channel`` is provided.
148153
quota_project_id (Optional[str]): An optional project to use for billing
149154
and quota.
150155
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -167,12 +172,22 @@ def __init__(
167172
# If a channel was explicitly provided, set it.
168173
self._grpc_channel = channel
169174
elif api_mtls_endpoint:
175+
warnings.warn(
176+
"api_mtls_endpoint and client_cert_source are deprecated",
177+
DeprecationWarning,
178+
)
179+
170180
host = (
171181
api_mtls_endpoint
172182
if ":" in api_mtls_endpoint
173183
else api_mtls_endpoint + ":443"
174184
)
175185

186+
if credentials is None:
187+
credentials, _ = auth.default(
188+
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
189+
)
190+
176191
# Create SSL credentials with client_cert_source or application
177192
# default SSL credentials.
178193
if client_cert_source:
@@ -192,6 +207,23 @@ def __init__(
192207
scopes=scopes or self.AUTH_SCOPES,
193208
quota_project_id=quota_project_id,
194209
)
210+
else:
211+
host = host if ":" in host else host + ":443"
212+
213+
if credentials is None:
214+
credentials, _ = auth.default(
215+
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
216+
)
217+
218+
# create a new channel. The provided one is ignored.
219+
self._grpc_channel = type(self).create_channel(
220+
host,
221+
credentials=credentials,
222+
credentials_file=credentials_file,
223+
ssl_credentials=ssl_channel_credentials,
224+
scopes=scopes or self.AUTH_SCOPES,
225+
quota_project_id=quota_project_id,
226+
)
195227

196228
# Run the base constructor.
197229
super().__init__(
@@ -212,13 +244,6 @@ def grpc_channel(self) -> aio.Channel:
212244
This property caches on the instance; repeated calls return
213245
the same channel.
214246
"""
215-
# Sanity check: Only create a new channel if we do not already
216-
# have one.
217-
if not hasattr(self, "_grpc_channel"):
218-
self._grpc_channel = self.create_channel(
219-
self._host, credentials=self._credentials,
220-
)
221-
222247
# Return the channel from cache.
223248
return self._grpc_channel
224249

synth.metadata

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"git": {
55
"name": ".",
66
"remote": "https://github.com/googleapis/python-bigquery-reservation.git",
7-
"sha": "1136cae5bf131f9e6aa54aa081416f7f0848eba1"
7+
"sha": "660abdcc27a9c584d9a771dbf80bcc53fb0a5797"
88
}
99
},
1010
{

0 commit comments

Comments
 (0)