blob: 4ae7c8c0612529d04f7399b4c6f0fce47ecd09f1 [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
arithmetic17285bd5ccf2021-10-21 15:25:46 -070026import six
27
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070028from google.auth import environment_vars
29from google.auth import exceptions
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070030import google.auth.transport._http_client
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070031
32_LOGGER = logging.getLogger(__name__)
33
34# Valid types accepted for file-based credentials.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070035_AUTHORIZED_USER_TYPE = "authorized_user"
36_SERVICE_ACCOUNT_TYPE = "service_account"
bojeil-googled4d7f382021-02-16 12:33:20 -080037_EXTERNAL_ACCOUNT_TYPE = "external_account"
38_VALID_TYPES = (_AUTHORIZED_USER_TYPE, _SERVICE_ACCOUNT_TYPE, _EXTERNAL_ACCOUNT_TYPE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070039
40# Help message when no credentials can be found.
Thea Flowersa8d93482018-05-31 14:52:06 -070041_HELP_MESSAGE = """\
42Could not automatically determine credentials. Please set {env} or \
43explicitly create credentials and re-run the application. For more \
44information, please see \
Christopher Wilcoxf1028252018-09-21 10:03:04 -070045https://cloud.google.com/docs/authentication/getting-started
Bu Sun Kim9eec0912019-10-21 17:04:21 -070046""".format(
47 env=environment_vars.CREDENTIALS
48).strip()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070049
Thea Flowersa8d93482018-05-31 14:52:06 -070050# Warning when using Cloud SDK user credentials
51_CLOUD_SDK_CREDENTIALS_WARNING = """\
52Your application has authenticated using end user credentials from Google \
arithmetic1728f30b45a2020-06-17 23:36:04 -070053Cloud SDK without a quota project. You might receive a "quota exceeded" \
54or "API not enabled" error. We recommend you rerun \
55`gcloud auth application-default login` and make sure a quota project is \
56added. Or you can use service accounts instead. For more information \
57about service accounts, see https://cloud.google.com/docs/authentication/"""
Thea Flowersa8d93482018-05-31 14:52:06 -070058
bojeil-google10bd9fb2021-09-30 23:19:51 -070059# The subject token type used for AWS external_account credentials.
60_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request"
61
Thea Flowersa8d93482018-05-31 14:52:06 -070062
63def _warn_about_problematic_credentials(credentials):
64 """Determines if the credentials are problematic.
65
66 Credentials from the Cloud SDK that are associated with Cloud SDK's project
67 are problematic because they may not have APIs enabled and have limited
68 quota. If this is the case, warn about it.
69 """
70 from google.auth import _cloud_sdk
Bu Sun Kim9eec0912019-10-21 17:04:21 -070071
Thea Flowersa8d93482018-05-31 14:52:06 -070072 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
73 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
74
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070075
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070076def load_credentials_from_file(
bojeil-googled4d7f382021-02-16 12:33:20 -080077 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070078):
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070079 """Loads Google credentials from a file.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070080
bojeil-googled4d7f382021-02-16 12:33:20 -080081 The credentials file must be a service account key, stored authorized
82 user credentials or external account credentials.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070083
84 Args:
85 filename (str): The full path to the credentials file.
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070086 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
87 specified, the credentials will automatically be scoped if
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070088 necessary
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -070089 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
90 Google client library. Use 'scopes' for user-defined scopes.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070091 quota_project_id (Optional[str]): The project ID used for
bojeil-googled4d7f382021-02-16 12:33:20 -080092 quota and billing.
93 request (Optional[google.auth.transport.Request]): An object used to make
94 HTTP requests. This is used to determine the associated project ID
95 for a workload identity pool resource (external account credentials).
96 If not specified, then it will use a
97 google.auth.transport.requests.Request client to make requests.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070098
99 Returns:
100 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
101 credentials and the project ID. Authorized user credentials do not
bojeil-googled4d7f382021-02-16 12:33:20 -0800102 have the project ID information. External account credentials project
103 IDs may not always be determined.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700104
105 Raises:
106 google.auth.exceptions.DefaultCredentialsError: if the file is in the
weitaiting6e86c932017-08-12 03:26:59 +0800107 wrong format or is missing.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700108 """
weitaiting6e86c932017-08-12 03:26:59 +0800109 if not os.path.exists(filename):
110 raise exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700111 "File {} was not found.".format(filename)
112 )
weitaiting6e86c932017-08-12 03:26:59 +0800113
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700114 with io.open(filename, "r") as file_obj:
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700115 try:
116 info = json.load(file_obj)
Danny Hermes895e3692017-11-09 11:35:57 -0800117 except ValueError as caught_exc:
118 new_exc = exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700119 "File {} is not a valid json file.".format(filename), caught_exc
120 )
arithmetic17285bd5ccf2021-10-21 15:25:46 -0700121 six.raise_from(new_exc, caught_exc)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700122
123 # The type key should indicate that the file is either a service account
124 # credentials file or an authorized user credentials file.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700125 credential_type = info.get("type")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700126
127 if credential_type == _AUTHORIZED_USER_TYPE:
arithmetic1728772dac62020-03-27 14:34:13 -0700128 from google.oauth2 import credentials
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800129
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700130 try:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700131 credentials = credentials.Credentials.from_authorized_user_info(
132 info, scopes=scopes
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700133 )
Danny Hermes895e3692017-11-09 11:35:57 -0800134 except ValueError as caught_exc:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700135 msg = "Failed to load authorized user credentials from {}".format(filename)
Danny Hermes0a93e872017-11-09 12:18:58 -0800136 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
arithmetic17285bd5ccf2021-10-21 15:25:46 -0700137 six.raise_from(new_exc, caught_exc)
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700138 if quota_project_id:
139 credentials = credentials.with_quota_project(quota_project_id)
arithmetic1728f30b45a2020-06-17 23:36:04 -0700140 if not credentials.quota_project_id:
141 _warn_about_problematic_credentials(credentials)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700142 return credentials, None
143
144 elif credential_type == _SERVICE_ACCOUNT_TYPE:
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800145 from google.oauth2 import service_account
146
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700147 try:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700148 credentials = service_account.Credentials.from_service_account_info(
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700149 info, scopes=scopes, default_scopes=default_scopes
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700150 )
Danny Hermes895e3692017-11-09 11:35:57 -0800151 except ValueError as caught_exc:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700152 msg = "Failed to load service account credentials from {}".format(filename)
Danny Hermes0a93e872017-11-09 12:18:58 -0800153 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
arithmetic17285bd5ccf2021-10-21 15:25:46 -0700154 six.raise_from(new_exc, caught_exc)
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700155 if quota_project_id:
156 credentials = credentials.with_quota_project(quota_project_id)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700157 return credentials, info.get("project_id")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700158
bojeil-googled4d7f382021-02-16 12:33:20 -0800159 elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
160 credentials, project_id = _get_external_account_credentials(
161 info,
162 filename,
163 scopes=scopes,
164 default_scopes=default_scopes,
165 request=request,
166 )
167 if quota_project_id:
168 credentials = credentials.with_quota_project(quota_project_id)
169 return credentials, project_id
170
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700171 else:
172 raise exceptions.DefaultCredentialsError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700173 "The file {file} does not have a valid type. "
174 "Type is {type}, expected one of {valid_types}.".format(
175 file=filename, type=credential_type, valid_types=_VALID_TYPES
176 )
177 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700178
179
arithmetic172811ebaeb2021-09-07 14:38:49 -0700180def _get_gcloud_sdk_credentials(quota_project_id=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700181 """Gets the credentials and project ID from the Cloud SDK."""
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800182 from google.auth import _cloud_sdk
183
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400184 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...")
185
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700186 # Check if application default credentials exist.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700187 credentials_filename = _cloud_sdk.get_application_default_credentials_path()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700188
189 if not os.path.isfile(credentials_filename):
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400190 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700191 return None, None
192
arithmetic172811ebaeb2021-09-07 14:38:49 -0700193 credentials, project_id = load_credentials_from_file(
194 credentials_filename, quota_project_id=quota_project_id
195 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700196
197 if not project_id:
198 project_id = _cloud_sdk.get_project_id()
199
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700200 return credentials, project_id
201
202
arithmetic172811ebaeb2021-09-07 14:38:49 -0700203def _get_explicit_environ_credentials(quota_project_id=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700204 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
Bu Sun Kim9dc2d862021-02-11 12:53:26 -0700205 variable."""
arithmetic1728333cb762021-02-25 15:42:32 -0800206 from google.auth import _cloud_sdk
207
208 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700209 explicit_file = os.environ.get(environment_vars.CREDENTIALS)
210
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400211 _LOGGER.debug(
212 "Checking %s for explicit credentials as part of auth process...", explicit_file
213 )
214
arithmetic1728333cb762021-02-25 15:42:32 -0800215 if explicit_file is not None and explicit_file == cloud_sdk_adc_path:
216 # Cloud sdk flow calls gcloud to fetch project id, so if the explicit
217 # file path is cloud sdk credentials path, then we should fall back
218 # to cloud sdk flow, otherwise project id cannot be obtained.
219 _LOGGER.debug(
220 "Explicit credentials path %s is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...",
221 explicit_file,
222 )
arithmetic172811ebaeb2021-09-07 14:38:49 -0700223 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id)
arithmetic1728333cb762021-02-25 15:42:32 -0800224
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700225 if explicit_file is not None:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700226 credentials, project_id = load_credentials_from_file(
arithmetic172811ebaeb2021-09-07 14:38:49 -0700227 os.environ[environment_vars.CREDENTIALS], quota_project_id=quota_project_id
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700228 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700229
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700230 return credentials, project_id
231
232 else:
233 return None, None
234
235
236def _get_gae_credentials():
237 """Gets Google App Engine App Identity credentials and project ID."""
Zev Goldstein7f7d92d2021-07-23 15:52:46 -0400238 # If not GAE gen1, prefer the metadata service even if the GAE APIs are
239 # available as per https://google.aip.dev/auth/4115.
240 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27":
241 return None, None
242
James Wilson6e0781b2018-12-20 20:38:52 -0500243 # While this library is normally bundled with app_engine, there are
244 # some cases where it's not available, so we tolerate ImportError.
245 try:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400246 _LOGGER.debug("Checking for App Engine runtime as part of auth process...")
James Wilson6e0781b2018-12-20 20:38:52 -0500247 import google.auth.app_engine as app_engine
248 except ImportError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400249 _LOGGER.warning("Import of App Engine auth library failed.")
James Wilson6e0781b2018-12-20 20:38:52 -0500250 return None, None
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800251
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700252 try:
253 credentials = app_engine.Credentials()
254 project_id = app_engine.get_project_id()
255 return credentials, project_id
256 except EnvironmentError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400257 _LOGGER.debug(
258 "No App Engine library was found so cannot authentication via App Engine Identity Credentials."
259 )
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700260 return None, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700261
262
263def _get_gce_credentials(request=None):
264 """Gets credentials and project ID from the GCE Metadata Service."""
265 # Ping requires a transport, but we want application default credentials
266 # to require no arguments. So, we'll use the _http_client transport which
267 # uses http.client. This is only acceptable because the metadata server
268 # doesn't do SSL and never requires proxies.
James Wilson6e0781b2018-12-20 20:38:52 -0500269
270 # While this library is normally bundled with compute_engine, there are
271 # some cases where it's not available, so we tolerate ImportError.
272 try:
273 from google.auth import compute_engine
274 from google.auth.compute_engine import _metadata
275 except ImportError:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400276 _LOGGER.warning("Import of Compute Engine auth library failed.")
James Wilson6e0781b2018-12-20 20:38:52 -0500277 return None, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700278
279 if request is None:
280 request = google.auth.transport._http_client.Request()
281
282 if _metadata.ping(request=request):
283 # Get the project ID.
284 try:
Jon Wayne Parrott5b03ba12016-10-24 13:51:26 -0700285 project_id = _metadata.get_project_id(request=request)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700286 except exceptions.TransportError:
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700287 project_id = None
288
289 return compute_engine.Credentials(), project_id
290 else:
Vaughan Hiltsecd88d42020-07-21 16:25:51 -0400291 _LOGGER.warning(
292 "Authentication failed using Compute Engine authentication due to unavailable metadata server."
293 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700294 return None, None
295
296
bojeil-googled4d7f382021-02-16 12:33:20 -0800297def _get_external_account_credentials(
298 info, filename, scopes=None, default_scopes=None, request=None
299):
300 """Loads external account Credentials from the parsed external account info.
301
302 The credentials information must correspond to a supported external account
303 credentials.
304
305 Args:
306 info (Mapping[str, str]): The external account info in Google format.
307 filename (str): The full path to the credentials file.
308 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
309 specified, the credentials will automatically be scoped if
310 necessary.
311 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
312 Google client library. Use 'scopes' for user-defined scopes.
313 request (Optional[google.auth.transport.Request]): An object used to make
314 HTTP requests. This is used to determine the associated project ID
315 for a workload identity pool resource (external account credentials).
316 If not specified, then it will use a
317 google.auth.transport.requests.Request client to make requests.
318
319 Returns:
320 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
321 credentials and the project ID. External account credentials project
322 IDs may not always be determined.
323
324 Raises:
325 google.auth.exceptions.DefaultCredentialsError: if the info dictionary
326 is in the wrong format or is missing required information.
327 """
328 # There are currently 2 types of external_account credentials.
bojeil-google10bd9fb2021-09-30 23:19:51 -0700329 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
bojeil-googled4d7f382021-02-16 12:33:20 -0800330 # Check if configuration corresponds to an AWS credentials.
331 from google.auth import aws
332
333 credentials = aws.Credentials.from_info(
334 info, scopes=scopes, default_scopes=default_scopes
335 )
bojeil-google10bd9fb2021-09-30 23:19:51 -0700336 else:
bojeil-googled4d7f382021-02-16 12:33:20 -0800337 try:
338 # Check if configuration corresponds to an Identity Pool credentials.
339 from google.auth import identity_pool
340
341 credentials = identity_pool.Credentials.from_info(
342 info, scopes=scopes, default_scopes=default_scopes
343 )
344 except ValueError:
345 # If the configuration is invalid or does not correspond to any
346 # supported external_account credentials, raise an error.
347 raise exceptions.DefaultCredentialsError(
348 "Failed to load external account credentials from {}".format(filename)
349 )
350 if request is None:
351 request = google.auth.transport.requests.Request()
352
353 return credentials, credentials.get_project_id(request=request)
354
355
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700356def default(scopes=None, request=None, quota_project_id=None, default_scopes=None):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700357 """Gets the default credentials for the current environment.
358
359 `Application Default Credentials`_ provides an easy way to obtain
360 credentials to call Google APIs for server-to-server or local applications.
361 This function acquires credentials from the environment in the following
362 order:
363
364 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
365 to the path of a valid service account JSON private key file, then it is
366 loaded and returned. The project ID returned is the project ID defined
367 in the service account file if available (some older files do not
368 contain project ID information).
bojeil-googled4d7f382021-02-16 12:33:20 -0800369
370 If the environment variable is set to the path of a valid external
371 account JSON configuration file (workload identity federation), then the
372 configuration file is used to determine and retrieve the external
373 credentials from the current environment (AWS, Azure, etc).
374 These will then be exchanged for Google access tokens via the Google STS
375 endpoint.
376 The project ID returned in this case is the one corresponding to the
377 underlying workload identity pool resource if determinable.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700378 2. If the `Google Cloud SDK`_ is installed and has application default
379 credentials set they are loaded and returned.
380
381 To enable application default credentials with the Cloud SDK run::
382
383 gcloud auth application-default login
384
385 If the Cloud SDK has an active project, the project ID is returned. The
386 active project can be set using::
387
388 gcloud config set project
389
390 3. If the application is running in the `App Engine standard environment`_
David Buxton0323cf32020-10-29 21:26:11 +0000391 (first generation) then the credentials and project ID from the
392 `App Identity Service`_ are used.
393 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
394 the `App Engine flexible environment`_ or the `App Engine standard
395 environment`_ (second generation) then the credentials and project ID
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700396 are obtained from the `Metadata Service`_.
397 5. If no credentials are found,
398 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
399
400 .. _Application Default Credentials: https://developers.google.com\
401 /identity/protocols/application-default-credentials
402 .. _Google Cloud SDK: https://cloud.google.com/sdk
403 .. _App Engine standard environment: https://cloud.google.com/appengine
404 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\
405 /appidentity/
406 .. _Compute Engine: https://cloud.google.com/compute
407 .. _App Engine flexible environment: https://cloud.google.com\
408 /appengine/flexible
409 .. _Metadata Service: https://cloud.google.com/compute/docs\
410 /storing-retrieving-metadata
David Buxton0323cf32020-10-29 21:26:11 +0000411 .. _Cloud Run: https://cloud.google.com/run
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700412
413 Example::
414
415 import google.auth
416
417 credentials, project_id = google.auth.default()
418
419 Args:
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800420 scopes (Sequence[str]): The list of scopes for the credentials. If
421 specified, the credentials will automatically be scoped if
422 necessary.
bojeil-googled4d7f382021-02-16 12:33:20 -0800423 request (Optional[google.auth.transport.Request]): An object used to make
424 HTTP requests. This is used to either detect whether the application
425 is running on Compute Engine or to determine the associated project
426 ID for a workload identity pool resource (external account
427 credentials). If not specified, then it will either use the standard
428 library http client to make requests for Compute Engine credentials
429 or a google.auth.transport.requests.Request client for external
430 account credentials.
431 quota_project_id (Optional[str]): The project ID used for
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700432 quota and billing.
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700433 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
434 Google client library. Use 'scopes' for user-defined scopes.
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700435 Returns:
436 Tuple[~google.auth.credentials.Credentials, Optional[str]]:
437 the current environment's credentials and project ID. Project ID
438 may be None, which indicates that the Project ID could not be
439 ascertained from the environment.
440
441 Raises:
442 ~google.auth.exceptions.DefaultCredentialsError:
443 If no credentials were found, or if the credentials found were
444 invalid.
445 """
Jon Wayne Parrott6dca98c2016-12-01 15:34:59 -0800446 from google.auth.credentials import with_scopes_if_required
447
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800448 explicit_project_id = os.environ.get(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700449 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
450 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700451
452 checkers = (
bojeil-googled4d7f382021-02-16 12:33:20 -0800453 # Avoid passing scopes here to prevent passing scopes to user credentials.
454 # with_scopes_if_required() below will ensure scopes/default scopes are
455 # safely set on the returned credentials since requires_scopes will
456 # guard against setting scopes on user credentials.
arithmetic172811ebaeb2021-09-07 14:38:49 -0700457 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id),
458 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id),
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700459 _get_gae_credentials,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700460 lambda: _get_gce_credentials(request),
461 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700462
463 for checker in checkers:
464 credentials, project_id = checker()
465 if credentials is not None:
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700466 credentials = with_scopes_if_required(
467 credentials, scopes, default_scopes=default_scopes
468 )
bojeil-googled4d7f382021-02-16 12:33:20 -0800469
470 # For external account credentials, scopes are required to determine
471 # the project ID. Try to get the project ID again if not yet
472 # determined.
473 if not project_id and callable(
474 getattr(credentials, "get_project_id", None)
475 ):
476 if request is None:
477 request = google.auth.transport.requests.Request()
478 project_id = credentials.get_project_id(request=request)
479
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700480 if quota_project_id:
481 credentials = credentials.with_quota_project(quota_project_id)
482
Jacob Hayes15af07b2017-12-13 14:09:47 -0600483 effective_project_id = explicit_project_id or project_id
484 if not effective_project_id:
485 _LOGGER.warning(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700486 "No project ID could be determined. Consider running "
487 "`gcloud config set project` or setting the %s "
488 "environment variable",
489 environment_vars.PROJECT,
490 )
Jacob Hayes15af07b2017-12-13 14:09:47 -0600491 return credentials, effective_project_id
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700492
493 raise exceptions.DefaultCredentialsError(_HELP_MESSAGE)