I want to create an automatic deployment of GCP for clients.
In order to do that, I have opened a page for them to login with google, and then enabled the IAM API and the Service Usage API.
Then I have created a service account that I want to use from this point forward in order to enable other required APIs on demand and not all at once.
When I try to enable the cloudkms API, I get
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://serviceusage.googleapis.com/v1/projects/x-y-z/services/cloudkms.googleapis.com?alt=json returned "The caller does not have permission"
I tried using the service account credentials (google.auth.jwt.Credentials) that I have created from the response of creating the service account, and I have added all the required permissions. I don't want to grant the role owner to the service account, because I want the account to have as less permissions as possible.
When I try to get the status of cloudkms API using the user's permissions, it works.
I have seen some solutions addressing me needing to create credentials for the service account here : https://console.developers.google.com/apis/credentials but I really need to do this programatically as well.
My code:
credentials = jwt.Credentials.from_service_account_file(service_account_info['email'] + '.json', audience="https://www.googleapis.com/auth/cloud-platform")
# credentials = GoogleCredentials.get_application_default() - it works with this
service_usage = googleapiclient.discovery.build('serviceusage', 'v1', credentials=credentials)
service_usage.services().get(name="projects/<project_id>/services/cloudkms.googleapis.com").execute()
The error was mentioned above.
You need the Cloud IAM permission serviceusage.services.enable to enable services. Depending on what features your require, such as listing services, you need serviceusage.services.list.
Typically you add the role roles/serviceusage.serviceUsageAdmin which includes the following permissions:
serviceusage.services.get
serviceusage.services.list
serviceusage.services.enable
serviceusage.services.disable
Goto IAM
Edit user selected
Add new rol
Type Service Usage Admin
Save
Related
I have a script which modifies my work supplied GCal. For authentication I use an access/refresh token (like this: https://developers.google.com/people/quickstart/python).
I want to run the script in Docker now. For authentication I have decided to use a service account.
I have created the service account, shared my calendar with it and accepted the calendar. In the Google Console where you create the service account, I set the permission to "owner".
When I try to run the script using the service account (not in Docker yet) it returns only a subset of attributes for each calendar event. I can see that accessRole = freeBusyReader.
How do I grant write access to this service account? I have tried:
rule = service.acl().get(calendarId="myId", ruleId='user:service#myApp-351310.iam.gserviceaccount.com').execute() # Get this from acl_items
rule["role"] = "owner"
service.acl().update(calendarId="myId", ruleId="user:service#myApp-351310.iam.gserviceaccount.com", body=rule).execute()
I have read about firmwide delegation and impersonation of users. I'm not sure if this is requred or not. Does anyone know how to do this?
The code to authenticate a service account is slightly different then the sample you were using for an installed application it is as follows.
credentials = ServiceAccountCredentials.from_json_keyfile_name(
key_file_location, scopes=scopes)
credentials = credentials.create_delegated(user_email)
This video shows How to create Google Oauth2 Service account credentials. just make sure to enable the google calendar api.
Remember service accounts are only supported via domain wide delegation to users on your google workspace domain. You cant use a standard google gmail user.
I recommend following the Delegate domain-wide authority to your service account sample it shows how to set up the delegation to a service account from your workspace domain. Just change out the section about admin sdk to that of google calendar as this is the api you are trying to connect to.
You add the user_Email being the user on your domain you want the service account to impersonate.
Is it possible to access the Google Admin Reports API via server to server Service Account authorization?
I am try to make a server to server call to the Google Admin API, following the tutorial here.
When setting domain-wide delegation, I added these scopes: https://www.googleapis.com/auth/admin.reports.usage.readonly, https://www.googleapis.com/auth/admin.reports.audit.readonly, as defined here.
I try making the API call like this, using the relevant PyPI packages:
creds = service_account.Credentials.from_service_account_file('credentials.json', scopes=SCOPES)
with build('admin', 'reports_v1', credentials=creds) as service:
response = service.activities().list(userKey='all', applicationName='login', maxResults=10).execute()
Which results in the following error:
googleapiclient.errors.HttpError: <HttpError 401 when requesting https://admin.googleapis.com/admin/reports/v1/activity/users/all/applications/login?maxResults=10&alt=json returned "Access denied. You are not authorized to read activity records.". Details: "[{'message': 'Access denied. You are not authorized to read activity records.', 'domain': 'global', 'reason': 'authError', 'location': 'Authorization', 'locationType': 'header'}]">
When I make the API call using a different credentials method, such as Desktop Application, the call works as expected. However, the first time I run it, I have to interact with it via browser to approve/authenticate the call. Because this code will be running on a server without user interaction, that is not desirable behavior.
As a note, the docs for the Admin API say
Your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
Based on the documentation for sever to server calls, I believe service accounts still qualify as OAuth 2.0, but I could be wrong in that assumption.
In Google Workspace domains, the domain administrator can grant third-party applications with domain-wide access to its users' data — this is referred as domain-wide delegation of authority. Perform Google Workspace Domain-Wide Delegation of Authority
The documentation even has a python example.
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
"""Email of the Service Account"""
SERVICE_ACCOUNT_EMAIL = '<some-id>#developer.gserviceaccount.com'
"""Path to the Service Account's Private Key file"""
SERVICE_ACCOUNT_PKCS12_FILE_PATH = '/path/to/<public_key_fingerprint>-privatekey.p12'
def create_reports_service(user_email):
"""Build and returns an Admin SDK Reports service object authorized with the service accounts
that act on behalf of the given user.
Args:
user_email: The email of the user. Needs permissions to access the Admin APIs.
Returns:
Admin SDK reports service object.
"""
credentials = ServiceAccountCredentials.from_p12_keyfile(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_PKCS12_FILE_PATH,
'notasecret',
scopes=['https://www.googleapis.com/auth/admin.reports.audit.readonly'])
credentials = credentials.create_delegated(user_email)
return build('admin', 'reports_v1', http=http)
Notice that user_email is the user you are acting on behalf of, not the service account email.
The error message Access denied. You are not authorized to read activity records. means that you have not properly set up delegation for the user. Contact your workspace admin and have them look into it.
I'm using a Google Service Account to upload videos using Resumable Method to Google Drive. The python code works well but I'm running into Google Service Account storage issue.
It seems like Google Service Account can only have 15 GB of storage. Even though I upload the video to a regular Google Drive folder, the video is still owned by the Service Account. Therefore, I tried to transfer the owner of the videos to a different account but it didn't work, the error is bad request. User message: \"You can't yet change the owner of this item. (We're working on it.)
Below is my python code that generate an access token from the service account and perform the Resumable Upload
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'creds.json',
scopes='https://www.googleapis.com/auth/drive'
)
delegated_credentials = credentials.create_delegated('service_account_email')
access_token = delegated_credentials.get_access_token().access_token
filesize = os.path.getsize(file_location)
# Retrieve session for resumable upload.
headers1 = {"Authorization": "Bearer " + access_token, "Content-Type": "application/json"}
params = {
"name": file_name,
"mimeType": "video/mp4",
"parents": [folder_id]
}
r = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable",
headers=headers1,
data=json.dumps(params)
)
location = r.headers['Location']
# Upload the file.
headers2 = {"Content-Range": "bytes 0-" + str(filesize - 1) + "/" + str(filesize)}
r = requests.put(
location,
headers=headers2,
data=open(file_location, 'rb')
)
Is there a workaround or increase the storage limit of the Google Service Accounts?
Any advice would be very appreciated. Thank you!
You want to use the Service Account to make a Resumable Upload to Drive.
You want the owner of the video not to be the Service Account, but a regular account which has enough Drive storage capacity.
If that's correct, then you can just have to delegate domain-wide authority to the Service Account, so that it can act on behalf of any user in the domain and, when uploading the file, impersonate the account you want to be the owner of the file.
Delegating domain-wide authority:
The process of granting domain-wide authority is explained here:
On the Service accounts page, select your Service Account, and while editing the SA, click SHOW DOMAIN-WIDE DELEGATION and, on the content that was just displayed, check the option Enable G Suite Domain-wide Delegation.
Once you've done this, go to the Admin console and then go to Main menu > Security > API Controls.
Select Manage Domain Wide Delegation in the Domain wide delegation pane, and click Add new.
Fill up the corresponding fields: (1) in Client ID, enter the SA's Client ID, which you can find both in the credentials JSON file and on the Service Account page, and (2) in OAuth scopes, add the scopes corresponding to the resources you want the SA to access on behalf of users in the domain. In this case, I guess that's just https://www.googleapis.com/auth/drive.
After clicking Authorize, you have conferred the Service Account the ability to access resources on behalf of any user in the domain.
Impersonating another user:
Now the Service Account impersonate any user in the domain, but you have to specify which user you want it to impersonate. In order to do that, you just have to do a small change in your code. Right now, you're setting the service_account_email when delegating credentials via create_delegated:
delegated_credentials = credentials.create_delegated('service_account_email')
That is, the Service Account is acting on behalf of the Service Account. If you didn't want to impersonate another account, there would be no real need for this line of code (it doesn't have any effect, since credentials and delegated_credentials both refer to the same account (the Service Account).
But since you want to use the Service Account to act on behalf of another account, you have to specify this other account's email address on this line:
delegated_credentials = credentials.create_delegated('user_account_email')
That's the only change you need to do in your code. If you have granted domain-wide delegation, the Service Account will act as if it was this other user. It will be like it was this other user who uploaded the file, so this user will be the owner of the file.
Note:
You are using a deprecated library (oauth2client). Since this is still working, there is no real need to do it now, but please consider changing your code to google-auth.
Reference:
Delegating domain-wide authority to the service account
I am new to Google API and currently working on adding forwarding email address using code. The code is as below.
credentials = get_credentials(request.data['code'], request.data['state'])
service = build_gmail_service(credentials)
address = {'forwardingEmail': 'abcd1234#mydomain.com'}
result = service.users().settings().forwardingAddresses().create(userId='me', body=address).execute()
I am able to build google service using the above code but when executing the last line which setting forwarding email address I am getting below error.
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/gmail/v1/users/me/settings/forwardingAddresses?alt=json returned "Access restricted to service accounts that have been delegated domain-wide authority">
I have searching for a solution for a day but not able to solve it so please let me know if any other have faced same issue and solved it.
Gsuite domain wise delegation image:
Thanks.
Access restricted to service accounts that have been delegated domain-wide authority
Its telling you that you are trying to connect to Admin settings api using a service account but have not properly set up domain wide deligation of the service account from gsuite.
Your gsuite admin will need to set up the delegation to your service account before you will be allowed to use it.
Delegating domain-wide authority to the service account
I am try to access dbm api , I am authenticating the url using service account please find the sample code below
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
from httplib2 import Http
scopes =['https://www.googleapis.com/auth/doubleclickbidmanager']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'path/to/key/.jsonfile', scopes=scopes)
http_auth = credentials.authorize(Http())
body={}
dbm = build('doubleclickbidmanager', 'v1', http=http_auth)
print dbm
request = dbm.lineitems().downloadlineitems(body=body).execute()
print request
If I use oauth mechanism to authenticate the url the code is running properly, since I don't want user interaction, I need server to server mechanism so I used service account
Steps which I tried:
I have created the service account and downloaded the json key file and used in the code but when I try to run my code it throws the following error:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/doubleclickbidmanager/v1/lineitems/downloadlineitems?alt=json returned "You are not authorized to use DoubleClick Bid Manager API. Please contact dbm-support#google.com.">
Please help , thanks in advance.
As others have said here, you want to log in to the DBM site and add your service account as a user:
Then, per this documentation, you can set up service account credentials using your client secrets json file. If you want that service account to be able to access reports you've created in DBM under your user account (what you log in with) you need to delegate domain-wide authority:
delegated_credentials = credentials.create_delegated('user#example.org')
http_auth = delegated_credentials.authorize(Http())
dbm = build('doubleclickbidmanager', 'v1', http=http_auth)
queries = dbm.queries().listqueries().execute()['queries']
A service account isn't you its a dummy user it has its on Google drive account for example, and by default it doesn't have access to any DoubleClick Bid Manager APIs. Service accounts need to be pre authorized to be able to access private data. So for it to be able to access your double click data you are going to have to grant it access.
Normally with any other API I would say you take the service account email address and add it as a user. I don't have access to double click so I am not even sure if you can add other users manually. They don't have anything in the documentation about service accounts kind of makes me think its not supported. Let us know if you manage to get it to work.