We are trying to call a cloud function from apigeex via ILB protected by IAP. Currently we are seeing an error "Invalid IAP credentials: JWT 'email' claim isn't a string". Is there a shared flow or function that could generate JWT for IAP ? apigeex service account has been provided access in the "IAP: Secured Web App User" in the destination GCP project. could you please help on how to generate JWT from apigeex end?
thanks!!
Raghu
Solved! Go to Solution.
Invoking a Cloud Run or a Cloud Function through IAP, looks like this:
source: https://cloud.google.com/iap/docs/concepts-overview
Effectively you want IAP to receive an inbound authenticated request from Apigee, and then verify that identity, and if it is correct/valid, invoke the cloud Function (Cloud Run). Apigee needs to send a specially-formatted JWT to IAP in that request.
Is there a shared flow or function that could generate JWT for IAP ? apigeex service account has been provided access in the "IAP: Secured Web App User" in the destination GCP project. could you please help on how to generate JWT from apigeex end?
I recommend that you do not try to "manually" construct the JWT with a sharedflow or function etc. Apigee can generate the JWT for you in the correct format, if you use the Authentication element in the HTTPTargetConnection.
Here's what you need to do:
# get the service account for IAP
IAP_SA_EMAIL=service-${PROJECT_NUMBER}@gcp-sa-iap.iam.gserviceaccount.com
# allow it to invoke the service
gcloud run services add-iam-policy-binding "${CLOUD_RUN_SERVICE_NAME}" \
--member="serviceAccount:${IAP_SA_EMAIL}" \
--role='roles/run.invoker' \
--region="${REGION}" \
--project="$PROJECT"
gcloud compute backend-services list
BACKEND_SERVICE=....one.of.the.values.from.the.above....
# create a new SA that the proxy will run as *(optional if you already have one)
PROXY_SERVICE_ACCOUNT_NAME=my-apigee-proxy-sa
gcloud iam service-accounts create "${PROXY_SERVICE_ACCOUNT_NAME}"
PROXY_SERVICE_ACCOUNT_EMAIL="${PROXY_SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
# allow the SA to invoke the endpoint protected by IAP
gcloud iap web add-iam-policy-binding --service "${BACKEND_SERVICE}" \
--member="serviceAccount:${PROXY_SERVICE_ACCOUNT_EMAIL}" \
--role='roles/iap.httpsResourceAccessor' \
--resource-type=backend-services \
--project="$PROJECT_ID"
gcloud compute backend-services describe "${BACKEND_SERVICE}" \
--project="${PROJECT_ID}" \
--global \
--format="value(iap.oauth2ClientId)"
...
<HTTPTargetConnection>
<Authentication>
<GoogleIDToken>
<!-- replace this with the value you obtained above -->
<Audience>511582533367-vtrfdsroh4iv.apps.googleusercontent.com</Audience>
<IncludeEmail>true</IncludeEmail>
</GoogleIDToken>
</Authentication>
<URL>https://DNS-name-for-load-balancer.com/</URL>
</HTTPTargetConnection>
This configuration tells Apigee to generate an ID token, and send it to the target as a Bearer token in the Authorization header.
When you send a request to the proxy, Apigee generates a JWT and sends it to the target, which is an IAP-protected endpoint. IAP checks the Apigee-provided Identity, then invokes Cloud Run (Functions). Cloud Run then checks the IAP-provided identity. For maximum security, the cloud run service or cloud function should also check the Apigee-generated identity! But this is done in your own code, so it will vary depending on the language you use.
Invoking a Cloud Run or a Cloud Function through IAP, looks like this:
source: https://cloud.google.com/iap/docs/concepts-overview
Effectively you want IAP to receive an inbound authenticated request from Apigee, and then verify that identity, and if it is correct/valid, invoke the cloud Function (Cloud Run). Apigee needs to send a specially-formatted JWT to IAP in that request.
Is there a shared flow or function that could generate JWT for IAP ? apigeex service account has been provided access in the "IAP: Secured Web App User" in the destination GCP project. could you please help on how to generate JWT from apigeex end?
I recommend that you do not try to "manually" construct the JWT with a sharedflow or function etc. Apigee can generate the JWT for you in the correct format, if you use the Authentication element in the HTTPTargetConnection.
Here's what you need to do:
# get the service account for IAP
IAP_SA_EMAIL=service-${PROJECT_NUMBER}@gcp-sa-iap.iam.gserviceaccount.com
# allow it to invoke the service
gcloud run services add-iam-policy-binding "${CLOUD_RUN_SERVICE_NAME}" \
--member="serviceAccount:${IAP_SA_EMAIL}" \
--role='roles/run.invoker' \
--region="${REGION}" \
--project="$PROJECT"
gcloud compute backend-services list
BACKEND_SERVICE=....one.of.the.values.from.the.above....
# create a new SA that the proxy will run as *(optional if you already have one)
PROXY_SERVICE_ACCOUNT_NAME=my-apigee-proxy-sa
gcloud iam service-accounts create "${PROXY_SERVICE_ACCOUNT_NAME}"
PROXY_SERVICE_ACCOUNT_EMAIL="${PROXY_SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
# allow the SA to invoke the endpoint protected by IAP
gcloud iap web add-iam-policy-binding --service "${BACKEND_SERVICE}" \
--member="serviceAccount:${PROXY_SERVICE_ACCOUNT_EMAIL}" \
--role='roles/iap.httpsResourceAccessor' \
--resource-type=backend-services \
--project="$PROJECT_ID"
gcloud compute backend-services describe "${BACKEND_SERVICE}" \
--project="${PROJECT_ID}" \
--global \
--format="value(iap.oauth2ClientId)"
...
<HTTPTargetConnection>
<Authentication>
<GoogleIDToken>
<!-- replace this with the value you obtained above -->
<Audience>511582533367-vtrfdsroh4iv.apps.googleusercontent.com</Audience>
<IncludeEmail>true</IncludeEmail>
</GoogleIDToken>
</Authentication>
<URL>https://DNS-name-for-load-balancer.com/</URL>
</HTTPTargetConnection>
This configuration tells Apigee to generate an ID token, and send it to the target as a Bearer token in the Authorization header.
When you send a request to the proxy, Apigee generates a JWT and sends it to the target, which is an IAP-protected endpoint. IAP checks the Apigee-provided Identity, then invokes Cloud Run (Functions). Cloud Run then checks the IAP-provided identity. For maximum security, the cloud run service or cloud function should also check the Apigee-generated identity! But this is done in your own code, so it will vary depending on the language you use.