I am trying to access a (GKE) application sitting behind IAP using the official GCP Python libraries and service account credentials.
The code is (taken from https://cloud.google.com/iap/docs/samples/iap-make-request)
from google.oauth2 import id_token
from google.auth.transport.requests import Request
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
requests.request(
"GET",
"https://myapp.com",
headers={"Authorization": "Bearer {}".format(open_id_connect_token)}
)
where client_id is the oauth client ID used by IAP (something like 8xxxxxxxxx.apps.googleusercontent.com) and the GOOGLE_APPLICATION_CREDENTIALS env var points to the JSON key file of a service account. The service account has the appropriate IAM permissions to access the IAP-protected application.
I've also added the following IAP settings using gcloud iap settings set SETTING_FILE --project=my-project where my-project is the project to which the IAP and the application belongs.
access_settings:
oauth_settings:
programmatic_clients: ["8xxxxxxxxx.apps.googleusercontent.com"]
I was mainly following this guide: https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_service_account
I would expect that the HTTP call made by request would yield a 2xx response, or at least reach the application. However, it returns 401 with the following error:
Invalid IAP credentials: Service Account doesn't match the authorized party for this application.
('sub' claim (1yyyyyyyyyyyyy) doesn't match expected value ([email protected]))
Here, the value 1yyyyyyyyyyyyy is actually the client_id property in the service account JSON file. So it looks like the token produced by the Python library (which calls https://oauth2.googleapis.com/token behind the scenes), has an unexpected combination of sub and azp. This is the payload of the token:
{
"aud": "8xxxxxxxxx.apps.googleusercontent.com",
"azp": "[email protected]",
"email": "[email protected]",
"email_verified": true,
"exp": 1696584237,
"iat": 1696580637,
"iss": "https://accounts.google.com",
"sub": "1yyyyyyyyyyyyy"
}
I have been trying the following, with no change of the outcome:
- use different service accounts (also from the same project as the IAP lives in)
- tried to add the service account's
client_idinto theaccess_settings.oauth_settings.programmatic_clientsconfiguration, but that is rejected bygcloud. - use different flags in the call of
gcloud iap settings set SETTING_FILE, e.g.--resource-type,--organization, or--service - find a way to influence the token payload by looking at the Python source code
Does anyone know how to obtain a token for a service account that is accepted by IAP?
In the end, I resorted to the following workaround:
Instead of using the Python SDK to generate the token, I use the
gcloudCLI, i.e.