8

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.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
luhu
  • 361
  • 3
  • 12

3 Answers3

6

I think you can check the specific firebase function. In the UI, the service account used should be listed.

By default, GCF functions all use <project_id>@appspot.gserviceaccount.com

wlhee
  • 2,334
  • 4
  • 18
  • 19
  • I already tried the mentioned address, but it does not work. What do you mean with "you can check the specific firebase function"? Where in the UI can I see the specific account for it? – luhu Jul 11 '20 at 06:47
  • 3
    In addition to this, make sure you read https://cloud.google.com/run/docs/authenticating/service-to-service, as adding permissions to the service account magically won't make it accessible only by that Function. The function needs to have code changes to add an identity token to the request that goes to Cloud Run. – ahmet alp balkan Jul 11 '20 at 19:12
  • this [answer](https://stackoverflow.com/questions/62850467/getsignedurl-when-using-cloud-functions) describes how to retrieve the firebase service account. Then, follow the link of @AhmetB-Google. You have to explicitly add an identity token to the header. Node lib is one of the easiest to use! Don't hesitate to ask if you are stuck – guillaume blaquiere Jul 11 '20 at 19:58
2

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(...);
luhu
  • 361
  • 3
  • 12
0

@luhu 's answer was really helpful. I'd like to add just one note for those whose are willing to test with the emulators locally first. The metadata server (which is actually http://metadata.google.internal now) as they state

does not work outside of Google Cloud, including from your local machine.

As a workarund, you can use the google-auth-library and then get the token directly if you prefer sticking with axios. Remember to set the GOOGLE_APPLICATION_CREDENTIALS env variable pointing to a service account secret first as it's the only way to make it work (I've tested setting the credential field during admin.initializeApp() but didn't seem to like it).

const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

const url_origin = '....'
const client = await auth.getIdTokenClient(url_origin);
const token = (await client.getRequestHeaders()).Authorization;
const url = '....'

const response = await axios.get(
  url,
  {
   headers: {
    Authorization: token,
   },
  }
);
Barnercart
  • 1,523
  • 1
  • 11
  • 23