Skip to content

Authentication Reference

WebbinRoot edited this page Jul 10, 2026 · 2 revisions

Authentication Reference

If you are new to GCPwn, read Getting Started first.

This page is the canonical authentication reference for GCPwn. It covers each auth mode, setup patterns, startup syntax, and in-workspace credential operations.

Table of Contents

Auth Modes at a Glance

Auth Type Supported in GCPwn Typical Credential Source Rotation Model Common Use
ADC (adc) Yes Local Google auth defaults / ADC JSON Refresh-token backed OAuth flow Standard operator workflow with gcloud. Can result in OAuth2 tokens for next row being created, but has refresh mechanism backing.
OAuth2 bare token (oauth2 --token) Yes Direct bearer token input Short-lived bearer token, no refresh material Testing standalone delegated/harvested access tokens identified (ex ya29.a0AfH6SM...)
OAuth2 token file (oauth2 --token-file) Yes An authorized_user-shaped JSON (a token.json, same shape as an ADC file) Refresh-token backed — reloads/auto-renews like ADC Loading a pre-obtained user credential — one you obtained elsewhere, recovered from a compromised host, or exported from another tool.
Service account key (service-acc-key / service) Yes Service account JSON key file Long-lived key unless rotated Service-account identity operations

GCPwn Startup Commands

At startup, add credentials with one of the following patterns:

  • adc
adc <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
  • oauth2
oauth2 <credential_name> --token <access_token> [--tokeninfo]
  • service-acc-key
service-acc-key <credential_name> --service-file <service_account_json_path>

Quick startup examples:

adc corp-adc --filepath-to-adc ~/.config/gcloud/application_default_credentials.json
oauth2 redteam-token --token ya29.a0AfH6SM...
service-acc-key app-sa --service-file /tmp/app-sa.json

You can also select an existing credential by name/index, or press Enter to continue without loading credentials.

The startup screen above is a shorthand for the three most common cases. --token-file (no service account / no ADC needed — see below) is only available via the in-workspace creds add command, not the startup menu — press Enter to skip startup creds (or load any existing credential) and run it once you're in the workspace.

After Startup

  • creds list
  • creds swap [<credname>]
  • creds info [<credname>] [--csv]
  • creds tokeninfo [<credname>]
  • creds add <credname> --type <adc|oauth2|service> [credential flags...] [--assume]
  • creds update [<credname>] --type <adc|oauth2|service> [credential flags...] [--assume]

Add new credentials at startup (adc, oauth2, service-acc-key), or in-workspace via creds add (strictly more options, including --token-file), then use creds update to refresh stored credentials.

For full workspace command coverage, see Workspace Instructions.

Non-Interactive Runs (--module)

Some workflows (CI, scripting, scheduled scans) need to run a single module without dropping into the interactive REPL. GCPwn supports two non-interactive "passthrough" modes from the shell.

Unauthenticated passthrough

Run an unauthenticated module directly — no workspace or credential needed:

gcpwn --module unauth_apikey_enum_all_scopes --api-key AIza...
gcpwn --module unauth_bucketbrute --keyword acme --check

Only unauthenticated modules (the unauth_* family) are allowed here. --project-id optionally supplies a project context for modules that derive target URLs from it.

Authenticated drive-through

Run an authenticated module against a stored credential by supplying the workspace and credential names as flags — the credential must already have been added to that workspace via a previous interactive session (see GCPwn Startup Commands):

# Enumerate IAM against the credential's own project
gcpwn --module enum_iam --workspace WORKSPACE_NAME --cred CRED_NAME --current-project

# Target a specific project (or a comma list)
gcpwn --module enum_iam --workspace WORKSPACE_NAME --cred CRED_NAME --project-id my-project

# Fan out across every project already known to the workspace
gcpwn --module enum_gcp --workspace WORKSPACE_NAME --cred CRED_NAME --all-projects
  • --workspace <name> — the workspace that holds the credential (matched by exact name).
  • --cred <credname> — the stored credential to load into the session.
  • Project scope flows through the normal selectors: --project-id / --project-ids / --project-id-file, --current-project, or --all-projects. If you pass none, the run defaults to the credential's own project and never blocks on a prompt (drive-through mode is non-interactive).
  • Everything after the recognized flags is passed straight to the module, so modules run <module> -h flags work here too.

