2
votes

I am trying to set up service to service authentication so an external application can make requests to a Cloud Run application (behind a Cloud Endpoints API gateway).

I have followed the Cloud Endpoints authentication between services documentation, however I continue to receive the following error when trying to reach the Cloud Run service:

401: Jwt issuer is not configured

Within the openapi spec, I have setup endpoint security and securityDefinition:

/endpoint_1:
  get:
     ...
     security:
       - service_account: []

securityDefinitions:
  service_account:
    authorizationUrl: ""
    flow: "implicit"
    type: "oauth2"
    x-google-issuer: "<service_account_email>"
    x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/<service_account_email>"
    x-google-audiences: "https://<cloud-run-service>-pjcfvhz2qq-uc.a.run.app"

This was then deployed to Cloud Run using ESPv2 Beta as described the Cloud Endpoints documentation.

After everything is deployed, I am trying to run the following script from my local machine to generate a signed jwt and make a request to the Cloud Run service:

import os
import json
import time
import requests
import google.auth.crypt
import google.auth.jwt

now = int(time.time())
expiry_length = 3600
sa_email = '<service_account_email>'

payload = {
    'iat': now,
    'exp': now + expiry_length,
    'iss': sa_email,
    'sub': sa_email,
    'email': sa_email,
    'aud': 'https://<cloud-run-service>-pjcfvhz2qq-uc.a.run.app',
}

file_path = "service-account.json"

signer = google.auth.crypt.RSASigner.from_service_account_file(file_path)
signed_jwt = google.auth.jwt.encode(signer, payload)

headers = {
    'Authorization': 'Bearer {}'.format(signed_jwt.decode('utf-8')),
    'content-type': 'application/json',
}

url = "https://<cloud-run-service>-pjcfvhz2qq-uc.a.run.app/endpoint_1"
res = requests.get(url, headers=headers)
print(res.json())

response of the get request:

{'message': 'Jwt issuer is not configured', 'code': 401}

The issuer has been specified on the openapi spec as the service account email which matches the issuer used with generating the JWT.

Any guidance on what Jwt issuer is not configured actually means, is appreciated.

2
@Chaos I have tried accounts.google.com as the issuer, after seeing that post, but without success. I also am not sure it's relevant to service accounts, but rather id tokens like what is provided from firebase auth.beano
I see you are basing the securityDefinitions: fields of the OpenAPI spec based on this information. Nonetheless, since you are using the ESPv2 Beta I think you should update those specs according to this documentation.Daniel Ocando

2 Answers

6
votes

I think you need a Google signed JWT token and not a self signed token. Try to change the end of your code with this (after your signed_jwt = ... line)

    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    params = {
        'assertion': signed_jwt, # You may need to decode the signed_jwt: signed_jwt.decode('utf-8')
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    }

    r = requests.post(auth_url, data=params)

    if r.ok:
        id_token = r.json()['id_token']

        headers = {
            'Authorization': 'Bearer {}'.format(id_token),
            'content-type': 'application/json',
        }

        url = "https://<cloud-run-service>-pjcfvhz2qq-uc.a.run.app/endpoint_1"
        res = requests.get(url, headers=headers)
        print(res.json())

    # For debugging
    print(r)
    print(vars(r))
0
votes

Did you deploy ESPv2 Cloud-Run service with the flag "--allow-unauthenticated"? If no, the ESPv2 cloud-run service is protected by IAM server, it will verify the JWT token and pass in a new token to ESPv2. ESPv2 will not recognize its issuer from the new token.

In order for ESPv2 JWT authentication to work, you have to disable IAM for ESPv2 cloud-run by passing the flag "--allow-unauthenticated" in "gcloud run deploy" command.