blob: 8b0573bc8a55a5741fdf83da6766ff597e3eb8d4 [file] [log] [blame]
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -07001# Copyright 2015 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Application default credentials.
16
17Implements application default credentials and project ID detection.
18"""
19
20import io
21import json
22import logging
23import os
Thea Flowersa8d93482018-05-31 14:52:06 -070024import warnings
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070025
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070026from google.auth import environment_vars
27from google.auth import exceptions
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070028import google.auth.transport._http_client
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070029
30_LOGGER = logging.getLogger(__name__)
31
32# Valid types accepted for file-based credentials.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070033_AUTHORIZED_USER_TYPE = "authorized_user"
34_SERVICE_ACCOUNT_TYPE = "service_account"
bojeil-googled4d7f382021-02-16 12:33:20 -080035_EXTERNAL_ACCOUNT_TYPE = "external_account"
36_VALID_TYPES = (_AUTHORIZED_USER_TYPE, _SERVICE_ACCOUNT_TYPE, _EXTERNAL_ACCOUNT_TYPE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070037
38# Help message when no credentials can be found.
Thea Flowersa8d93482018-05-31 14:52:06 -070039_HELP_MESSAGE = """\
40Could not automatically determine credentials. Please set {env} or \
41explicitly create credentials and re-run the application. For more \
42information, please see \
Christopher Wilcoxf1028252018-09-21 10:03:04 -070043https://cloud.google.com/docs/authentication/getting-started
Bu Sun Kim9eec0912019-10-21 17:04:21 -070044""".format(
45 env=environment_vars.CREDENTIALS
46).strip()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070047
Thea Flowersa8d93482018-05-31 14:52:06 -070048# Warning when using Cloud SDK user credentials
49_CLOUD_SDK_CREDENTIALS_WARNING = """\
50Your application has authenticated using end user credentials from Google \
arithmetic1728f30b45a2020-06-17 23:36:04 -070051Cloud SDK without a quota project. You might receive a "quota exceeded" \
52or "API not enabled" error. We recommend you rerun \
53`gcloud auth application-default login` and make sure a quota project is \
54added. Or you can use service accounts instead. For more information \
55about service accounts, see https://cloud.google.com/docs/authentication/"""
Thea Flowersa8d93482018-05-31 14:52:06 -070056
bojeil-google10bd9fb2021-09-30 23:19:51 -070057# The subject token type used for AWS external_account credentials.
58_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request"
59
Thea Flowersa8d93482018-05-31 14:52:06 -070060
61def _warn_about_problematic_credentials(credentials):
62 """Determines if the credentials are problematic.
63
64 Credentials from the Cloud SDK that are associated with Cloud SDK's project
65 are problematic because they may not have APIs enabled and have limited
66 quota. If this is the case, warn about it.
67 """
68 from google.auth import _cloud_sdk
Bu Sun Kim9eec0912019-10-21 17:04:21 -070069
Thea Flowersa8d93482018-05-31 14:52:06 -070070 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
71 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
72
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070073
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070074def load_credentials_from_file(
bojeil-googled4d7f382021-02-16 12:33:20 -080075 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070076):
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070077 """Loads Google credentials from a file.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070078
bojeil-googled4d7f382021-02-16 12:33:20 -080079 The credentials file must be a service account key, stored authorized
80 user credentials or external account credentials.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070081
82 Args:
83 filename (str): The full path to the credentials file.
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070084 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
85 specified, the credentials will automatically be scoped if
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070086 necessary
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070087 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
88 Google client library. Use 'scopes' for user-defined scopes.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070089 quota_project_id (Optional[str]): The project ID used for
bojeil-googled4d7f382021-02-16 12:33:20 -080090 quota and billing.
91 request (Optional[google.auth.transport.Request]): An object used to make
92 HTTP requests. This is used to determine the associated project ID
93 for a workload identity pool resource (external account credentials).
94 If not specified, then it will use a
95 google.auth.transport.requests.Request client to make requests.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070096
97 Returns:
98 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
99 credentials and the project ID. Authorized user credentials do not
bojeil-googled4d7f382021-02-16 12:33:20 -0800100 have the project ID information. External account credentials project
101 IDs may not always be determined.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700102
103 Raises:
104 google.auth.exceptions.DefaultCredentialsError: if the file is in the
weitaiting6e86c932017-08-12 03:26:59 +0800105 wrong format or is missing.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700106 """
weitaiting6e86c932017-08-12 03:26:59 +0800107 if not os.path.exists(filename):
108 raise exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700109 "File {} was not found.".format(filename)
110 )
weitaiting6e86c932017-08-12 03:26:59 +0800111
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700112 with io.open(filename, "r") as file_obj:
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700113 try:
114 info = json.load(file_obj)
Danny Hermes895e3692017-11-09 11:35:57 -0800115 except ValueError as caught_exc:
116 new_exc = exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700117 "File {} is not a valid json file.".format(filename), caught_exc
118 )
Tres Seaver560cf1e2021-08-03 16:35:54 -0400119 raise new_exc from caught_exc
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700120
121 # The type key should indicate that the file is either a service account
122 # credentials file or an authorized user credentials file.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700123 credential_type = info.get("type")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700124
125 if credential_type == _AUTHORIZED_USER_TYPE:
arithmetic1728772dac62020-03-27 14:34:13 -0700126 from google.oauth2 import credentials
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800127
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700128 try:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700129 credentials = credentials.Credentials.from_authorized_user_info(
130 info, scopes=scopes
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700131 )
Danny Hermes895e3692017-11-09 11:35:57 -0800132 except ValueError as caught_exc:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700133 msg = "Failed to load authorized user credentials from {}".format(filename)
Danny Hermes0a93e872017-11-09 12:18:58 -0800134 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
Tres Seaver560cf1e2021-08-03 16:35:54 -0400135 raise new_exc from caught_exc
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700136 if quota_project_id:
137 credentials = credentials.with_quota_project(quota_project_id)
arithmetic1728f30b45a2020-06-17 23:36:04 -0700138 if not credentials.quota_project_id:
139 _warn_about_problematic_credentials(credentials)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700140 return credentials, None
141
142 elif credential_type == _SERVICE_ACCOUNT_TYPE:
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800143 from google.oauth2 import service_account
144
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700145 try:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700146 credentials = service_account.Credentials.from_service_account_info(
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700147 info, scopes=scopes, default_scopes=default_scopes
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700148 )
Danny Hermes895e3692017-11-09 11:35:57 -0800149 except ValueError as caught_exc:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700150 msg = "Failed to load service account credentials from {}".format(filename)
Danny Hermes0a93e872017-11-09 12:18:58 -0800151 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
Tres Seaver560cf1e2021-08-03 16:35:54 -0400152 raise new_exc from caught_exc
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700153 if quota_project_id:
154 credentials = credentials.with_quota_project(quota_project_id)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700155 return credentials, info.get("project_id")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700156
bojeil-googled4d7f382021-02-16 12:33:20 -0800157 elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
158 credentials, project_id = _get_external_account_credentials(
159 info,
160 filename,
161 scopes=scopes,
162 default_scopes=default_scopes,
163 request=request,
164 )
165 if quota_project_id:
166 credentials = credentials.with_quota_project(quota_project_id)
167 return credentials, project_id
168
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700169 else:
170 raise exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700171 "The file {file} does not have a valid type. "
172 "Type is {type}, expected one of {valid_types}.".format(
173 file=filename, type=credential_type, valid_types=_VALID_TYPES
174 )
175 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700176
177
arithmetic172811ebaeb2021-09-07 14:38:49 -0700178def _get_gcloud_sdk_credentials(quota_project_id=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700179 """Gets the credentials and project ID from the Cloud SDK."""
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800180 from google.auth import _cloud_sdk
181
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400182 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...")
183
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700184 # Check if application default credentials exist.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700185 credentials_filename = _cloud_sdk.get_application_default_credentials_path()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700186
187 if not os.path.isfile(credentials_filename):
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400188 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700189 return None, None
190
arithmetic172811ebaeb2021-09-07 14:38:49 -0700191 credentials, project_id = load_credentials_from_file(
192 credentials_filename, quota_project_id=quota_project_id
193 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700194
195 if not project_id:
196 project_id = _cloud_sdk.get_project_id()
197
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700198 return credentials, project_id
199
200
arithmetic172811ebaeb2021-09-07 14:38:49 -0700201def _get_explicit_environ_credentials(quota_project_id=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700202 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
Bu Sun Kim9dc2d862021-02-11 12:53:26 -0700203 variable."""
arithmetic1728333cb762021-02-25 15:42:32 -0800204 from google.auth import _cloud_sdk
205
206 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700207 explicit_file = os.environ.get(environment_vars.CREDENTIALS)
208
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400209 _LOGGER.debug(
210 "Checking %s for explicit credentials as part of auth process...", explicit_file
211 )
212
arithmetic1728333cb762021-02-25 15:42:32 -0800213 if explicit_file is not None and explicit_file == cloud_sdk_adc_path:
214 # Cloud sdk flow calls gcloud to fetch project id, so if the explicit
215 # file path is cloud sdk credentials path, then we should fall back
216 # to cloud sdk flow, otherwise project id cannot be obtained.
217 _LOGGER.debug(
218 "Explicit credentials path %s is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...",
219 explicit_file,
220 )
arithmetic172811ebaeb2021-09-07 14:38:49 -0700221 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id)
arithmetic1728333cb762021-02-25 15:42:32 -0800222
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700223 if explicit_file is not None:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700224 credentials, project_id = load_credentials_from_file(
arithmetic172811ebaeb2021-09-07 14:38:49 -0700225 os.environ[environment_vars.CREDENTIALS], quota_project_id=quota_project_id
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700226 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700227
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700228 return credentials, project_id
229
230 else:
231 return None, None
232
233
234def _get_gae_credentials():
235 """Gets Google App Engine App Identity credentials and project ID."""
Zev Goldstein7f7d92d2021-07-23 15:52:46 -0400236 # If not GAE gen1, prefer the metadata service even if the GAE APIs are
237 # available as per https://google.aip.dev/auth/4115.
238 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27":
239 return None, None
240
James Wilson6e0781b2018-12-20 20:38:52 -0500241 # While this library is normally bundled with app_engine, there are
242 # some cases where it's not available, so we tolerate ImportError.
243 try:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400244 _LOGGER.debug("Checking for App Engine runtime as part of auth process...")
James Wilson6e0781b2018-12-20 20:38:52 -0500245 import google.auth.app_engine as app_engine
246 except ImportError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400247 _LOGGER.warning("Import of App Engine auth library failed.")
James Wilson6e0781b2018-12-20 20:38:52 -0500248 return None, None
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800249
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700250 try:
251 credentials = app_engine.Credentials()
252 project_id = app_engine.get_project_id()
253 return credentials, project_id
254 except EnvironmentError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400255 _LOGGER.debug(
256 "No App Engine library was found so cannot authentication via App Engine Identity Credentials."
257 )
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700258 return None, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700259
260
261def _get_gce_credentials(request=None):
262 """Gets credentials and project ID from the GCE Metadata Service."""
263 # Ping requires a transport, but we want application default credentials
264 # to require no arguments. So, we'll use the _http_client transport which
265 # uses http.client. This is only acceptable because the metadata server
266 # doesn't do SSL and never requires proxies.
James Wilson6e0781b2018-12-20 20:38:52 -0500267
268 # While this library is normally bundled with compute_engine, there are
269 # some cases where it's not available, so we tolerate ImportError.
270 try:
271 from google.auth import compute_engine
272 from google.auth.compute_engine import _metadata
273 except ImportError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400274 _LOGGER.warning("Import of Compute Engine auth library failed.")
James Wilson6e0781b2018-12-20 20:38:52 -0500275 return None, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700276
277 if request is None:
278 request = google.auth.transport._http_client.Request()
279
280 if _metadata.ping(request=request):
281 # Get the project ID.
282 try:
Jon Wayne Parrott5b03ba12016-10-24 13:51:26 -0700283 project_id = _metadata.get_project_id(request=request)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700284 except exceptions.TransportError:
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700285 project_id = None
286
287 return compute_engine.Credentials(), project_id
288 else:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400289 _LOGGER.warning(
290 "Authentication failed using Compute Engine authentication due to unavailable metadata server."
291 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700292 return None, None
293
294
bojeil-googled4d7f382021-02-16 12:33:20 -0800295def _get_external_account_credentials(
296 info, filename, scopes=None, default_scopes=None, request=None
297):
298 """Loads external account Credentials from the parsed external account info.
299
300 The credentials information must correspond to a supported external account
301 credentials.
302
303 Args:
304 info (Mapping[str, str]): The external account info in Google format.
305 filename (str): The full path to the credentials file.
306 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
307 specified, the credentials will automatically be scoped if
308 necessary.
309 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
310 Google client library. Use 'scopes' for user-defined scopes.
311 request (Optional[google.auth.transport.Request]): An object used to make
312 HTTP requests. This is used to determine the associated project ID
313 for a workload identity pool resource (external account credentials).
314 If not specified, then it will use a
315 google.auth.transport.requests.Request client to make requests.
316
317 Returns:
318 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
319 credentials and the project ID. External account credentials project
320 IDs may not always be determined.
321
322 Raises:
323 google.auth.exceptions.DefaultCredentialsError: if the info dictionary
324 is in the wrong format or is missing required information.
325 """
326 # There are currently 2 types of external_account credentials.
bojeil-google10bd9fb2021-09-30 23:19:51 -0700327 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
bojeil-googled4d7f382021-02-16 12:33:20 -0800328 # Check if configuration corresponds to an AWS credentials.
329 from google.auth import aws
330
331 credentials = aws.Credentials.from_info(
332 info, scopes=scopes, default_scopes=default_scopes
333 )
bojeil-google10bd9fb2021-09-30 23:19:51 -0700334 else:
bojeil-googled4d7f382021-02-16 12:33:20 -0800335 try:
336 # Check if configuration corresponds to an Identity Pool credentials.
337 from google.auth import identity_pool
338
339 credentials = identity_pool.Credentials.from_info(
340 info, scopes=scopes, default_scopes=default_scopes
341 )
342 except ValueError:
343 # If the configuration is invalid or does not correspond to any
344 # supported external_account credentials, raise an error.
345 raise exceptions.DefaultCredentialsError(
346 "Failed to load external account credentials from {}".format(filename)
347 )
348 if request is None:
349 request = google.auth.transport.requests.Request()
350
351 return credentials, credentials.get_project_id(request=request)
352
353
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700354def default(scopes=None, request=None, quota_project_id=None, default_scopes=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700355 """Gets the default credentials for the current environment.
356
357 `Application Default Credentials`_ provides an easy way to obtain
358 credentials to call Google APIs for server-to-server or local applications.
359 This function acquires credentials from the environment in the following
360 order:
361
362 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
363 to the path of a valid service account JSON private key file, then it is
364 loaded and returned. The project ID returned is the project ID defined
365 in the service account file if available (some older files do not
366 contain project ID information).
bojeil-googled4d7f382021-02-16 12:33:20 -0800367
368 If the environment variable is set to the path of a valid external
369 account JSON configuration file (workload identity federation), then the
370 configuration file is used to determine and retrieve the external
371 credentials from the current environment (AWS, Azure, etc).
372 These will then be exchanged for Google access tokens via the Google STS
373 endpoint.
374 The project ID returned in this case is the one corresponding to the
375 underlying workload identity pool resource if determinable.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700376 2. If the `Google Cloud SDK`_ is installed and has application default
377 credentials set they are loaded and returned.
378
379 To enable application default credentials with the Cloud SDK run::
380
381 gcloud auth application-default login
382
383 If the Cloud SDK has an active project, the project ID is returned. The
384 active project can be set using::
385
386 gcloud config set project
387
388 3. If the application is running in the `App Engine standard environment`_
David Buxton0323cf32020-10-29 21:26:11 +0000389 (first generation) then the credentials and project ID from the
390 `App Identity Service`_ are used.
391 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
392 the `App Engine flexible environment`_ or the `App Engine standard
393 environment`_ (second generation) then the credentials and project ID
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700394 are obtained from the `Metadata Service`_.
395 5. If no credentials are found,
396 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
397
398 .. _Application Default Credentials: https://developers.google.com\
399 /identity/protocols/application-default-credentials
400 .. _Google Cloud SDK: https://cloud.google.com/sdk
401 .. _App Engine standard environment: https://cloud.google.com/appengine
402 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\
403 /appidentity/
404 .. _Compute Engine: https://cloud.google.com/compute
405 .. _App Engine flexible environment: https://cloud.google.com\
406 /appengine/flexible
407 .. _Metadata Service: https://cloud.google.com/compute/docs\
408 /storing-retrieving-metadata
David Buxton0323cf32020-10-29 21:26:11 +0000409 .. _Cloud Run: https://cloud.google.com/run
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700410
411 Example::
412
413 import google.auth
414
415 credentials, project_id = google.auth.default()
416
417 Args:
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800418 scopes (Sequence[str]): The list of scopes for the credentials. If
419 specified, the credentials will automatically be scoped if
420 necessary.
bojeil-googled4d7f382021-02-16 12:33:20 -0800421 request (Optional[google.auth.transport.Request]): An object used to make
422 HTTP requests. This is used to either detect whether the application
423 is running on Compute Engine or to determine the associated project
424 ID for a workload identity pool resource (external account
425 credentials). If not specified, then it will either use the standard
426 library http client to make requests for Compute Engine credentials
427 or a google.auth.transport.requests.Request client for external
428 account credentials.
429 quota_project_id (Optional[str]): The project ID used for
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700430 quota and billing.
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700431 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
432 Google client library. Use 'scopes' for user-defined scopes.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700433 Returns:
434 Tuple[~google.auth.credentials.Credentials, Optional[str]]:
435 the current environment's credentials and project ID. Project ID
436 may be None, which indicates that the Project ID could not be
437 ascertained from the environment.
438
439 Raises:
440 ~google.auth.exceptions.DefaultCredentialsError:
441 If no credentials were found, or if the credentials found were
442 invalid.
443 """
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800444 from google.auth.credentials import with_scopes_if_required
445
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800446 explicit_project_id = os.environ.get(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700447 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
448 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700449
450 checkers = (
bojeil-googled4d7f382021-02-16 12:33:20 -0800451 # Avoid passing scopes here to prevent passing scopes to user credentials.
452 # with_scopes_if_required() below will ensure scopes/default scopes are
453 # safely set on the returned credentials since requires_scopes will
454 # guard against setting scopes on user credentials.
arithmetic172811ebaeb2021-09-07 14:38:49 -0700455 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id),
456 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id),
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700457 _get_gae_credentials,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700458 lambda: _get_gce_credentials(request),
459 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700460
461 for checker in checkers:
462 credentials, project_id = checker()
463 if credentials is not None:
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700464 credentials = with_scopes_if_required(
465 credentials, scopes, default_scopes=default_scopes
466 )
bojeil-googled4d7f382021-02-16 12:33:20 -0800467
468 # For external account credentials, scopes are required to determine
469 # the project ID. Try to get the project ID again if not yet
470 # determined.
471 if not project_id and callable(
472 getattr(credentials, "get_project_id", None)
473 ):
474 if request is None:
475 request = google.auth.transport.requests.Request()
476 project_id = credentials.get_project_id(request=request)
477
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700478 if quota_project_id:
479 credentials = credentials.with_quota_project(quota_project_id)
480
Jacob Hayes15af07b2017-12-13 14:09:47 -0600481 effective_project_id = explicit_project_id or project_id
482 if not effective_project_id:
483 _LOGGER.warning(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700484 "No project ID could be determined. Consider running "
485 "`gcloud config set project` or setting the %s "
486 "environment variable",
487 environment_vars.PROJECT,
488 )
Jacob Hayes15af07b2017-12-13 14:09:47 -0600489 return credentials, effective_project_id
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700490
491 raise exceptions.DefaultCredentialsError(_HELP_MESSAGE)