note, i just have this here as archive, please see
Almost two years ago I wrote an article about using the Service Account Actor IAM role for account impersonation. Since then, there have been some API surface changes and enchanced capabilities that makes that flow a lot easier…and as noted in the article, a bit obsolete. The ideas contained in that article are still valid though the mechanism is dated. In the new flow, you can now ‘just get’ an access_token
, id_token
, jwt
or sign
arbitrary blobs for a target service account by directly calling the iamcredentials API.
Lets use that API and go one step further: what if we bake in that exchange directly into the various google-auth-*
libraries? That is, perform the exchange directly within any cloud library and use the assumed identity within any of target service set. For example:
You start with a credential A initialized by any means (Service Account JSON, GCE metadata, userflow-oauth, etc)
You use GCP auth libraries to exchange A for credentials representing serviceAccountB
You use any google-cloud* library as account B
In code, it would look like this:
Note we start off with serviceAccount Credentials and then use google.auth.impersonated_credentials to exchange the provided credentials for another and the proceed to ‘just use’ any google API library
Using this is pretty straightforward:
then just run the the main.py python sample above (ofcourse replace PROJECT_ID
variable in code above)
You can also ‘just run’ the sample above in a GCE compute engine instance:
gcloud compute instances create impersonate-test \
--service-account=source-serviceaccount@$PROJECT.iam.gserviceaccount.com \
--scopes=https://www.googleapis.com/auth/iam
Note that the API surface for iamcredentials.*
describes a lifetime variable. What that does is pretty self-explanatory in that it just limits the lifetime of the derived access_token. By default its one hour 3600s
but will automatically refresh even if the lifetime is set. Effectively, the lifetime is there for the transient token since its auto-refreshed on expiration.
If on the otherhand what you want is a true static access token for its duration, you will need to extract the impersonated credentials access token and apply it to a generic Credential object as such:
import google.auth.transport.requests
from google.oauth2.credentials import Credentials
target_credentials = impersonated_credentials.Credentials(
source_credentials = source_credentials,
target_principal='impersonated-account@your_project.iam.gserviceaccount.com',
target_scopes = target_scopes,
delegates=[],
lifetime=500)
request = google.auth.transport.requests.Request()
target_credentials.refresh(request)
derived_access_token = target_credentials.token
print derived_access_token
static_credentials = Credentials(token=derived_access_token)
client = storage.Client(credentials=static_credentials)
buckets = client.list_buckets(project='your_project')
for bucket in buckets:
print bucket.name
In the example above, tthe final client will only work for 500
seconds
Another feature with iamcredentials.*
api suite is the delegates parameter. What that signifies is the list of service accounts that must already have authorization to mint tokens on behalf of the successive account. The chained list of delegates required to grant the final access_token. If set, the sequence of identities must have Service Account Token Creator capability granted to the prceeding identity. For example, if set to [serviceAccountB
, serviceAccountC
], the source_credential must have the Token Creator role on serviceAccountB
. serviceAccountB
must have the Token Creator on serviceAccountC
. Finally, C
must have Token Creator
on target_principal. If left unset, source_credential must have that role on target_principal
.
You can think of this as getting a form of a simple ‘workflow’ where the source account can’t unilaterally acquire permissions on the target but one where a sequence of ‘approvals` in a workflow is needed.
For more information on this, see: Creating Short-Lived Service Account Credentials
update 12/13/21: the following is incorrect!!, see (https://github.com/salrashid123/gcp_impersonated_credentials)
At the time of writing (11/25/18), the ‘first class’ support for impersonated credentials is not available in all languages Available:
If you are interested in contributing a binding in any of the languages above, please feel free :)
The following shows the audit logs that would get generated as a result of the Impersonated and Resource (GCS) access above:
Note that the logs span two different resource.types in Cloud logging (IAM and the resource in context). That means to see them together, just run a query with a filter like:
resource.type="service_account" OR resource.type="gcs_bucket"
Here is a detailed logging payload for the IAM request:
And the actual resource request.
Notice that the api request contains the ORIGINAL user that is impersonating the service account
"authenticationInfo": {
"principalEmail": "target-serviceaccount@fabled-ray-104117.iam.gserviceaccount.com",
"serviceAccountDelegationInfo": [
{
"firstPartyPrincipal": {
"principalEmail": "admin@esodemoapp2.com"
}
}
]
},
For more information, see Audit logs for service accounts
This site supports webmentions. Send me a mention via this form.