2
votes

I'm trying to access a secure cloud run service. If I try from my machine with the SDK it works fine:

curl --header "Authorization: Bearer $(gcloud auth print-identity-token)"

However, I can not get it to work using the Python API using the same service account, I've tried using google-auth to get an access token but that gives me a 401 authentication error. This is the code I am using to try to get a token:

import google.auth
import google.auth.transport.requests

scopes = ['https://www.googleapis.com/auth/cloud-platform']

creds, projects = google.auth.default(scopes=scopes)
auth_req = google.auth.transport.requests.Request()
creds.refresh(auth_req)

# then using creds.token 

Looking at the docs: https://cloud.google.com/run/docs/authenticating/service-to-service#calling_from_outside_gcp it says to follow the sample code here: https://cloud.google.com/iap/docs/authentication-howto#iap_make_request-python I can't seem to follow the guide as it says to enable IAP but it seems that IAP is only for app engine and not cloud run?

Has anyone go any advice on this one?

Thanks

2
I've also tried using AuthorizedSession with the credentials google-auth.readthedocs.io/en/latest/… this to gives a 401 errorDan
Your code is generating an Access Token. Cloud Run requires an Identity Token. Were are you running this code at? This changes possible answers and required permissions.John Hanley
I see now that I need an ID rather than Access token - i've used IDTokenCredentials to get that. ThanksDan
It also seems that I can not use a domain mapped to the cloud run service. Using the run.app generated domain works using a mapped domain gives a 401 error.Dan
You can use a custom domain. However, right now there seems to be an issue that is being investigated.John Hanley

2 Answers

6
votes

OK it seems that there is an IDTokenCredentials class that works for this as it uses Open ID Connect ID Tokens instead of OAuth 2.0 Access Tokens:

https://google-auth.readthedocs.io/en/latest/reference/google.oauth2.service_account.html

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession

service_url = 'example.com'
key_file = 'key.json'

credentials = service_account.IDTokenCredentials.from_service_account_file(
    key_file, target_audience=service_url)
authed_session = AuthorizedSession(credentials)
response = authed_session.get(service_url)

It's confusing as I don't see it in the docs and it's leading me to something else about IAP which I don't think is working with Cloud Run.

2
votes

If you still want to obtain your ID token and not use method from Dan's response there is an updated code:

import requests
import google.auth    
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession

service_url = 'example.com'
key_file = 'key.json'

credentials = service_account.IDTokenCredentials.from_service_account_file(
    key_file, target_audience=service_url)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
token = credentials.token
print('ID Token:', token)