Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCP - Impersonate service account as a user

I would like to allow users to impersonate a service account to do operations on a long running process. However, all the code examples illustrate a service account impersonating another service account.

Can users directly impersonate a service account? If so, how?

I'm following this example code.

Initialize a source credential which does not have access to list bucket:

from google.oauth2 import service_acccount

target_scopes = [
    'https://www.googleapis.com/auth/devstorage.read_only']

source_credentials = (
    service_account.Credentials.from_service_account_file(
        '/path/to/svc_account.json',
        scopes=target_scopes))

Now use the source credentials to acquire credentials to impersonate another service account:

from google.auth import impersonated_credentials

target_credentials = impersonated_credentials.Credentials(
  source_credentials=source_credentials,
  target_principal='impersonated-account@_project_.iam.gserviceaccount.com',
  target_scopes = target_scopes,
  lifetime=500)
like image 694
A Clockwork Orange Avatar asked Mar 05 '20 22:03

A Clockwork Orange


2 Answers

Instead of trying to impersonate a service account from a user account, grant the user permission to create a service account OAuth access token.

Grant the user the role roles/iam.serviceAccountTokenCreator on the service account. This role is called "Service Account Token Creator" in the web console.

Call the API generateAccessToken to create an access token from the service account.

projects.serviceAccounts.generateAccessToken

A simple HTTP POST request will return an access token. Modify the following request with the service account email address.

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[email protected]:generateAccessToken

Request Body:

{
  "delegates": [],
  "scope": [
      "https://www.googleapis.com/auth/cloud-platform"
  ],
  "lifetime": "3600s"
}

This API requires authorization. Include the user's OAuth access token in the HTTP Authorization header.

Authorization: Bearer ACCESS_TOKEN

Response Body:

{
   "accessToken": "eyJ0eXAifeA...NiK8i",
   "expireTime": "2020-03-05T15:01:00.12345678Z"
}
like image 66
John Hanley Avatar answered Oct 21 '22 11:10

John Hanley


Yes, you can impersonate from user to service account. You only need to ensure that your user has Service Account Token Creator role for the target service account. You need to explicitly grant it by:

  1. Selecting the service account in IAM & Admin
  2. Select IAM
  3. Select your account and yourself as the above role (Service Account Token Creator).

Even if you are Project Owner, it doesn't cut it.

Please note it can take 1-2 minutes for the permission to apply, so if your code errors on:

Unable to acquire impersonated credentials...

Make sure you have the above permission and if you just added it recently have a coffee break and try again :)

The code remains practically the same, here is an adapted example from the docs:

import google.auth
import google.auth.impersonated_credentials
from google.cloud import storage


target_scopes = [
    "https://www.googleapis.com/auth/devstorage.read_only"
]

creds, pid = google.auth.default()
print(f"Obtained default credentials for the project {pid}")
tcreds = google.auth.impersonated_credentials.Credentials(
    source_credentials=creds,
    target_principal="<target service account email>",
    target_scopes=target_scopes,
)

client = storage.Client(credentials=tcreds)
buckets = client.list_buckets(project=pid)
for bucket in buckets:
    print(bucket.name)
like image 45
Zaar Hai Avatar answered Oct 21 '22 13:10

Zaar Hai