I searched a lot how to authenticate/authorize Google's client libraries and it seems no one agrees how to do it.
Some people states that I should create a service account, create a key out from it and give that key to each developer that wants to act as this service account. I hate this solution because it leaks the identity of the service account to multiple person.
Others mentioned that you simply log in with the Cloud SDK and ADC (Application Default Credentials) by doing:
$ gcloud auth application-default login
Then, libraries like google-cloud-storage
will load credentials tied to my user from the ADC.
It's better but still not good for me as this require to go to IAM
and give every developer (or a group) the permissions required for the application to run. Moreover, if the developer runs many applications locally for testing purposes (e.g. microservices), the list of permissions required will probably be very long. Also it will be hard to understand why we gave such permissions after some time.
The last approach I encountered is service account impersonation. This resolve the fact of exposing private keys to developers, and let us define the permission required by an application, let's say A once, associate them to a service account and say:
Hey, let Julien act as the service account used for application A.
Here's a snippet of how to impersonate a principal:
from google.auth import impersonated_credentials
from google.auth import default
from google.cloud import storage
target_scopes = ['https://www.googleapis.com/auth/devstorage.read_only']
credentials, project = default(scopes=target_scopes)
final_credentials = impersonated_credentials.Credentials(
source_credentials=credentials,
target_principal="foo@bar-271618.iam.gserviceaccount.com",
target_scopes=target_scopes
)
client = storage.Client(credentials=final_credentials)
print(next(client.list_buckets()))
If you want to try this yourself, you need to create the service account you want to impersonate (here foo@bar-271618.iam.gserviceaccount.com) and grant your user the role
Service Account Token Creator
from the service account permission tab.
My only concern is that it would require me to wrap all Google Cloud client libraries I want to use with something that checks if I am running my app locally:
from google.auth import impersonated_credentials
from google.auth import default
from google.cloud import storage
target_scopes = ['https://www.googleapis.com/auth/devstorage.read_only']
credentials, project = default(scopes=target_scopes)
if env := os.getenv("RUNNING_ENVIRONMENT") == "local":
credentials = impersonated_credentials.Credentials(
source_credentials=credentials,
target_principal=os.environ["TARGET_PRINCIPAL"],
target_scopes=target_scopes
)
client = storage.Client(credentials=credentials)
print(next(client.list_buckets()))
Also, I have to define the scopes (I think it's the oauth2 access scopes?) I am using, which is pretty annoying.
My question is: I am I going the right direction? Do I overthink all of that? Is there any easier way to achieve all of that?
Here's some of the source I used:
- https://readthedocs.org/projects/google-auth/downloads/pdf/latest/
- https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials
- https://cloud.google.com/docs/authentication/production
- https://youtu.be/IYGkbDXDR9I?t=822
Update 1
This topic is discussed here.
I've made a first proposition here to support this enhancement.
Update 2
The feature has been implemented! See here for details.