From aa3182ebc55e01dbaddf191374e201e4c65a2464 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 16 Apr 2025 10:35:04 -0400 Subject: [PATCH] feat(gcp): support CLOUDSDK_AUTH_ACCESS_TOKEN (#7495) --- docs/tutorials/gcp/authentication.md | 44 +++++++++++++++++++++++- prowler/CHANGELOG.md | 1 + prowler/providers/gcp/gcp_provider.py | 11 ++++-- tests/providers/gcp/gcp_provider_test.py | 20 +++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/gcp/authentication.md b/docs/tutorials/gcp/authentication.md index 95c026decf..971796a753 100644 --- a/docs/tutorials/gcp/authentication.md +++ b/docs/tutorials/gcp/authentication.md @@ -4,8 +4,13 @@ Prowler will use by default your User Account credentials, you can configure it - `gcloud init` to use a new account - `gcloud config set account ` to use an existing account +- `gcloud auth application-default login` -Then, obtain your access credentials using: `gcloud auth application-default login` +This will generate Application Default Credentials (ADC) that Prowler will use automatically. + +--- + +## Using a Service Account key file Otherwise, you can generate and download Service Account keys in JSON format (refer to https://cloud.google.com/iam/docs/creating-managing-service-account-keys) and provide the location of the file with the following argument: @@ -16,6 +21,43 @@ prowler gcp --credentials-file path ???+ note `prowler` will scan the GCP project associated with the credentials. +--- + +## Using an access token + +If you already have an access token (e.g., generated with `gcloud auth print-access-token`), you can run Prowler with: + +```bash +export CLOUDSDK_AUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) +prowler gcp --project-ids +``` + +???+ note + If using this method, it's recommended to also set the default project explicitly: + ```bash + export GOOGLE_CLOUD_PROJECT= + ``` + +--- + +## Credentials lookup order + +Prowler follows the same search order as [Google authentication libraries](https://cloud.google.com/docs/authentication/application-default-credentials#search_order): + +1. [`GOOGLE_APPLICATION_CREDENTIALS` environment variable](https://cloud.google.com/docs/authentication/application-default-credentials#GAC) +2. [`CLOUDSDK_AUTH_ACCESS_TOKEN` + optional `GOOGLE_CLOUD_PROJECT`](https://cloud.google.com/sdk/gcloud/reference/auth/print-access-token) +3. [User credentials set up by using the Google Cloud CLI](https://cloud.google.com/docs/authentication/application-default-credentials#personal) +4. [Attached service account (e.g., Cloud Run, GCE, Cloud Functions)](https://cloud.google.com/docs/authentication/application-default-credentials#attached-sa) + +???+ note + The credentials must belong to a user or service account with the necessary permissions. + To ensure full access, assign the roles/viewer IAM role to the identity being used. + +???+ note + Prowler will use the enabled Google Cloud APIs to get the information needed to perform the checks. + +--- + ## Needed permissions diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 7964df1eec..a3edc2e94a 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489). - Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419). +- Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495). - Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331) ### Fixed diff --git a/prowler/providers/gcp/gcp_provider.py b/prowler/providers/gcp/gcp_provider.py index 4ba25277d3..789c434bb4 100644 --- a/prowler/providers/gcp/gcp_provider.py +++ b/prowler/providers/gcp/gcp_provider.py @@ -396,14 +396,19 @@ class GcpProvider(Provider): client_secrets_path = os.path.abspath(credentials_file) os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = client_secrets_path + access_token = os.getenv("CLOUDSDK_AUTH_ACCESS_TOKEN") + if access_token: + logger.info("Using access token from CLOUDSDK_AUTH_ACCESS_TOKEN") + credentials = Credentials(token=access_token, scopes=scopes) + default_project_id = os.getenv("GOOGLE_CLOUD_PROJECT", "") + return credentials, default_project_id + # Get default credentials credentials, default_project_id = default(scopes=scopes) # Refresh the credentials to ensure they are valid credentials.refresh(Request()) - logger.info(f"Initial credentials: {credentials}") - if service_account: # Create the impersonated credentials credentials = impersonated_credentials.Credentials( @@ -411,7 +416,7 @@ class GcpProvider(Provider): target_principal=service_account, target_scopes=scopes, ) - logger.info(f"Impersonated credentials: {credentials}") + logger.info(f"Impersonating service account: {service_account}") return credentials, default_project_id except Exception as error: diff --git a/tests/providers/gcp/gcp_provider_test.py b/tests/providers/gcp/gcp_provider_test.py index e3c7644f17..8a10350d7d 100644 --- a/tests/providers/gcp/gcp_provider_test.py +++ b/tests/providers/gcp/gcp_provider_test.py @@ -323,6 +323,26 @@ class TestGCPProvider: == "test-impersonate-service-account" ) + def test_setup_session_with_access_token(self, monkeypatch): + from google.oauth2.credentials import Credentials as TokenCredentials + + access_token = "fake-access-token" + default_project_id = "test-access-token-project" + + monkeypatch.setenv("CLOUDSDK_AUTH_ACCESS_TOKEN", access_token) + monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", default_project_id) + + session, project_id = GcpProvider.setup_session( + credentials_file=None, + service_account=None, + gcp_credentials=None, + service_account_key=None, + ) + + assert isinstance(session, TokenCredentials) + assert session.token == access_token + assert project_id == default_project_id + def test_setup_session_with_organization_id(self): mocked_credentials = MagicMock()