Fetch signedJwt token for google service account - google-cloud-platform

I am trying to generate signedJWT token for google service account
now = int(time.time())
expires = now + 900 # 15 mins in seconds, can't be longer.
payload = {
'iat': now,
'exp': expires,
'sub': 'somekey#someproject.iam.gserviceaccount.com',
'aud': 'aud'
}
body = {'payload': json.dumps(payload)}
name = 'projects/someproject/serviceAccounts/somekey#someproject.iam.gserviceaccount.com'
iam = googleapiclient.discovery.build('iam', 'v1', credentials=credentials)
request = iam.projects().serviceAccounts().signJwt(name=name, body=body)
resp = request.execute()
jwt = resp['signedJwt']
The problem I am facing is regarding credentials
If I use
credentials = service_account.Credentials.from_service_account_info(gcp_json_credentials_dict)
works fine.
But I am trying to use default service account
credentials, your_project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"])
Getting following error -
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://iam.googleapis.com/v1/projects/someproject/serviceAccounts/somekey#someproject.iam.gserviceaccount.com:signJwt?alt=json returned "Permission iam.serviceAccounts.signJwt is required to perform this operation on service account

First, I will try to explain why you are getting the error:
permission iam.serviceAccounts.signJwt is required to perform this operation on service account.
A) Your code is running on a compute service using the default service account. I will call this Identity-1.
B) Your code is impersonating the identity somekey#someproject.iam.gserviceaccount.com. I will call this Identity-2.
Your code needs permissions to use the credentials of Identity-1 and the rights to impersonate Identity-2.
Part 1:
When you use the default service account for a compute service or assign a service account to a compute service, two forms of permission control are in effect. The master control is the IAM roles assigned to the service account. The limiter is the ** OAuth scopes** set for the compute service.
The OAuth scopes do not grant permissions, the OAuth scopes limit permissions already granted to the service account via IAM roles. This is an important point that I see so many configure incorrectly. I recommend using the compute engine Access scopes set to Allow full access to all Cloud APIs. Then modify/manage the IAM roles assigned to the service account assigned to Compute Engine.
Part 2:
In order to impersonate another identity, in your case Identity-1 is impersonating Identity-2, your code must have the right to do so. There are two types of identities that can be impersonated: a) service accounts; b) user identities. In your case, you are impersonating another service account.
If you are impersonating a service account, that requires granting the correct IAM permission via an IAM role on Identity-2 with the member set to Identity-1. Think of it this way: Identity-2 must grant permission to Identity-1.
If you are impersonating a user identity, that requires setting up Google Workspace Domain-Wide Delegation of Authority. The account that you are impersonating must be managed by Google Workspace. Refer to Google Workspace Domain-Wide Delegation of Authority is set up user account impersonation which is not required in your case.
Now you might wonder, which identity needs the right to impersonate? The identity that the JWT represents. That identity is declared by the JWT claim iss. Your JWT does not include an iss claim. For more details an example see this link. The identity that you are impersonating is specified by the claim sub. In OAuth speak iss is impersonating sub.
Part 3:
You must also configure your Google Cloud Project to support your objective. This requires enabling two APIs:
iamcredentials.googleapis.com
cloudresourcemanager.googleapis.com
Solution:
Enable the required APIs:
gcloud services enable iamcredentials.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
Set the Compute Engine Access Scopes to Allow full access to all Cloud APIs. This requires shutting down the VM and editing the VM configuration.
Add the iss claim to the JWT that you are creating with the value Identity-1.
Grant an IAM Role containing the permission iam.serviceAccounts.signJwt. A good role to use is Service Account Token Creator to Identity-2. See this link for more details.
Example command:
gcloud iam service-accounts add-iam-policy-binding [Identity-2] \
--member serviceAccount:[Identity-1\ \
--role roles/iam.serviceAccountTokenCreator

Related

What is the point of "Service Account User" role if it's not for impersonation?

The documentation for the Service Account User role is a bit confusing.
https://cloud.google.com/iam/docs/service-accounts#user-role
Users granted the Service Account User role on a service account can use it to indirectly access all the resources to which the service account has access. For example, if a service account has been granted the Compute Admin role (roles/compute.admin), a user that has been granted the Service Account Users role (roles/iam.serviceAccountUser) on that service account can act as the service account to start a Compute Engine instance. In this flow, the user impersonates the service account to perform any tasks using its granted roles and permissions.
Based on this, I assume that by granting my account the Service Account User role on a service account that is owner, I should be able to impersonate that service account from the command line and run gcloud commands with the inherited permissions of the service account
gcloud init # login to my account that has the user role on the SA
gcloud set config auth/impersonate_service_account <service-account-email>
gcloud compute instances list
> WARNING: This command is using service account impersonation. All API calls will be executed as [<service-account>#<project>.iam.gserviceaccount.com].
> ERROR: (gcloud.compute.instances.list) Failed to impersonate [<service-account>#<project>.iam.gserviceaccount.com]. Make sure the account that's trying to impersonate it has access to the service account itself and the "roles/iam.serviceAccountTokenCreator" role.
So I removed the User role and assigned myself the Token Creator role. Works as expected. Why does the description for the User role sound like its the role I'm meant to be using but it seems like Token Creator is the only one I need?
So despite the confusion of the GCP docs, I think I was able to reach a conclusion on the difference between:
Service Account User
Service Account Token Creator
As an example, if I wanted to deploy a GKE cluster but specify a service account for the nodes to use other than the default service account I would add the flag:
gcloud containers cluster create my-cluster --service-account=<service-account>
For me to do this I would at a minimum require Service Account User on the service account I am attempting to assign to the resources. This role appears to also be used in other cases such as executing code on a VM and using the VMs identity instead(??).
If I wanted to deploy the cluster using the service account credentials (ie. Not my own account), I would use impersonation which requires the Token Creator role. I might want to do this because my personal account doesn't have permission to deploy clusters but the SA does.
gcloud containers cluster create my-cluster --impersonate-service-account=<service-account>
This would build the cluster and log the action as that of the service account, not my personal account.
Please correct me if I'm wrong.

ERROR: (gcloud.composer.environments.update) Failed to impersonate when terraform runs impersonating as a second account

I am getting the following error (Please see below) when I run my terraform apply.
I am running Terraform 12.x.
GCP Cloud Build runs in a different project other than project-abcd (where these accounts are)
My terraform code tries execute a gcloud command in a GCP cloud build container. It does so by impersonating as composer-bq-sa#prj-abcd.iam.gserviceaccount.com
The service account that terraform runs as is:
terraform_service_account = "org-terraform#abcd.iam.gserviceaccount.com"
(before impersonating)
This IAM account (org-terraform#abcd.iam.gserviceaccount.com) (NOT service account) has the following role bindings (TOTAL 9):
(There is no Service Account with that email)
Composer Administrator
Compute Network Admin
Service Account Token Creator
Owner
Access Context Manager Admin
Security Admin
Service Account Admin
Logs Configuration Writer
Security Center Notification Configurations Editor
The service account (composer-bq-sa#prj-abcd.iam.gserviceaccount.com) has as one of its members: org-terraform#abcd.iam.gserviceaccount.com
When I look at the screen titled "Members with access to this service account" and look at org-terraform#abcd.iam.gserviceaccount.com , I see that it has the following role-bindings (ONLY 4):
Service Account Token Creator
Owner
Security Admin
Service Account Admin
Why am I getting the error below even though IAM account has apparently the right roles and it is one of the members of the service account it is impersonating as?
ERROR
module.gcloud_composer_bucket_env_var.null_resource.run_command[0] (local-exec): WARNING: This command
is using service account impersonation. All API calls will be executed as [**composer-bq-sa#prj-abcd.iam.gserviceaccount.com**].
module.gcloud_composer_bucket_env_var.null_resource.run_command[0] (local-exec): ERROR:
(gcloud.composer.environments.update) Failed to impersonate [**composer-bq-sa#prj-abcd.iam.gserviceaccount.com**]. Make sure the account that's trying to impersonate it has access to the service account itself and the "roles/iam.serviceAccountTokenCreator" role.
Recapping:
In order to grant user permission to impersonate a Service Account follow instructions listed in this document.
Depending on the use case, you may grant user following roles:
roles/iam.serviceAccountUser
roles/iam.serviceAccountTokenCreator
roles/iam.workloadIdentityUser

Grant your originating account the Service Account Token Creator role on the target service account

I used the below command to Authenticate in MAC OS terminal
gcloud auth login
It redirects to the google login page and show the authentication process successful.
While using the command
gsutil -i fetebird-storage#fetebird.iam.gserviceaccount.com ls
Getting an exception as
AccessDeniedException: Service account impersonation failed. Please go to the Google Cloud Platform Console (https://cloud.google.com/console), select IAM & admin, then Service Accounts, and grant your originating account the Service Account Token Creator role on the target service account.
However, on the cloud I do have given the permission as shown below
Auth List
The current logged in user (fetebird#gmail.com) must have the Service Account Access Token Creator role.
You might think the owner role would be sufficient, however, when I tested this myself you need to explicitly add it to the account that is impersonating the service account.
https://cloud.google.com/iam/docs/service-accounts#token-creator-role

GCP - Not able to list objects inside Bucket even having devstorage.read_only permission?

I have created a EC2 instance, which creates by default service account with default permissions. So when I checked the default permissions I found that the service account is all these permissions below.
https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/logging.write
https://www.googleapis.com/auth/monitoring.write
https://www.googleapis.com/auth/servicecontrol
https://www.googleapis.com/auth/service.management.readonly
https://www.googleapis.com/auth/trace.append
Now I tried to list all the objects inside the bucket by using the command:-
gsutil ls gs://mybucketname
Found an error
AccessDeniedException: 403 XXXX#developer.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket.
Why I am getting this error even though my service account user is having devstorage.read_only?
And I am very new to GCP here, so let me know.
Please read the official documentation regarding the difference between setting the service account level of access with IAM roles and setting the GCE instance's access scopes:
Service account permissions
When you set up an instance to run as a service account, you determine
the level of access the service account has by the IAM roles that you
grant to the service account. If the service account has no IAM roles,
then no API methods can be run by the service account on that
instance.
Furthermore, an instance's access scopes determine the default OAuth
scopes for requests made through the gcloud tool and client libraries
on the instance. As a result, access scopes potentially further
limit access to API methods when authenticating through OAuth. However, they do not extend to other authentication protocols like
gRPC.
Essentially:
IAM restricts access to APIs based on the IAM roles that are granted
to the service account.
Access scopes potentially further limit
access to API methods when authenticating through OAuth.
Therefore I would recomend to add an IAM role with storage.objects.list permission to your instance service account (maybe roles/storage.legacyBucketReader).

What is the difference between Service account, Roles and Access Scopes in GCP?

I am creating gcp instance using below python method:
compute.instances().insert(project=project, zone=zonee, body=config).execute()
In config variable, i have added serviceAccount section:
"serviceAccounts": [
{
"email": SA-email,
"scopes": [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol"
"https://www.googleapis.com/auth/trace.append",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/cloud-platform"
]
}
]
I am not sure what roles should i assign to this SA-email. If i am mentioning access scopes, does it mean those roles must be assigned to SA-email?
When i run above code. Instance creation is being failed.
I am very confused between SA, Roles and Scopes.
What property should i check to troubleshoot above issue.
The Service Account is a special Google account that belongs to your application or a Virtual Machine instead of an individual end user . The Service Account act like an Identity associated with an applications , an application uses a service account to authenticate between the application and GCP services so that the users are not directly involved 1.
The Service Account is very unique in that in addition to being an identity, the service account is also a resource which has IAM policy attached to it, these policies determine who can use this Service Account so it is both an identity and a resource.
For example if you grant Bob the compute instance Admin Role with the service account user role he can create and manage compute engine instances that use a service account. After you grant IAM roles to that Service Account you can than assign that Service Account to one or more new virtual machine instances and now Bob will have an admin access to those instances. To sum it up a user account must be granted a service account user role and the service account must be granted a role to access GCP resources.
The Service Account ACCESS SCOPES are the Legacy methods of specifying permissions for your instance and they are used in substitutions of IAM roles. They you used specifically for default or automatically created service accounts based on enabled APIs. Before the existence of IAM roles the Access Scopes were the only way for granting permissions to the service accounts , although they are not the primary way of granting permissions now , you must still set service account access scopes when configuring an instance to run as a service account. However when you are using a custom service account you will not be using access scopes rather you will be using IAM Roles. So when you are using a default Service Account for your compute Instance it will default to use scopes instead of IAM roles.
For your config variable , you can select the access scopes from the complete list Or you can create the custom Service account and assign the IAM role.