Overcoming 401 on /compute/v1/projects/{project}/zones? - google-cloud-platform

Reverse-engineering the gcloud tool—with the suggested --log-http mostly—I was able to get auth tokens generated, and even selected the same scope (double checking at https://www.googleapis.com/oauth2/v1/tokeninfo):
http://[redacted]/callback?state=[redacted]&code=[redacted]&scope=email+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&authuser=0&prompt=consent
https://oauth2.googleapis.com:443/token?grant_type=authorization_code&code=[redacted]&redirect_uri=[redacted]/callback&client_id=[redacted]apps.googleusercontent.com&client_secret=[redacted]
Headers I try to hit the /zones/list endpoint with:
Content-Type: application/json
charset: utf-8
Authorization: Bearer [redacted]
X-Goog-User-Project: [redacted]
I've also tried putting access_token=[redacted] in my query string. But not matter what I do, I always get:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}
Other endpoints like like /projects/list seem to work with this access token (in header). What am I doing wrong?

As I see from the error message, you got 401 http status code. It means that the access token you used does not give you access (is not authorised) to list zones. And here you need to know that you cannot compare zone.list and projects.list. In fact:
zone.list is part of compute engine API, whereas projects.list is part of resource-manager API
zone.list requires compute.zones.list permission that is part of Compute Engine roles, like Compute Viewer whereas projects.list requires resourcemanager.projects.list which you'll find with many roles even the Browser role which is the smallest role (I think) in terms of number of permission.
To summarise, typically you used an access token of an identity which has access to projects.list but not to zone.list. Example this identity has only Browser role.
Then, there this sentence that caught my attention on how you are getting the access token:
Reverse-engineering the gcloud tool
You need to know that getting an access token is quite easy.
Run gcloud auth login which obtains access credentials for your user account via a web-based authorization flow.
Run gcloud auth print-access-token which prints an access token for your user account, so his permissions.
So if your user account has a role with compute.zones.list and resourcemanager.projects.list permissions (for example Compute Viewer role has both), you will be able to call both endpoints successfully.
Finally, here is a curl example, listing zones, using the generated access token:
curl -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json" https://compute.googleapis.com/compute/v1/projects/<PROJECT_ID>/zones

Turns out my original solution was 100% correct. For some odd reason the string being saved in the access token field of my struct was different to the one gathered from the remote auth flow.

Related

How to resolve "Access to requested resource is denied"?

I am getting the following when sending a marketplaceParticipations request to sellers/v1/marketplaceParticipations via Postman after following instructions and examples provided at https://developer-docs.amazon.com/sp-api/docs/connecting-to-the-selling-partner-api
{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "Unauthorized",
"details": ""
}
]
}
We have registered a self-authorized app client in Draft status which has a user ARN IAM attached as described at https://developer-docs.amazon.com/sp-api/docs/registering-your-application.Ï
I've checked the inline and role policies for the ARN IAM. They are exactly as described at https://developer-docs.amazon.com/sp-api/docs/creating-and-configuring-iam-policies-and-entities#step-4-create-an-iam-role.
We are able to successfully request an LWA access token following the docs at https://developer-docs.amazon.com/sp-api/docs/connecting-to-the-selling-partner-api#step-1-request-a-login-with-amazon-access-token.
Please check that the roles of the user you are using allow to make request to that endpoint in your dev profile at https://sellercentral.amazon.com/
As far as I know, the getMarketplaceParticipations doesn't need a Restricted Data Token (RDT). So you must be able to solve it by giving the user the correct roles.
I was able to get them using Postman. It is a good way to check that the request is correctly built and not a programming issue.

Google Cloud Storage API: can't generate access token, access denied

I'm new to Google APIs and I've been trying for days to use a service account to upload content to a Google Cloud Storage bucket. I'm able to accomplish this, but only with a temporary access token obtained from the Google API playground, and I need to be able to get new access tokens so the service account can always upload content.
I've been experimenting with the following, but I keep getting access denied, even though the account in question has 'owner' permissions.
curl -X POST / -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \ -H "Content-Type: application/json; charset=utf-8" \ -d #Documents/request.json \ https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/content-uploader#kol-hatorah-kulah.iam.gserviceaccount.com:generateAccessToken
response:
{ "error": { "code": 403, "message": "The caller does not have permission", "status": "PERMISSION_DENIED" } }
When I run gcloud config list I get the correct project, and the account is my work email, which is also in Google Cloud as an owner.
Thanks in advance!
DISCLAIMER - my solution works for Workload Identity Federation
related problems.
I've had hard time with this error, but finally found it!
For me it was wrong attribute mapping.
I was following some tutorial (which probably went outdated) and mapping was different than from official github action task documentation (here)
I had repository_owner and aud. Changed it for repository and...
It works!
To sum up my mapping looks like this:
"google.subject" = "assertion.sub"
"attribute.actor" = "assertion.actor"
"attribute.repository" = "assertion.repository"
So if you got here because of same tutorial... you've been served!
Your curl command is attempting to use a service account identity to generate an Access Token. The command is failing because you do not have permission.
Add the role roles/iam.serviceAccountTokenCreator to the identity running the command.

Google recommendations AI deleting catalog items error 403

I am trying to integrate my catalog into google recommendations ai, and for debugging purposes I want to be able to delete items from the catalog once imported. The documentations suggests running the following code:
curl -X DELETE \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
"https://retail.googleapis.com/v2/projects/[PROJECT_NUMBER]/locations/global/catalogs/default_catalog/branches/0/products/[PRODUCT_ID]"
which returns the following error:
{
"error": {
"code": 403,
"message": "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the retail.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.",
"status": "PERMISSION_DENIED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "SERVICE_DISABLED",
"domain": "googleapis.com",
"metadata": {
"service": "retail.googleapis.com",
"consumer": "[redacted for privacy]"
}
}
]
}
Running the suggested code with the --impersonate-service-account flag, results in the same error as above, but preceded with
WARNING: Impersonate service account '[name redacted for privacy]' is detected. This command cannot be used to print the access token for an impersonate account. The token below is still the application default credentials' access token.
If I attempt to log in for authorization instead of printing an access token, I get the following error:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
The link provided is no longer working. I would like to know how to provide proper authorization/authentication for deleting an item from the recommendation ai catalog.
PS. The account I am using to do this is the owner of the project, and as such should have all the appropriate permissions.
To set up authentication for your application of local cURL request to Recommendations AI. You have to create a Service Account, download SA key, and set the environment variable 'GOOGLE_APPLICATION_CREDENTIALS' to the key so allow your local cURL request noted in the original description
If you are unable to download a SA key file, I kindly suggest to try to use a ! before the curl like this, !curl -X POST , also if you are familiar with Python, it's recommended to use the python library for Recommendations AI.

cURL to GoogleCloud Vision API: Caller does not have required permission to use project foo

I'm following https://cloud.google.com/vision/docs/quickstart-cli
I've created a Google Cloud account, created a project, enabled Vision API, setup billing.
I now execute the cURL:
curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-H "X-Goog-User-Project: dragon-ocr-324006" \
https://vision.googleapis.com/v1/images:annotate -d #request.json
I get the response:
{
"error": {
"code": 403,
"message": "Caller does not have required permission to use project dragon-ocr-324006. Grant the caller the Owner or Editor role, or a custom role with the serviceusage.services.use permission, by visiting https://console.developers.google.com/iam-admin/iam/project?project=dragon-ocr-324006 and then retry (propagation of new permission may take a few minutes).",
"status": "PERMISSION_DENIED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developer console IAM admin",
"url": "https://console.developers.google.com/iam-admin/iam/project?project=dragon-ocr-324006"
}
]
},
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "USER_PROJECT_DENIED",
"domain": "googleapis.com",
"metadata": {
"consumer": "projects/dragon-ocr-324006",
"service": "vision.googleapis.com"
}
}
]
}
}
What does this mean? Who is the 'caller'?
When I do gcloud auth application-default login it lets me log in as, I guess, root user for my gcloud. And that must be the caller...?
So, I click that link, and get:
Permissions error... great! And now other pages give the same perms-error. So I have to repoint my browser to https://console.cloud.google.com/ and go in manually.
So, both root-user and project-user (if I got that right) have Owner permission.
So what is the problem.
Maybe my local machine doesn't have the updated profile for the project-user?
ok, so rm -rf ~/.config/gcloud and gcloud auth application-default login
Quick test: gcloud auth application-default print-access-token gives me an access token, great!
I rerun my crl.sh script and get the same problem.
Now here's the kicker. I've got another gcloud account I just created today, and if I run it on that one, it completes fine!
So what am I doing wrong on the first account?
Bear with me because you asked different questions :)
First:
Who is the 'caller'? When I do gcloud auth application-default login it lets me log in as, I guess, root user for my gcloud. And that must be the caller...?
It's normal that the error message is not referring a specific caller / identity. In fact, you are using an access token in your curl through gcloud auth application-default print-access-token. Access tokens are used to inform an API that the bearer of the token has been authorised to access the API. It doesn't hold any identity information.
Second:
That access token has been generated for you based on the credentials, you already setup as default credentials. You get these credentials in 2 ways
you run export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-file.json" But I think you didn't use this since you didn't evoke any key file.
you run gcloud auth application-default login, you had to go through a web flow, and the creadentials are generated and stored under ~/.config/gcloud/application_default_credentials.json
Third:
So, both root-user and project-user (if I got that right) have Owner permission.
ok, so rm -rf ~/.config/gcloud and gcloud auth application-default login
Here I understand that you changed the roles. So the initial role (set of permissions) given to the identity for which you generated the default credentials, was not enough.
Fourth:
You gave both users a large set of permissions (the Owner role has almost all permissions) Then you regenerated the default credentials.
But it did not work: because as stated in error message : (propagation of new permission may take a few minutes)
Finally:
When you came back with a new account it did work because he was already set with proper permissions. But if you retry with the old one it will work also, of course if you did not change his Owner role.
I had almost similar kind of issue when I was working on a Cloud Function in VS Code local development.In my case Application Default Credentials (ADC) was pointing to different service account which didn't had enough permission.
I followed the below steps to resolve this issue:
Executed these commands (locally) in Google Cloud SDK Shell
First list the current configuration to verify the config values
gcloud config list
This will output:
[accessibility]
screen_reader = False
[core]
account = <service_account>#appspot.gserviceaccount.com
disable_usage_reporting = True
project = ProjectId
Then I had to run a command to list all Credentialed Accounts
gcloud auth list
This will output the service accounts and an asterisk (*) at the beginning of an account which is active.
If this active service account is different than what is expected then must
activate the respective service account by running the following command.
gcloud auth activate-service-account <different_service_account>#appspot.gserviceaccount.com --key-file=PATH_TO_SERVICE_ACCOUNT_KEY_FILE
More details can be found here
Then restart the application resolved my issue.
Though this is not exactly the solution for this question, but definitely may help anyone who got into this error.

Cannot authenticate into google datastore through REST Api

I tried to access Google's Datastore through their REST Api. It says that they allow authentication through the API-key. However it doesn't seems that I can get it to work any where. I copied the snippet generated from their Try this API page.
curl --request POST \
'https://datastore.googleapis.com/v1/projects/PROJECT_ID:runQuery?key=[YOUR_API_KEY]' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"query":{"filter":{"compositeFilter":{"op":"AND","filters":[{"propertyFilter":{"property":{"name":"id"},"op":"EQUAL","value":{"stringValue":"ID"}}}]}},"kind":[{"name":"NAME"}]},"partitionId":{"namespaceId":"NAMESPACE_ID","projectId":"PROJECT_ID"}}' \
--compressed
But it keeps returning me an 401 error.
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
It looks like it require me to use OAuth instead, which is not what their documentation says. Anyone experienced something similar?
You are using an API key which is incorrect.
This link details which services support API Keys. Cloud Datastore is not one of them.
Using API Keys
You want to use an Access Token which is derived from Service Account credentials.
Review this document.
Using OAuth 2.0
The steps to generate an Access Token:
Load the service account credentials json file.
Extract the client_email, private_key and private_key_id.
Create a json payload.
Call the authorization URL: https://www.googleapis.com/oauth2/v4/token
This returns a json object. Extract the access_token.
Use the access_token instead of an API Key.
There are examples on the Internet in various languages. The link will get you started. The process appears complicated, and it is, but once you understand it, generating Access Tokens is easy and they can be reused until they expire (typically 60 minutes which you control).
This document on Google Cloud Storage authentication is the same for Cloud Datastore. The key is understanding "Authorization: Bearer" which is a header you need to include with your curl request.
Authentication