Skip to content

Commit 4c8a5f9

Browse files
chuanrgcf-owl-bot[bot]arithmetic1728lsirac
authored
feat: pluggable auth support (#1045)
* feat: Add Pluggable auth support See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md feat: Add Pluggable auth support (#988) * Port identity pool credentials * access_token retrieved * -> pluggable * Update pluggable.py * Create test_pluggable.py * Unit tests * Address pr issues feat: Add file caching (#990) * Add file cache * feat: add output file cache support 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update pluggable.py 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update pluggable.py Update setup.py 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update setup.py Update setup.py pytest_subprocess timeout Update pluggable.py env 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update _default.py 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update requirements.txt Update _default.py Update pluggable.py Update pluggable.py Update pluggable.py Update test_pluggable.py format validations Update _default.py Update requirements.txt 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Revert "Update requirements.txt" This reverts commit 1c9b6db25c683663ed4b71ab0ab39946fce8f6eb. Revert "Update _default.py" This reverts commit ac6c36072084a440c234a9465b35462bd52378b3. Revert "Revert "Update _default.py"" This reverts commit 1c08483586007e4caf1a36f2c9cbf2a45d403ee0. Raise output format error but retry parsing token if `success` is 0 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Update requirements.txt Delete test_pluggable.py Revert "Delete test_pluggable.py" This reverts commit 74beba9405564a5b764af8718c49e640d9b84c5f. Update pluggable.py Update pluggable.py pytest-subprocess 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md lint Update pluggable.py nox cover nox cover 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md lint Update test_pluggable.py Update test_pluggable.py * Disable Pluggable Auth for Python 2.* Update noxfile.py * Update pluggable.py * Update pluggable.py * Update pluggable.py * Update pluggable.py * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Address PR issues * Update pluggable.py * Update pluggable.py * Update user-guide.rst * Update user-guide.rst * Update user-guide.rst * Update user-guide.rst * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com> Co-authored-by: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com>
1 parent b06952d commit 4c8a5f9

File tree

6 files changed

+1256
-3
lines changed

6 files changed

+1256
-3
lines changed

packages/google-auth/docs/user-guide.rst

Lines changed: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,155 @@ Follow the detailed instructions on how to
329329
.. _Configure Workload Identity Federation from an OIDC identity provider:
330330
https://cloud.google.com/iam/docs/access-resources-oidc
331331

332+
Using Executable-sourced credentials with OIDC and SAML
333+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334+
335+
**Executable-sourced credentials** For executable-sourced credentials, a
336+
local executable is used to retrieve the 3rd party token. The executable
337+
must handle providing a valid, unexpired OIDC ID token or SAML assertion
338+
in JSON format to stdout.
339+
340+
To use executable-sourced credentials, the
341+
``GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES`` environment variable must
342+
be set to ``1``.
343+
344+
To generate an executable-sourced workload identity configuration, run
345+
the following command:
346+
347+
.. code:: bash
348+
349+
# Generate a configuration file for executable-sourced credentials.
350+
gcloud iam workload-identity-pools create-cred-config \
351+
projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID \
352+
--service-account=$SERVICE_ACCOUNT_EMAIL \
353+
--subject-token-type=$SUBJECT_TOKEN_TYPE \
354+
# The absolute path for the program, including arguments.
355+
# e.g. --executable-command="/path/to/command --foo=bar"
356+
--executable-command=$EXECUTABLE_COMMAND \
357+
# Optional argument for the executable timeout. Defaults to 30s.
358+
# --executable-timeout-millis=$EXECUTABLE_TIMEOUT \
359+
# Optional argument for the absolute path to the executable output file.
360+
# See below on how this argument impacts the library behaviour.
361+
# --executable-output-file=$EXECUTABLE_OUTPUT_FILE \
362+
--output-file /path/to/generated/config.json
363+
364+
Where the following variables need to be substituted: -
365+
``$PROJECT_NUMBER``: The Google Cloud project number. - ``$POOL_ID``:
366+
The workload identity pool ID. - ``$PROVIDER_ID``: The OIDC or SAML
367+
provider ID. - ``$SERVICE_ACCOUNT_EMAIL``: The email of the service
368+
account to impersonate. - ``$SUBJECT_TOKEN_TYPE``: The subject token
369+
type. - ``$EXECUTABLE_COMMAND``: The full command to run, including
370+
arguments. Must be an absolute path to the program.
371+
372+
The ``--executable-timeout-millis`` flag is optional. This is the
373+
duration for which the auth library will wait for the executable to
374+
finish, in milliseconds. Defaults to 30 seconds when not provided. The
375+
maximum allowed value is 2 minutes. The minimum is 5 seconds.
376+
377+
The ``--executable-output-file`` flag is optional. If provided, the file
378+
path must point to the 3PI credential response generated by the
379+
executable. This is useful for caching the credentials. By specifying
380+
this path, the Auth libraries will first check for its existence before
381+
running the executable. By caching the executable JSON response to this
382+
file, it improves performance as it avoids the need to run the
383+
executable until the cached credentials in the output file are expired.
384+
The executable must handle writing to this file - the auth libraries
385+
will only attempt to read from this location. The format of contents in
386+
the file should match the JSON format expected by the executable shown
387+
below.
388+
389+
To retrieve the 3rd party token, the library will call the executable
390+
using the command specified. The executable’s output must adhere to the
391+
response format specified below. It must output the response to stdout.
392+
393+
A sample successful executable OIDC response:
394+
395+
.. code:: json
396+
397+
{
398+
"version": 1,
399+
"success": true,
400+
"token_type": "urn:ietf:params:oauth:token-type:id_token",
401+
"id_token": "HEADER.PAYLOAD.SIGNATURE",
402+
"expiration_time": 1620499962
403+
}
404+
405+
A sample successful executable SAML response:
406+
407+
.. code:: json
408+
409+
{
410+
"version": 1,
411+
"success": true,
412+
"token_type": "urn:ietf:params:oauth:token-type:saml2",
413+
"saml_response": "...",
414+
"expiration_time": 1620499962
415+
}
416+
417+
A sample executable error response:
418+
419+
.. code:: json
420+
421+
{
422+
"version": 1,
423+
"success": false,
424+
"code": "401",
425+
"message": "Caller not authorized."
426+
}
427+
428+
These are all required fields for an error response. The code and
429+
message fields will be used by the library as part of the thrown
430+
exception.
431+
432+
Response format fields summary: ``version``: The version of the JSON
433+
output. Currently only version 1 is supported. ``success``: The
434+
status of the response. When true, the response must contain the 3rd
435+
party token, token type, and expiration. The executable must also exit
436+
with exit code 0. When false, the response must contain the error code
437+
and message fields and exit with a non-zero value. ``token_type``:
438+
The 3rd party subject token type. Must be
439+
*urn:ietf:params:oauth:token-type:jwt*,
440+
*urn:ietf:params:oauth:token-type:id_token*, or
441+
*urn:ietf:params:oauth:token-type:saml2*. ``id_token``: The 3rd party
442+
OIDC token. ``saml_response``: The 3rd party SAML response.
443+
``expiration_time``: The 3rd party subject token expiration time in
444+
seconds (unix epoch time). ``code``: The error code string.
445+
``message``: The error message.
446+
447+
All response types must include both the ``version`` and ``success``
448+
fields. Successful responses must include the ``token_type``,
449+
``expiration_time``, and one of ``id_token`` or ``saml_response``.
450+
Error responses must include both the ``code`` and ``message`` fields.
451+
452+
The library will populate the following environment variables when the
453+
executable is run: ``GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE``: The audience
454+
field from the credential configuration. Always present.
455+
``GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL``: The service account
456+
email. Only present when service account impersonation is used.
457+
``GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE``: The output file location from
458+
the credential configuration. Only present when specified in the
459+
credential configuration.
460+
461+
These environment variables can be used by the executable to avoid
462+
hard-coding these values.
463+
464+
Security considerations
465+
466+
The following security practices are highly recommended:
467+
Access to the script should be restricted as it will be displaying
468+
credentials to stdout. This ensures that rogue processes do not gain
469+
access to the script. The configuration file should not be
470+
modifiable. Write access should be restricted to avoid processes
471+
modifying the executable command portion.
472+
473+
Given the complexity of using executable-sourced credentials, it is
474+
recommended to use the existing supported mechanisms
475+
(file-sourced/URL-sourced) for providing 3rd party credentials unless
476+
they do not meet your specific requirements.
477+
478+
You can now `use the Auth library <#using-external-identities>`__ to
479+
call Google Cloud resources from an OIDC or SAML provider.
480+
332481
Using External Identities
333482
~~~~~~~~~~~~~~~~~~~~~~~~~
334483

@@ -395,7 +544,7 @@ Impersonated credentials
395544
++++++++++++++++++++++++
396545

397546
Impersonated Credentials allows one set of credentials issued to a user or service account
398-
to impersonate another. The source credentials must be granted
547+
to impersonate another. The source credentials must be granted
399548
the "Service Account Token Creator" IAM role. ::
400549

401550
from google.auth import impersonated_credentials
@@ -417,7 +566,7 @@ the "Service Account Token Creator" IAM role. ::
417566

418567

419568
In the example above `source_credentials` does not have direct access to list buckets
420-
in the target project. Using `ImpersonatedCredentials` will allow the source_credentials
569+
in the target project. Using `ImpersonatedCredentials` will allow the source_credentials
421570
to assume the identity of a target_principal that does have access.
422571

423572

packages/google-auth/google/auth/_default.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,14 +324,23 @@ def _get_external_account_credentials(
324324
google.auth.exceptions.DefaultCredentialsError: if the info dictionary
325325
is in the wrong format or is missing required information.
326326
"""
327-
# There are currently 2 types of external_account credentials.
327+
# There are currently 3 types of external_account credentials.
328328
if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
329329
# Check if configuration corresponds to an AWS credentials.
330330
from google.auth import aws
331331

332332
credentials = aws.Credentials.from_info(
333333
info, scopes=scopes, default_scopes=default_scopes
334334
)
335+
elif (
336+
info.get("credential_source") is not None
337+
and info.get("credential_source").get("executable") is not None
338+
):
339+
from google.auth import pluggable
340+
341+
credentials = pluggable.Credentials.from_info(
342+
info, scopes=scopes, default_scopes=default_scopes
343+
)
335344
else:
336345
try:
337346
# Check if configuration corresponds to an Identity Pool credentials.

0 commit comments

Comments
 (0)