Determine this is the right repository
Summary of the issue
When using Workload Identity Federation with Service Account impersonation, gcloud caches the final Service Account access token on disk (access_tokens.db).
When reloading credentials, gcloud restores that cached access token directly onto the outer WL credential object. Because an unexpired token exists, the SDK skips a normal token refresh. Consequently, the inner impersonated credential object (self._impersonated_credentials) is never created.
When a Regional Access Boundary (RAB) check runs, it sees self._impersonated_credentials == None. It assumes this is a plain workload and queries the WL's allowedLocations endpoint using the cached Service Account access token, resulting in an immediate HTTP 500 Audience Mismatch rejection.
Proposed Fix
Instead of relying on mid-flight lazy initialization inside request hooks, __init__() on ExternalAccountCredentials initializes impersonation immediately upon creation:
- If an impersonation URL is configured,
__init__() immediately constructs self._impersonated_credentials (zero network I/O required) and adopts the Service Account's _rab_manager.
- Property setters on
.token and .expiry route any cached token loaded by gcloud directly to the inner Service Account identity.
- This avoids multithreaded race conditions and guarantees RAB checks target the correct Service Account endpoint from instantiation.
Potential Long-Term Fix
Right now, external account credentials act as a container around the inner impersonated service account. To fix this permanently without having to forward the properties, loading an external account config should return an actual impersonation credential object.
Here is what needs to change across both codebases:
-
In google-auth (Python SDK):
When ExternalAccountCredentials.from_info() sees a service_account_impersonation_url in the config, it should create a regular workload credential as the base source and return an impersonated_credentials.Credentials object directly. To make sure gcloud can still save these credentials back to disk, we also need to add .info serialization to the impersonated_credentials.Credentials class.
-
In gcloud (google-cloud-sdk):
Currently, gcloud checks if a credential is an external account using isinstance(cred, ExternalAccountCredentials). If we return an impersonated credential, those checks will fail. We need to update creds.py and store.py so that isinstance checks look inside cred._source_credentials to unwrap the original credential. This allows gcloud to attach token caches and read account IDs correctly.
Determine this is the right repository
Summary of the issue
When using Workload Identity Federation with Service Account impersonation,
gcloudcaches the final Service Account access token on disk (access_tokens.db).When reloading credentials,
gcloudrestores that cached access token directly onto the outer WL credential object. Because an unexpired token exists, the SDK skips a normal token refresh. Consequently, the inner impersonated credential object (self._impersonated_credentials) is never created.When a Regional Access Boundary (RAB) check runs, it sees
self._impersonated_credentials == None. It assumes this is a plain workload and queries the WL's allowedLocations endpoint using the cached Service Account access token, resulting in an immediateHTTP 500 Audience Mismatchrejection.Proposed Fix
Instead of relying on mid-flight lazy initialization inside request hooks,
__init__()onExternalAccountCredentialsinitializes impersonation immediately upon creation:__init__()immediately constructsself._impersonated_credentials(zero network I/O required) and adopts the Service Account's_rab_manager..tokenand.expiryroute any cached token loaded bygclouddirectly to the inner Service Account identity.Potential Long-Term Fix
Right now, external account credentials act as a container around the inner impersonated service account. To fix this permanently without having to forward the properties, loading an external account config should return an actual impersonation credential object.
Here is what needs to change across both codebases:
In
google-auth(Python SDK):When
ExternalAccountCredentials.from_info()sees aservice_account_impersonation_urlin the config, it should create a regular workload credential as the base source and return animpersonated_credentials.Credentialsobject directly. To make suregcloudcan still save these credentials back to disk, we also need to add.infoserialization to theimpersonated_credentials.Credentialsclass.In
gcloud(google-cloud-sdk):Currently,
gcloudchecks if a credential is an external account usingisinstance(cred, ExternalAccountCredentials). If we return an impersonated credential, those checks will fail. We need to updatecreds.pyandstore.pyso thatisinstancechecks look insidecred._source_credentialsto unwrap the original credential. This allowsgcloudto attach token caches and read account IDs correctly.