From 26f5c11de3a25a0df15c041b29ba25e213b8d71f Mon Sep 17 00:00:00 2001 From: Jin Date: Mon, 15 Aug 2022 13:32:32 -0700 Subject: [PATCH 1/4] doc: workforce identity federation for pluggable auth (#1104) * docs: workforce identity federation for pluggable auth * fix indent * chore: Refresh system test creds * fix the subtitles not outlined --- docs/user-guide.rst | 245 +++++++++++++++++++++++++++++++++++ system_tests/secrets.tar.enc | Bin 10323 -> 10324 bytes 2 files changed, 245 insertions(+) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 16de58d9d..e689b11c6 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -544,6 +544,251 @@ For AWS providers, use :meth:`aws.Credentials.from_info ['https://www.googleapis.com/auth/cloud-platform']) +External credentials (Workforce identity federation) +++++++++++++++++++++++++++++++++++++++++++++++++++++ + +`Workforce identity federation`_ lets you use an external identify provider +(IdP) to authenticate and authorize a workforce—a group of users, such as +employees, partners, and contractors—using IAM, so that the users can access +Google Cloud services. Workforce identity federation extends Google Cloud's +identity capabilities to support syncless, attribute-based single sign on. + +With workforce identity federation, your workforce can access Google Cloud +resources using an external identity provider (IdP) that supports OpenID +Connect (OIDC) or SAML 2.0 such as Azure Active Directory (Azure AD), Active +Directory Federation Services (AD FS), Okta, and others. + + +Accessing resources using an OIDC or SAML 2.0 identity provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to access Google Cloud resources from an identity provider that +supports `OpenID Connect (OIDC)`_, the following requirements are needed: + +- A workforce identity pool needs to be created. +- An OIDC or SAML 2.0 identity provider needs to be added in the workforce pool. + +Follow the detailed `instructions`_ on how to configure workforce identity +federation. + +After configuring an OIDC or SAML 2.0 provider, a credential configuration file +needs to be generated. The generated credential configuration file contains +non-sensitive metadata to instruct the library on how to retrieve external +subject tokens and exchange them for GCP access tokens. The configuration file +can be generated by using the `gcloud CLI`_. + +The Auth library can retrieve external subject tokens from a local file +location (file-sourced credentials), from a local server (URL-sourced +credentials) or by calling an executable (executable-sourced credentials). + +File-sourced credentials +++++++++++++++++++++++++ + +For file-sourced credentials, a background process needs to be continuously +refreshing the file location with a new subject token prior to expiration. For +tokens with one hour lifetimes, the token needs to be updated in the file every +hour. The token can be stored directly as plain text or in JSON format. + +To generate a file-sourced OIDC configuration, run the following command: + +.. code-block:: bash + + # Generate an OIDC configuration file for file-sourced credentials. + gcloud iam workforce-pools create-cred-config \ + locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID \ + --subject-token-type=urn:ietf:params:oauth:token-type:id_token \ + --credential-source-file=$PATH_TO_OIDC_ID_TOKEN \ + --workforce-pool-user-project=$WORKFORCE_POOL_USER_PROJECT \ + # Optional arguments for file types. Default is "text": + # --credential-source-type "json" \ + # Optional argument for the field that contains the OIDC credential. + # This is required for json. + # --credential-source-field-name "id_token" \ + --output-file=/path/to/generated/config.json + +Where the following variables need to be substituted: + +* ``$WORKFORCE_POOL_ID``: The workforce pool ID. +* ``$PROVIDER_ID``: The provider ID. +* ``$PATH_TO_OIDC_ID_TOKEN``: The file path used to retrieve the OIDC token. +* ``$WORKFORCE_POOL_USER_PROJECT``: The project number associated with the + `workforce pools user project`_. + +To generate a file-sourced SAML configuration, run the following command: + +.. code-block:: bash + + # Generate a SAML configuration file for file-sourced credentials. + gcloud iam workforce-pools create-cred-config \ + locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID \ + --credential-source-file=$PATH_TO_SAML_ASSERTION \ + --subject-token-type=urn:ietf:params:oauth:token-type:saml2 \ + --workforce-pool-user-project=$WORKFORCE_POOL_USER_PROJECT \ + --output-file=/path/to/generated/config.json + +Where the following variables need to be substituted: + +* ``$WORKFORCE_POOL_ID``: The workforce pool ID. +* ``$PROVIDER_ID``: The provider ID. +* ``$PATH_TO_SAML_ASSERTION``: The file path used to retrieve the + base64-encoded SAML assertion. +* ``$WORKFORCE_POOL_USER_PROJECT``: The project number associated with the + `workforce pools user project`_. + +These commands generate the configuration file in the specified output file. + +URL-sourced credentials ++++++++++++++++++++++++ + +For URL-sourced credentials, a local server needs to host a GET endpoint to +return the OIDC token. The response can be in plain text or JSON. Additional +required request headers can also be specified. + +To generate a URL-sourced OIDC workforce identity configuration, run the +following command: + +.. code-block:: bash + + # Generate an OIDC configuration file for URL-sourced credentials. + gcloud iam workforce-pools create-cred-config \ + locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID \ + --subject-token-type=urn:ietf:params:oauth:token-type:id_token \ + --credential-source-url=$URL_TO_RETURN_OIDC_ID_TOKEN \ + --credential-source-headers $HEADER_KEY=$HEADER_VALUE \ + --workforce-pool-user-project=$WORKFORCE_POOL_USER_PROJECT \ + --output-file=/path/to/generated/config.json + +Where the following variables need to be substituted: + +* ``$WORKFORCE_POOL_ID``: The workforce pool ID. +* ``$PROVIDER_ID``: The provider ID. +* ``$URL_TO_RETURN_OIDC_ID_TOKEN``: The URL of the local server endpoint. +* ``$HEADER_KEY`` and ``$HEADER_VALUE``: The additional header key/value + pairs to pass along the GET request to ``$URL_TO_GET_OIDC_TOKEN``, e.g. + ``Metadata-Flavor=Google``. +* ``$WORKFORCE_POOL_USER_PROJECT``: The project number associated with the + `workforce pools user project`_. + +To generate a URL-sourced SAML configuration, run the following command: + +.. code-block:: bash + + # Generate a SAML configuration file for file-sourced credentials. + gcloud iam workforce-pools create-cred-config \ + locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID \ + --subject-token-type=urn:ietf:params:oauth:token-type:saml2 \ + --credential-source-url=$URL_TO_GET_SAML_ASSERTION \ + --credential-source-headers $HEADER_KEY=$HEADER_VALUE \ + --workforce-pool-user-project=$WORKFORCE_POOL_USER_PROJECT \ + --output-file=/path/to/generated/config.json + +These commands generate the configuration file in the specified output file. + +Where the following variables need to be substituted: + +* ``$WORKFORCE_POOL_ID``: The workforce pool ID. +* ``$PROVIDER_ID``: The provider ID. +* ``$URL_TO_GET_SAML_ASSERTION``: The URL of the local server endpoint. +* ``$HEADER_KEY`` and ``$HEADER_VALUE``: The additional header key/value + pairs to pass along the GET request to ``$URL_TO_GET_SAML_ASSERTION``, e.g. + ``Metadata-Flavor=Google``. +* ``$WORKFORCE_POOL_USER_PROJECT``: The project number associated with the + `workforce pools user project`_. + +Using Executable-sourced workforce credentials with OIDC and SAML +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Executable-sourced credentials** For executable-sourced credentials, a local +executable is used to retrieve the 3rd party token. The executable must handle +providing a valid, unexpired OIDC ID token or SAML assertion in JSON format to +stdout. + +To use executable-sourced credentials, the +``GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES`` environment variable must be set +to ``1``. + +To generate an executable-sourced workforce identity configuration, run the +following command: + +.. code-block:: bash + + # Generate a configuration file for executable-sourced credentials. + gcloud iam workforce-pools create-cred-config \ + locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID \ + --subject-token-type=$SUBJECT_TOKEN_TYPE \ + # The absolute path for the program, including arguments. + # e.g. --executable-command="/path/to/command --foo=bar" + --executable-command=$EXECUTABLE_COMMAND \ + # Optional argument for the executable timeout. Defaults to 30s. + # --executable-timeout-millis=$EXECUTABLE_TIMEOUT \ + # Optional argument for the absolute path to the executable output file. + # See below on how this argument impacts the library behaviour. + # --executable-output-file=$EXECUTABLE_OUTPUT_FILE \ + --workforce-pool-user-project=$WORKFORCE_POOL_USER_PROJECT \ + --output-file /path/to/generated/config.json + +Where the following variables need to be substituted: + +* ``$WORKFORCE_POOL_ID``: The workforce pool ID. +* ``$PROVIDER_ID``: The provider ID. +* ``$SUBJECT_TOKEN_TYPE``: The subject token type. +* ``$EXECUTABLE_COMMAND``: The full command to run, including arguments. Must be + an absolute path to the program. +* ``$WORKFORCE_POOL_USER_PROJECT``: The project number associated with the + workforce pools user project. + +The ``--executable-timeout-millis`` flag is optional. This is the duration for +which the auth library will wait for the executable to finish, in milliseconds. +Defaults to 30 seconds when not provided. The maximum allowed value is 2 +minutes. The minimum is 5 seconds. + +The ``--executable-output-file`` flag is optional. If provided, the file path +must point to the 3rd party credential response generated by the executable. +This is useful for caching the credentials. By specifying this path, the Auth +libraries will first check for its existence before running the executable. By +caching the executable JSON response to this file, it improves performance as it +avoids the need to run the executable until the cached credentials in the output +file are expired. The executable must handle writing to this file - the auth +libraries will only attempt to read from this location. The format of contents +in the file should match the JSON format expected by the executable shown below. + +To retrieve the 3rd party token, the library will call the executable using the +command specified. The executable's output must adhere to the response format +specified below. It must output the response to stdout. + +Refer to the `using executable-sourced credentials with Workload Identity +Federation `__ above +for the executable response specification. + +Security considerations +~~~~~~~~~~~~~~~~~~~~~~~ + +The following security practices are highly recommended: + +* Access to the script should be restricted as it will be displaying credentials + to stdout. This ensures that rogue processes do not gain access to the script. +* The configuration file should not be modifiable. Write access should be + restricted to avoid processes modifying the executable command portion. + +Given the complexity of using executable-sourced credentials, it is recommended +to use the existing supported mechanisms (file-sourced/URL-sourced) for +providing 3rd party credentials unless they do not meet your specific +requirements. + +You can now `use the Auth library <#using-external-identities>`__ to call Google +Cloud resources from an OIDC or SAML provider. + + +.. _Workforce Identity Federation: + https://cloud.google.com/iam/docs/workforce-identity-federation +.. _OpenID Connect (OIDC): https://openid.net/connect/ +.. _instructions: + https://cloud.google.com/iam/docs/configuring-workforce-identity-federation +.. _gcloud CLI: https://cloud.google.com/sdk/ +.. _workforce pools user project: + https://cloud.google.com/iam/docs/workforce-identity-federation#workforce-pools-user-project + + Impersonated credentials ++++++++++++++++++++++++ diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index f5652a5a43307c097d5572a2a6fe506ef322c1c8..77f7e7a2db30dce540e9457b8fe26019d13c781c 100644 GIT binary patch literal 10324 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 lJh>B>L8vNy;PZbrz=mwr#8V Date: Thu, 18 Aug 2022 23:02:14 +0300 Subject: [PATCH 2/4] Fix: Async certificate retrieving (#1101) * fix: Handle certificate retrieving in a more proper way --- google/oauth2/_id_token_async.py | 4 ++-- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes tests_async/oauth2/test_id_token.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google/oauth2/_id_token_async.py b/google/oauth2/_id_token_async.py index b90994cdc..c32dfa47d 100644 --- a/google/oauth2/_id_token_async.py +++ b/google/oauth2/_id_token_async.py @@ -93,9 +93,9 @@ async def _fetch_certs(request, certs_url): "Could not fetch certificates at {}".format(certs_url) ) - data = await response.data.read() + data = await response.content() - return json.loads(data.decode("utf-8")) + return json.loads(data) async def verify_token( diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 77f7e7a2db30dce540e9457b8fe26019d13c781c..ec376950bd458b8105dc47c111bcd1adcb90b406 100644 GIT binary patch literal 10324 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 literal 10324 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 Date: Thu, 18 Aug 2022 18:00:47 -0400 Subject: [PATCH 3/4] feat: add integration tests for configurable token lifespan (#1103) * feat: add integration tests for configurable token lifespan * Reducing buffer to 5 seconds --- .../test_external_accounts.py | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/system_tests/system_tests_sync/test_external_accounts.py b/system_tests/system_tests_sync/test_external_accounts.py index 59fbd4bef..29355f479 100644 --- a/system_tests/system_tests_sync/test_external_accounts.py +++ b/system_tests/system_tests_sync/test_external_accounts.py @@ -42,6 +42,7 @@ import sys import google.auth +from google.auth import _helpers from googleapiclient import discovery from six.moves import BaseHTTPServer from google.oauth2 import service_account @@ -132,7 +133,6 @@ def get_project_dns(dns_access, credential_data): with NamedTemporaryFile() as credfile: credfile.write(json.dumps(credential_data).encode("utf-8")) credfile.flush() - old_credentials = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS") with patch.dict(os.environ, {"GOOGLE_APPLICATION_CREDENTIALS": credfile.name}): # If our setup and credential file are correct, @@ -150,9 +150,7 @@ def get_xml_value_by_tagname(data, tagname): # This test makes sure that setting an accesible credential file # works to allow access to Google resources. -def test_file_based_external_account( - oidc_credentials, service_account_info, dns_access -): +def test_file_based_external_account(oidc_credentials, dns_access): with NamedTemporaryFile() as tmpfile: tmpfile.write(oidc_credentials.token.encode("utf-8")) tmpfile.flush() @@ -173,10 +171,11 @@ def test_file_based_external_account( }, ) + # This test makes sure that setting a token lifetime works # for service account impersonation. def test_file_based_external_account_with_configure_token_lifetime( - oidc_credentials, service_account_info, dns_access + oidc_credentials, dns_access ): with NamedTemporaryFile() as tmpfile: tmpfile.write(oidc_credentials.token.encode("utf-8")) @@ -202,6 +201,47 @@ def test_file_based_external_account_with_configure_token_lifetime( ) +def test_configurable_token_lifespan(oidc_credentials, http_request): + TOKEN_LIFETIME_SECONDS = 2800 + BUFFER_SECONDS = 5 + + def check_impersonation_expiration(): + # First, get the default credentials. + credentials, _ = google.auth.default( + scopes=["https://www.googleapis.com/auth/cloud-platform.read-only"], + request=http_request, + ) + + utcmax = _helpers.utcnow() + datetime.timedelta(seconds=TOKEN_LIFETIME_SECONDS) + utcmin = utcmax - datetime.timedelta(seconds=BUFFER_SECONDS) + assert utcmin < credentials._impersonated_credentials.expiry <= utcmax + + return True + + with NamedTemporaryFile() as tmpfile: + tmpfile.write(oidc_credentials.token.encode("utf-8")) + tmpfile.flush() + + assert get_project_dns( + check_impersonation_expiration, + { + "type": "external_account", + "audience": _AUDIENCE_OIDC, + "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", + "token_url": "https://sts.googleapis.com/v1/token", + "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{}:generateAccessToken".format( + oidc_credentials.service_account_email + ), + "service_account_impersonation": { + "token_lifetime_seconds": TOKEN_LIFETIME_SECONDS, + }, + "credential_source": { + "file": tmpfile.name, + }, + }, + ) + + # This test makes sure that setting up an http server to provide credentials # works to allow access to Google resources. def test_url_based_external_account(dns_access, oidc_credentials, service_account_info): @@ -337,9 +377,7 @@ def test_aws_based_external_account( # This test makes sure that setting up an executable to provide credentials # works to allow access to Google resources. -def test_pluggable_external_account( - oidc_credentials, service_account_info, dns_access -): +def test_pluggable_external_account(oidc_credentials, service_account_info, dns_access): now = datetime.datetime.now() unix_seconds = time.mktime(now.timetuple()) expiration_time = (unix_seconds + 1 * 60 * 60) * 1000 @@ -354,7 +392,7 @@ def test_pluggable_external_account( tmpfile = NamedTemporaryFile(delete=True) with open(tmpfile.name, "w") as f: f.write("#!/bin/bash\n") - f.write("echo \"{}\"\n".format(json.dumps(credential).replace('"', '\\"'))) + f.write('echo "{}"\n'.format(json.dumps(credential).replace('"', '\\"'))) tmpfile.file.close() os.chmod(tmpfile.name, 0o777) From 3fd4b0ddb72a1ede2e3bf4e6da928db95f23caa6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 19 Aug 2022 16:25:38 -0700 Subject: [PATCH 4/4] chore(main): release 2.11.0 (#1106) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 12 ++++++++++++ google/auth/version.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e08322a6a..7b1d296cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ [1]: https://pypi.org/project/google-auth/#history +## [2.11.0](https://github.com/googleapis/google-auth-library-python/compare/v2.10.0...v2.11.0) (2022-08-18) + + +### Features + +* add integration tests for configurable token lifespan ([#1103](https://github.com/googleapis/google-auth-library-python/issues/1103)) ([124bae6](https://github.com/googleapis/google-auth-library-python/commit/124bae60771a8984674a1d7eeab3ec22b2fa0033)) + + +### Bug Fixes + +* Async certificate retrieving ([#1101](https://github.com/googleapis/google-auth-library-python/issues/1101)) ([05f125d](https://github.com/googleapis/google-auth-library-python/commit/05f125def1205a14db52c870f2bfcef47f047206)) + ## [2.10.0](https://github.com/googleapis/google-auth-library-python/compare/v2.9.1...v2.10.0) (2022-08-05) diff --git a/google/auth/version.py b/google/auth/version.py index bcf2a36f4..10a1c7fd9 100644 --- a/google/auth/version.py +++ b/google/auth/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.10.0" +__version__ = "2.11.0"