Errors are explicit: an unknown --workspace lists the available workspaces; an unknown or missing --cred lists the credentials stored in that workspace; and running an authenticated module without --workspace/--cred prints the exact drive-through command to use.

Resuming enum_all (Ctrl+C / mid-run failure): resumability is fully preserved in drive-through mode. enum_all / enum_gcp run with --parallel-services N record every completed (project, service) unit in a workspace-scoped SQLite ledger (enum_all_task_ledger). The workspace itself is the checkpoint — there is no separate token to save. If a run is interrupted (Ctrl+C) or fails partway, just re-run the exact same command (same --workspace, --cred, and project scope): completed units are skipped (... resuming: N services already done) and only the remaining work runs. The default (non-parallel) path does not skip-track units, but its writes are idempotent upserts, so a re-run re-enumerates without duplicating or losing data. For large scans, prefer --parallel-services N for true skip-done resume.

Note: Drive-through is designed for non-prompting modules (enumeration, enum_all, policy bindings, OpenGraph). Modules that require interactive selection or confirmation (most exploit_* modules) will skip the prompt rather than hang — auto-selecting when there is a single obvious choice, otherwise reporting that the step needs the interactive REPL. Run those from a normal session.

Tokeninfo Quick Note

BOTH user and service account access tokens can exist, but the token string by itself does not clearly identify the principal behind it (you can't base64 decode it like a JWT; its "opaque").

The --tokeninfo flag and creds tokeninfo command call Google’s /tokeninfo endpoint to return token metadata (for example, email and scopes) given an access token. This helps enrich your session data, details who the token belongs to if you don't have that context, and maps the current credential to the correct IAM identity during enumeration.

Tokeninfo Endpoint

https://oauth2.googleapis.com/tokeninfo?access_token=<ACCESS_TOKEN>

GCPwn examples

# When adding creds
oauth2 redteam-token --token ya29.a0AfH6SM... --tokeninfo
# While in workspace
creds tokeninfo redteam-token

References

Application Default Credentials (ADC)

ADC Overview

Application Default Credentials (ADC) is not a single credential. It is Google’s credential discovery mechanism used by SDK-backed tooling to automatically locate usable auth material.

In GCPwn, this maps to google.auth.default() behavior. The library resolves the active credential source for you (local user ADC, service account material, workload identity config, or metadata-attached identity).

Common ADC lookup order in operator workflows as follows, so unset GOOGLE_APPLICATION_CREDENTIALS if that is potentially causing you issues as we focus on 2 for now:

  1. GOOGLE_APPLICATION_CREDENTIALS environment variable
  2. Local ADC file from gcloud auth application-default login

If you are operating interactively, "ADC" usually maps to user-backed OAuth credentials (aka. username/password login) which is what we will consider here.

ADC TLDR Setup

# Browser-based user auth + local ADC file
gcloud auth application-default login

# Recommended to avoid project-context confusion
gcloud config set project <project_ID>

# After starting gcpwn choose ADC as your option with your crednmae. Default ADC file location is usually ~/.config/gcloud/application_default_credentials.json but you can specify path to another file if needed
gcpwn> adc <credname> [--filepath-to-adc ~/.config/gcloud/application_default_credentials.json]

ADC Field Mapping

Field Required Source
credential_name Yes Operator-defined alias
--filepath-to-adc No ADC JSON file path
--tokeninfo No Query Google tokeninfo metadata endpoint

ADC Deep Dive/Setup

1. Know which gcloud login matters

  • gcloud auth login: authenticates the gcloud CLI user context. i.e. you can make further gcloud commands at command line as that user.
  • gcloud auth application-default login: creates ADC material for SDK/client-library usage. i.e. you can make further SDK calls as the user you authenticated as

For GCPwn, application-default login is the key requirement because GCPwn relies on SDK-backed authentication resolution.

2. Start ADC browser authentication

> gcloud auth application-default login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=76408[REDACTED]

Sign in through the browser flow:

Sign-In-1 Sign-In-2 Sign-In-3 Sign-In-4

3. Confirm ADC file creation

After redirecting back to localhost, Google writes your ADC credential file under .config/gcloud:

Credentials saved to file: [/home/user/.config/gcloud/application_default_credentials.json]

These credentials will be used by any library that requests Application Default Credentials (ADC).

Inspect the file. Note there is a client_id, client_secret, and refresh_token. These can be ingested as we will see by a python SDK/code for GCP to auto gen a token and make subsequent API calls.

# cat /home/user/.config/gcloud/application_default_credentials.json                                                     
{
  "account": "",
  "client_id": "764086[REDACTED].apps.googleusercontent.com",
  "client_secret": "d-FL[REDACTED]",
  "refresh_token": "1//01i[REDACTED]",
  "type": "authorized_user",
  "universe_domain": "googleapis.com"
} 

4. Set project context explicitly

The ADC file itself does not set your intended project target. Set project context explicitly to avoid issues with gcpwn:

# Set the project to avoid issues down the road
gcloud config set project <PROJECT_ID>

5. Understand refresh token vs access token behavior

In the ADC file we saw a client_id, client_secret, refresh_token but no access token to send directly to a GCP API. You will typically see a refresh token, not a long-lived pre-generated access token.

At runtime, GCPwn loads the ADC material, uses the material to request and store an access token, uses that access token for subsequent calls, and reuses stored refresh material (ex. refresh_token) for future auto-refresh attempts when the token is invalid.

6. Load ADC into GCPwn and validate with tokeninfo

After startup, load ADC. Note this was successful and gcpwn in the background requested and stored an access token as we will see in the next step.

What you will notice is the final access token (ya29...) is opaque, or you can't decode it locally. Same with gpwn. If you want to decode the opaque access token to better enrich your data then run creds tokeninfo to inspect token metadata (email/scopes) from Google’s tokeninfo endpoint:

Welcome to your workspace! Type 'help' or '?' to see available commands.

[-] No creds found
Submit the name or index of an existing credential from above, or add NEW credentials via:
  [1] adc      <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
  [2] oauth2   <credential_name> --token <access_token> [--tokeninfo]
  [3] service-acc-key <credential_name> --service-file <service_account_json_path>

Tip: `--tokeninfo` queries Google's tokeninfo endpoint to capture scope/email for OAuth-style creds.

Input: adc starting_user_token
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token
(<PROJECT_ID>:starting_user_token)> creds tokeninfo
[*] Checking credentials against https://oauth2.googleapis.com/tokeninfo endpoint...
[*] Succeeded in querying tokeninfo. The response is shown below:
{
  "azp": "764086[TRUNCATED]",
  "aud": "764086[TRUNCATED]",
  "sub": "1057[TRUNCATED]",
  "scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
  "exp": "1778303317",
  "expires_in": "3512",
  "email": "[REDACTED_EMAIL]",
  "email_verified": "true",
  "access_type": "offline"
}

7. Verify session storage behavior

If you want to see the actual access token generated, you can inspect the unified databases/gcpwn.db (the session table) to confirm that GCPwn stored session credential material, including refreshed access-token state:

# sqlite3 databases/gcpwn.db 
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> SELECT workspace_id, credname, credtype, email, default_project FROM session;
1|starting_user_token|adc|[REDACTED_EMAIL]|<PROJECT_ID>

Session credential payload (formatted):

{
  "token": "ya29.a0AQvPyI[REDACTED]",
  "refresh_token": "1//01in[REDACTED]",
  "token_uri": "https://oauth2.googleapis.com/token",
  "client_id": "76408[TRUNCATED]",
  "client_secret": "d-FL[REDACTED]",
  "universe_domain": "googleapis.com",
  "account": "",
  "expiry": "2026-05-09T05:08:36.410200Z"
}

8. Optional manual workflow for access token generation (without GCPwn)

If needed, you can manually:

  1. exchange refresh token material for an access token
  2. send that access token to /tokeninfo
  3. Use that access token as a token input credential in gcpwn covered in the next section

Generate Access Token

# curl request
CLIENT_ID="<CLIENT_ID>"
CLIENT_SECRET="<CLIENT_SECRET>"
REFRESH_TOKEN="<REFRESH_TOKEN>"

curl -sS -X POST "https://oauth2.googleapis.com/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "client_id=${CLIENT_ID}" \
  --data-urlencode "client_secret=${CLIENT_SECRET}" \
  --data-urlencode "refresh_token=${REFRESH_TOKEN}" \
  --data-urlencode "grant_type=refresh_token"

# curl example
CLIENT_ID="764[TRUNCATED]"
CLIENT_SECRET="d-FL[REDACTED]"
REFRESH_TOKEN="1//01i[REDACTED]"

curl -sS -X POST "https://oauth2.googleapis.com/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "client_id=${CLIENT_ID}" \
  --data-urlencode "client_secret=${CLIENT_SECRET}" \
  --data-urlencode "refresh_token=${REFRESH_TOKEN}" \
  --data-urlencode "grant_type=refresh_token"
{
  "access_token": "ya29.a0AQvPyIOFt[REDACTED]",
  "expires_in": 3599,
  "scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/sqlservice.login openid https://www.googleapis.com/auth/cloud-platform",
  "token_type": "Bearer",
  "id_token": "eyJhbGciOiJSUz[REDACTE]"
}  

Send Token to /tokeninfo

# curl request
>curl "https://oauth2.googleapis.com/tokeninfo?access_token=<token>"

#example 
> curl "https://oauth2.googleapis.com/tokeninfo?access_token=ya29.a0AQvPy[REDACTED]"
{
  "azp": "7640[TRUNCATED].com",
  "aud": "7640[TRUNCATED].com",
  "sub": "1057[TRUNCATED]",
  "scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
  "exp": "1778303317",
  "expires_in": "3188",
  "email": "[REDACTED_EMAIL]",
  "email_verified": "true",
  "access_type": "offline"
}

9. Refresh Creds

Like I showed before, gcpwn ALSO stores the refresh material from ADC. So if your access token expires and the tool doesn't auto-refresh it, or you want to refresh your token sooner, you can do that as shown below assuming your adc creds have not changed

(<PROJECT_ID>:starting_user_token)> creds update starting_user_token --type adc --assume
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token

OAuth2 Token

OAuth2 Overview

OAuth2 tokens can come from multiple sources in GCP for both users and service accounts. They typically look like ya29.... These might be from a local user:<email> on the system or a serviceAccount:<email> attached to something like a compute instance for example (classic SSRF).

If you recover a standalone OAuth2 token, you can load it directly into GCPwn and begin making API calls immediately.

Important caveat: a standalone access token is short-lived and cannot be auto-refreshed by itself unless you also have refresh material. Review the instructions to refresh the <credname> at the end of this section

OAuth2 TLDR Setup

# Obtain a valid OAuth2 access token (ex. `ya29...`)

# Pass the token into GCPwn
oauth2 redteam-token --token ya29.a0AfH6SM...

OAuth2 Field Mapping

Field Required Source
credential_name Yes Operator-defined alias
--token Yes OAuth2 bearer token
--tokeninfo No Query Google tokeninfo metadata endpoint

OAuth2 Deep Dive/Setup

1. Decide which OAuth2 token source you have

There are a lot of paths that can lead to an OAuth token being recovered. Two common operator paths are:

  1. user token via gcloud auth login (or recovered local gcloud token cache)
  2. service-account token via instance metadata (IMDS)

2a. User path (gcloud auth login)

Run login and complete browser auth:

# gcloud auth login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=3255[REDACTED]

You are now logged in as [REDACTED_EMAIL].
Your current project is [<PROJECT_ID>].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID
2b Inspect local gcloud token stores

gcloud auth login commonly creates/updates token stores under ~/.config/gcloud, including:

  • access_tokens.db (short-lived access tokens)
  • credentials.db (credential profile material that may include refresh-backed fields)
$ ls -lart /home/user/.config/gcloud/
total 72
[TRUNCATED]
-rw-------  1 user user     5 May  9 01:03 gce
-rw-r--r--  1 user user 12288 May  9 01:03 default_configs.db
-rw-------  1 user user 12288 May  9 01:03 access_tokens.db
-rw-------  1 user user 12288 May  9 01:03 credentials.db
drwxrwxr-x  3 user user  4096 May  9 01:03 legacy_credentials
$ sqlite3 /home/user/.config/gcloud/access_tokens.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> PRAGMA table_info(access_tokens);
0|account_id|TEXT|0||1
1|access_token|TEXT|0||0
2|token_expiry|TIMESTAMP|0||0
3|rapt_token|TEXT|0||0
4|id_token|TEXT|0||0
sqlite> SELECT * FROM access_tokens;
[REDACTED_EMAIL]|ya29.a0[TRUNCATED]|2026-05-09 06:03:55.997030||eyJhbG[TRUNCATED]

credentials.db can also contain refresh/token profile material:

$ sqlite3 /home/user/.config/gcloud/credentials.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
credentials
sqlite> SELECT * FROM credentials;
[REDACTED_EMAIL]|{
  "client_id": "32555940559.apps.googleusercontent.com",
  "client_secret": "Zms[REDACTED]",
  "refresh_token": "1//01p9Q[REDACTED]",
  "revoke_uri": "https://oauth2.googleapis.com/revoke",
  "scopes": [
    "openid",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/appengine.admin",
    "https://www.googleapis.com/auth/sqlservice.login",
    "https://www.googleapis.com/auth/compute",
    "https://www.googleapis.com/auth/accounts.reauth"
  ],
  "token_uri": "https://oauth2.googleapis.com/token",
  "type": "authorized_user",
  "universe_domain": "googleapis.com"
}

3a. Service-account path (IMDS on compute)

On a compute instance with an attached service account, IMDS can return a service-account OAuth2 token:

user@gcp-instance:~$ curl -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/111122223333-compute@developer.gserviceaccount.com/token
{"access_token":"ya29.c.c0AZ[REDACTED]","expires_in":3599,"token_type":"Bearer"}

4. Load OAuth token into GCPwn

Whichever route you followed plug the OAuth2 credential into GCPwn and set project the project after loading the token:

Input: oauth2 my_compute_oauth_token --token "ya29.c.c0AZ4bNpad[REDACTED]"
[*] Project ID of credentials is: Unknown
[*] Credentials successfully added
Loading in OAuth2 token. Note it might be expired based on how long its existed...
[*] Loaded credentials my_compute_oauth_token
(Unknown:my_compute_oauth_token)> modules run enum_cloudstorage
(Unknown:my_compute_oauth_token)> projects set <PROJECT_ID>
(<PROJECT_ID>:my_compute_oauth_token)> modules run enum_cloudstorage
[*] Target project 1/1: <PROJECT_ID>
[**] Reviewing test_[TRUNCATED]
[*] GCPwn found 1 Buckets in project <PROJECT_ID>
[*] TEXT OUTPUT (<PROJECT_ID>)
Resource Type: Buckets
Columns: name | location | blobs
Rows: showing 1 of 1
[TRUNCATED]

5. Understand refresh behavior

A standalone OAuth2 token cannot be refreshed unless you also have refresh material.
When a token expires, obtain a new token for the same principal and update the existing credential name:

creds update redteam-token --type oauth2 --token ya29.NEWTOKEN... --assume

No Service Account Key? Load a User Token

Every auth mode above assumes you already have something — an ADC file, a harvested token, a service-account key. Two notes for the "I only have X" cases:

Have a user's token already? Load it directly — no service account or ADC needed. An authorized_user-shaped JSON (a token.json, refresh token included) auto-renews like ADC; a bare ya29. access token works too but expires in ~1h with no refresh:

creds add CRED_NAME --type oauth2 --token-file token.json --assume   # refresh-token backed, auto-renews
creds add CRED_NAME --type oauth2 --token ya29.<...> --assume         # bare access token, ~1h, no refresh

This is a general Google user credential — if the identity has IAM grants on GCP projects the regular enum_*/exploit_* GCP modules work against it; if it's a Workspace admin the Workspace modules work against it directly (no impersonation needed).

Only have an email + password, no token? Google has no password→token API (no ClientLogin/ROPC-style endpoint for Google identities — a deliberate security decision), so raw credentials cannot be exchanged for a token programmatically. The equivalent is a one-time interactive OAuth consent in a browser; a built-in creds login browser flow is planned but not currently shipped. For now, mint an authorized_user token out-of-band — e.g. gcloud auth application-default login on a machine with a browser — and load the resulting token.json with --token-file above.

For Google Workspace, the intended path is a service account with domain-wide delegation impersonating an admin — see Google Workspace Enumeration (customer ID, --impersonate, per-module scopes).

Service Account Key

Service Account Key Overview

Service accounts are included in IAM bindings throughout GCP environments. Users can generate long-lasting static JSON API keys for service accounts which can then be used in various tools/SDKs to make API calls as the service account.

Service Account Key TLDR Setup

# Obtain a service account JSON key file
# (usually via IAM -> Service Accounts -> Keys)

# Load the key into GCPwn at startup
service-acc-key app-sa --service-file /tmp/app-sa.json

Service Account Key Field Mapping

Field Required Source
credential_name Yes Operator-defined alias
--service-file Yes Service account JSON key file path

Service Account Key Deep Dive/Setup

1. Create or recover a service account key file

Service account auth requires a JSON key file. Operators usually obtain this from IAM key-management workflows (or recover it from an accessible host/workspace path).

Typical file shape:

{
  "type": "service_account",
  "project_id": "example-project",
  "private_key_id": "[REDACTED]",
  "private_key": "-----BEGIN PRIVATE KEY-----\n[REDACTED]\n-----END PRIVATE KEY-----\n",
  "client_email": "sa-name@example-project.iam.gserviceaccount.com",
  "client_id": "[REDACTED]",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token"
}

2. Secure the key file on disk

Treat this file like a password-equivalent secret.

chmod 600 /tmp/app-sa.json

3. Load the key into GCPwn

At startup:

service-acc-key app-sa --service-file /tmp/app-sa.json

4. Set project context and run a quick validation call

The tool should auto-detect the project based off the project_id field in the key. However, depending on the key/project context, explicitly setting the active project might be required:

(Unknown:app-sa)> projects set <PROJECT_ID>
(<PROJECT_ID>:app-sa)> modules run enum_cloudstorage

5. Refresh

Service account keys don't auto-refresh like the ADC example. If you recover another keyf or the same principle you can update a credname with

creds update app-sa --type service --service-file /tmp/app-sa.json --assume

Google Workspace (Domain-Wide Delegation)

The Google Workspace enumeration modules (enum_cloud_identity, enum_admin_roles, enum_org_units, enum_domains, enum_mobile_devices, enum_oauth_tokens, and the once-only enum_google_workspace phase) call the Cloud Identity API (cloudidentity.googleapis.com) and the Admin SDK Directory API (admin.googleapis.com). These are not regular GCP project APIs, and this is the single most common point of confusion:

GCP credentials do not grant Google Workspace access. A cloud-platform-scoped ADC/OAuth token or a service-account key that works perfectly for GCP project APIs still returns 403/404 against Directory/Cloud Identity. Workspace is a separate tenant (an admin console at admin.google.com) with its own identities and OAuth scopes. You need a principal that Workspace itself recognizes as an admin.

There is nothing to load differently at auth time — you still add creds with adc, oauth2, or service-acc-key as usual. What matters is which principal the creds resolve to, and Workspace supports two paths.

Path 1 — Admin user credential (no extra flags)

If the credential you loaded is a user who is a Workspace admin (an ADC/OAuth2 credential for e.g. admin@yourdomain.com), the Workspace modules work directly. The required OAuth scopes (cloud-identity.groups.readonly, admin.directory.user/group/group.member.readonly) are attached automatically at client build time, and no impersonation/subject is used (user credentials have no with_subject, so the subject resolution is a no-op). Just run the Workspace modules.

No gcloud installed and no key file for that admin — just their email/password? Google has no password→token API, so mint an authorized_user token out-of-band (e.g. gcloud auth application-default login on a machine with a browser) and load it with creds add <name> --type oauth2 --token-file token.json; the result is a plain OAuth2 user credential that works exactly the same as ADC here.

Path 2 — Service account + domain-wide delegation (DWD)

A service account cannot read Workspace on its own. It must:

  1. Have domain-wide delegation configured in the Workspace Admin console — its OAuth client ID authorized for the Directory/Cloud Identity scopes above. This is done outside gcpwn, once, by a Workspace super admin.
  2. Impersonate an admin subject at runtime. gcpwn performs the impersonation for you via credentials.with_subject(admin@domain); all you supply is the admin email.

You still load the SA the normal way (service-acc-key wsp-sa --service-file ...). Then supply the admin subject to impersonate with the --impersonate <admin@domain> flag, which every Workspace module and the enum_google_workspace orchestrator accepts:

# Load the delegated service account, then impersonate an admin subject
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --impersonate admin@yourdomain.com
(<PROJECT_ID>:wsp-sa)> modules run enum_google_workspace --impersonate admin@yourdomain.com

The admin subject can also live in a persistent config field, workspace_admin_subject, which the modules read when --impersonate is not passed. Note, however, that this key is not currently settable through the interactive configs set command (only workspace_customer_id is, see below) — in practice supply the subject with --impersonate. With no subject resolved and an SA credential, the modules run un-delegated and most Directory/Cloud Identity admin reads are denied (403/404). All Workspace modules degrade gracefully in that case rather than crashing.

Directory Customer ID (directoryCustomerId)

The Cloud Identity and Directory calls are scoped to a Workspace tenant by its Directory Customer ID (directoryCustomerId, looks like C0xxxxxxx). gcpwn resolves it in this order:

  1. Explicit --customer-id C... on the module.
  2. The persistent workspace_customer_id config (configs set workspace_customer_id C...).
  3. Derived from the current GCP organization: Resource Manager organizations.get reads the org's directoryCustomerId. You can point at a specific org with --org-id <numeric>; otherwise gcpwn walks the cached project hierarchy to find the org.

When step 3 succeeds it auto-persists the resolved customer ID into workspace_customer_id (via configs set), so later runs skip the organizations.get round-trip. If no customer ID can be resolved, the user-enumeration path is skipped with a notice.

# Explicit customer ID for this run
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --customer-id C0xxxxxxx --impersonate admin@yourdomain.com

# Persist the customer ID once (settable via configs), then just impersonate
(<PROJECT_ID>:wsp-sa)> configs set workspace_customer_id C0xxxxxxx
(<PROJECT_ID>:wsp-sa)> modules run enum_google_workspace --impersonate admin@yourdomain.com

# Let gcpwn derive + auto-persist the customer ID from the GCP org
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --org-id 123456789012 --impersonate admin@yourdomain.com

enum_all runs the normal GCP services plus a once-only Workspace phase; enum_gcp is GCP-only (skips Workspace); enum_google_workspace runs just the Workspace modules.

Auth Operational Notes

  • creds info prints current credential summary and discovered permission view.
  • creds info --csv exports flattened permission rows for review/filtering.
  • creds tokeninfo works for OAuth-style creds and is metadata enrichment only.
  • creds set updates stored email/project metadata for a credential context.

Common Auth Errors

Error Pattern Meaning Remediation
Must supply token via --token OAuth2 mode called without token Re-run with --token <access_token>
File ... does not exist ADC/service file path invalid Verify path and re-run
ADC not setup No default ADC available Run gcloud auth application-default login and gcloud config project set <PROJECT_ID> before starting gcpwn
Can't perform tokeninfo operations with a service account token tokeninfo used with service-account creds Use tokeninfo for OAuth-style creds only
Credential refresh errors Expired/invalid refresh state Your crednetials/token are expired. Re-authenticate and run creds update if you have a new token to replace your current expired session with

Source References

Clone this wiki locally