Search code examples
firebasegoogle-cloud-platformgoogle-cloud-functionsgoogle-cloud-rungoogle-iam

Call Cloud Run from Cloud Function: IAM Authentication


I've deployed a small HTTP endpoint via Google Cloud Run. It is working fine when I turn off the authentication.

I now want to turn it on so that it is only callable by my Firebase Cloud Function. If I understand it right, I just have to add the correct service account mail address in the IAM settings of the Cloud Run as "Cloud Run invoker". But which address is the correct one?

I've tried all addresses that I have found in Firebase Console -> Project Settings -> Service Accounts.


Solution

  • Thanks to @AhmetB - Google and @whlee's answer I got it working. Basically it is enough adding an Authorization Bearer token to the request, which you can get from a special endpoint: https://cloud.google.com/run/docs/authenticating/service-to-service#nodejs

    Then you just have to add the service account of the function to the IAM list of the Cloud Run container: <project_id>@appspot.gserviceaccount.com

    The nodejs example is using the deprecated request library, so here is my version using axios:

        const getOAuthToken = async (receivingServiceURL: string): Promise<string> => {
    
          // Set up metadata server request
          const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
          const uri = metadataServerTokenURL + receivingServiceURL;
          const options = {
            headers: {
              'Metadata-Flavor': 'Google'
            }
          };
    
          return axios.get(uri, options)
            .then((res) => res.data)
            .catch((error) => Promise.reject(error));
        }
    

    Then you can just use the token in the actual request:

        const url = `...`;
        const token = await getOAuthToken(url);
    
        axios.post(url, formData, {
            headers: {
                Authorization: `Bearer ${token}`,
            }
        }).then(...).catch(...);