auth: idtoken.NewCredentials
doubly-impersonates an account when used with workload identity federation
#11105
Labels
type: feature request
‘Nice-to-have’ improvement, new feature or different behavior or design.
Client
cloud.google.com/go/auth
Environment
Ubuntu 22.04 on GCE
Code and Dependencies
Expected behavior
When used with
GOOGLE_APPLICATION_CREDENTIALS=/path/to/workload-identity-federation-creds.json
,idtoken.NewCredentials
should:getOpenIdToken
on the service account in theservice_account_impersonation_url
field ofworkload-identity-federation-creds.json
Actual behavior
idtoken.NewCredentials
instead:getAccessToken
on the service account in theservice_account_impersonation_url
field ofworkload-identity-federation-creds.json
getOpenIdToken
on the service account in theservice_account_impersonation_url
field ofworkload-identity-federation-creds.json
In other words, it impersonates the account in
service_account_impersonation_url
, and then as that account tries to impersonate itself again.The final
getOpenIdToken
call fails with:This is because the service account does not have
iam.serviceAccounts.getOpenIdToken
on itself, which is expected, since it shouldn't need this permission. The workload identity principal hasroles/iam.workloadIdentityUser
on the target service account, and should be able to generate the ID token directly.Screenshots
N/A
Additional context
This also occurs in the old version of the golang auth library, see googleapis/google-api-go-client#2301.
I believe this happens because
idtoken.NewCredentials
callscredentials.DetectDefault
:google-cloud-go/auth/credentials/idtoken/idtoken.go
Lines 125 to 130 in 79556c4
...which eventually finds the
external_account
credentials:google-cloud-go/auth/credentials/filetypes.go
Lines 60 to 69 in 79556c4
...and
handleExternalAccount
callsexternalaccount.NewTokenProvider
:google-cloud-go/auth/credentials/filetypes.go
Line 185 in 79556c4
...which wraps the token provider with an
impersonate.NewTokenProvider
:google-cloud-go/auth/credentials/internal/externalaccount/externalaccount.go
Lines 243 to 261 in 79556c4
So now
idtoken.NewCredentials
has a credential that will automatically impersonate theservice_account_impersonation_url
account, and it then callscredsFromDefault
:google-cloud-go/auth/credentials/idtoken/idtoken.go
Line 134 in 79556c4
...which creates a second
impersonate.NewTokenProvider
with these credentials:google-cloud-go/auth/credentials/idtoken/file.go
Lines 78 to 106 in 79556c4
Thus, it impersonates the
service_account_impersonation_url
in order to get an access token, and then tries to impersonate itself to get an ID token.I believe that ideally, the library would instead use a non-impersonated credential provider to do the STS exchange and wrap that in a single impersonated credential provider to get the ID token.
The text was updated successfully, but these errors were encountered: