We have a Django application is hosted on GCP cloud run and sits behind IAP for user authentication. Our use case was to generate token on a local machine by a user and after getting the token. Followed IAP Programmatic authentication but was getting the following error.
Invalid IAP credentials: JWT audience doesn't match this application ('aud' claim (xxxxxxxx.apps.googleusercontent.com) doesn't match expected value (yyyyyyyy.apps.googleusercontent.com)
Expected result was a JSON response with token in it.
We solved the following issue by passing an 'audience' body param to the following code and tweaking original doc provided by GCP:
curl --verbose \
--data client_id=DESKTOP_CLIENT_ID \
--data client_secret=DESKTOP_CLIENT_SECRET \
--data code=AUTH_CODE \
--data redirect_uri=http://localhost:4444 \
--data audience=IAP_OAUTH_ID \
--data grant_type=authorization_code \
https://oauth2.googleapis.com/token
This IAP_OAUTH_ID is auto-generated by GCP when you turn on the IAP and is present under OAuth 2.0 Client IDs in APIs & services > Credentials section of GCP.
Our guess is when we try to generate token for IAP using our local machine without passing 'audience' in the body, it does generate token but for some other instance of IAP which obviously won't work with the one hosted on GCP, which is sitting in front of cloud run load balancer.
Therefore to make it work correct instance of IAP for which token is getting generated also has to be passed, which is done using the audience body param.
Related
I am trying to implement user authentication via JWTs in Google Cloud API Gateway.
I have configured the security requirement object and a security definitions object in the API config as per the documentation
securityDefinitions:
google_id_token:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://accounts.google.com"
x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs"
security:
- google_id_token: []
And the backend service is a Cloud Run service
x-google-backend:
address: https://my-apis-fskhw40mta-uk.a.run.app
However when I call the API with my user bearer token, I receive a 403 error and this error in the stackdriver logs
"jwt_authn_access_denied{Audiences_in_Jwt_are_not_allowed}"
The Python client code to call the API is
id_token = subprocess.run(['gcloud', 'auth', 'print-identity-token'], capture_output=True, text=True, shell=True).stdout
http = urllib3.PoolManager()
encoded_args = urlencode({'arg1': "val1"})
r = http.request(
'GET',
API_URL + "/run-api?" + encoded_args,
headers={"Authorization": f"Bearer {id_token}"}
)
What is the correct way to include an audience when using a User account (not service account)
Update 1
I have found one way to do it, however I'm not sure it is correct. If I add 32555940559.apps.googleusercontent.com
to the securityDefinitions so it looks like this
securityDefinitions:
google_id_token:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://accounts.google.com"
x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs"
x-google-audiences: "https://oauth2.googleapis.com/token, 32555940559.apps.googleusercontent.com"
It will allow unauthenticated access to Cloud Run, however I still can not call Cloud Run with authentication enabled. Cloud Run returns 403 error due to the API gateway service account not having permmissions - It has Cloud Run Invoker
Is there anything special I need to do to enable API Gateway to call cloud run other than granting Cloud Run Invoker
Adding 32555940559.apps.googleusercontent.com is not recommended, since this is the default. Ideally the audience should be unique for every service, which is why we normally use the service's own URL for this purpose. This prevents the tokens being reused, e.g. by a malicious or insecure server, to authenticate to other services which expect a different audience.
You can specify the audience you want to use when you create your identity token. For example: gcloud auth print-identity-token --audiences "https://service-acldswax.fx.gateway.dev"
You can specify the same audience in x-google-audiences to make this work. Alternatively, the service name prefixed with "https://" will be accepted by default. This can be specified as "host" in the API specification file and would normally be something like "api.example.com".
Note that anyone can generate a valid identity token, which will be accepted by the gateway. The gateway is performing /authentication/, but not /authorization/. You can either do authorization in the app, or for a private API you may wish to use a different oauth2 client.
When this is set up correctly you should be able to connect to the API gateway, but you will probably want your Cloud Run service to be locked down, to prevent the gateway from being bypassed. As you mentioned, the permission required to do this is included in the "Cloud Run Invoker" role, this needs to be granted to the gateway's service account on the Cloud Run service one of its containing resources (e.g. project, folder, organization).
I would suggest running the following commands to confirm/check the settings again :
Verify URL and API config in the gateway: gcloud api-gateway gateways describe $GATEWAY --location $REGION
Verify gateway config service account and backend URL (in base64 encoded document.contents): gcloud api-gateway api-configs describe --api $API $API_CONFIG --view FULL
Verify permission on Cloud Run service : gcloud run services --region $REGION get-iam-policy $SERVICE
I am using AWS sagemaker, and I have created an endpoint. I want to test endpoint on postman app. I give endpoint URL and JSON body to postman app. But I get this error that "message": "Missing Authentication Token" I need to know from where I 'll get bearer token so that I can give it to postman app.
I am answering my own question after searching and reading forums,
The easiest way to get bearer token is to install AWS CLI and configure it, using aws configure command.
For configuring, we must need to know access key, secret key, region of user. These things can be get by AWS users section.
After configuration by running this command, aws ecr get-authorization-token, we can get authorizationToken. here This token can be fed into bearer token, along with aws signature (access key and secret key) in authorization menu in Postman app.
I'm trying to get an OAuth2 token from google and keep getting this response:
{
"error": "invalid_grant",
"error_description": "Invalid JWT: Failed audience check. The right audience is https://oauth2.googleapis.com/token?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqb2Jpbmppc21pQGluZGlhLW5ldHN1aXRlLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic3ViIjoiaWxzZS5wcmFra2VuQHpvbm5lcGFuZaaaJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvY2FsZW5kYXIiLCJhdWQiOiJodHRwczovL29hdXRoMi5nb29nbGVhcGlzLmNvbS90b2tlbiIsImV4cCI6MTYxNTQ2MTU1OSwiaWF0IjoxNjE1NDU3OTU5fQ.HQ2nhaaaiB9b6jMq4l"
}
I need to access the google calendar API without user consent, so I have used the service account. I need to use the service account on the behalf of the application. I have given G Suite domain-wide authority to the service account for that I have Delegated domain-wide authority to the service account.
I followed all the steps defined in the google documentation
When I try to get an access token, I am getting an error. The error is
invalid grant: Invalid JWT: Failed audience check.
I am sending the request using the Postman:
curl --location --request POST 'https://oauth2.googleapis.com/token?grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUaaaIsInRIkpXVCIsImtpZCI6ImNkNjcwMzg4YzNhNjJiODBkZWJiNGQ2NmNiMzhiMDdhZDc5YjI0OWQifQ.eyJpc3MiOiJqd3Qtc2VydmljZS1hY2NvdW50QGp3dC1mb3ItY2FsZW5kYXIuaWFtLmdzZXJ2aWNlYWNjb3VaaaaaaiJmZWJpbkBqb2JpbmFuZGppc21pLmNvR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jYWxlbmRhciIsImF1ZCI6Imh0dHBzOi8vb2F1dGgyLmdvb2dsZWFwaXMaaaaNjE1NDY3NTcxLCJpYXjE2MTU0NjM5NzF9.NYwUaaaapxGmCWkUuEJurPWu5-vTrEpcL16g3lut8Z23p0R_jxOZZrYDA5lwDEjkqN0xxthvye7XBhvkpwRIn6kkydtw2p142O3aMczuK0wRV1RQmhO37oerKMPpZB8gpJf9RAL4BBNHx_CUgu4PN5TIaVw1raGWOoyfrwUnHyU8MFMHIfIBcm0h34GF9NfvBddSAfKPPqM0KsAZth4BHDa1ZYuYwXfRKQuJUZX1qpl6_z7Zlhl3Np4KShIvGaIAtd6OHR4EWDnV4pfzSDYy_JjCxRSbJ6-UDUKR86dLHuvpRlvMbrzJ07Gms47A' \
--header 'Content-Type: application/x-www-form-urlencoded'
Does anyone know what might be causing my audience check to fail and what I should be using as that value? Does anyone know where I am wrong for accessing the access token?
With gcloud I am logged into a terminal window with my email address, me#gmail.com. This project has the Gmail API enabled, and I am owner of this config. gcloud auth list shows
`Active Account`
`*me#gmail.com`
gcloud projects get-iam-policy $PROJECT shows that me#gmail.com as owner
I have an Oauth client/secret created in the project. My intent it to generate an access token to authenticate to the gmail API via the terminal with
`curl -H "Authorization: Bearer $(gcloud auth print-access-token)" https://gmail.googleapis.com/gmail/v1/users/me/labels`. (me is my actual email address)
Doing so gives me a 403. I can, however, use https://developers.google.com/oauthplayground/
and get a token with my particular scopes fine. Do I need to pass the Oauth Client Id to print-access-token? Why wouldn't owner have permissions over all possible actions in an API that's enabled?
EDIT: I have tried logging with auth application-default credentials as well with the same result.
TIA
You don't have the correct scope. You need to correctly scope your credential. Start by using this command to add the scope that you want in your credential
gcloud auth application-default login \
--scopes='https://mail.google.com/',\
'https://www.googleapis.com/auth/cloud-platform'
Then use the application-default access_token to call your service
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
https://gmail.googleapis.com/gmail/v1/users/me/labels`. (me is my actual email address)
It should work better.
I want to be able to invoke a GloudRun endpoint by one of my GKE pods.
When I describe my VMs/instances that comprise my GKE cluster, I see
serviceAccounts:
- email: 873099409230-compute#developer.gserviceaccount.com
So I added the CloudRun Invoker role to the above service account.
I have enabled CloudRun with Authentication Required.
However when I exec to one of my pods and try to curl the endpoint I get 403 (which I also get from my laptop, but the later is expected).
Any suggestions?
Curl don't know Google Cloud security. I mean that cURL don't know how to add the security token to your request. For this, you have to explicitly add the token in the header of your request.
From my computer I use this, because it's my personal account which is defined in Gcloud SDK.
curl -H "Authorization: Bearer $(gcloud config config-helper --format='value(credential.id_token)')" <URL>
With a service account defined in gcloud, you can use this command
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" <URL>
In both case you have to add the authorization header to your request.
In your code, if you use google libraries, you can use default credential, your default compute service-account will be used. cURL don't know do this!