从 Cloud Function 调用 Cloud 运行:IAM 身份验证

Call Cloud Run from Cloud Function: IAM Authentication

我已经通过 Google 云 运行 部署了一个小型 HTTP 端点。当我关闭身份验证时它工作正常。

我现在想打开它,以便它只能由我的 Firebase 云函数调用。如果我理解正确,我只需在 Cloud 运行 的 IAM 设置中添加正确的服务帐户邮件地址作为“Cloud 运行 invoker”。 但是哪个地址是正确的?

我已经尝试了在 Firebase 控制台 -> 项目设置 -> 服务帐户中找到的所有地址。

我想你可以查看具体的firebase函数。在UI中,应列出使用的服务帐户。

默认情况下,GCF函数全部使用@appspot.gserviceaccount.com

感谢@AhmetB - Google 和@whlee 的回答,我让它工作了。基本上,向请求添加一个授权承载令牌就足够了,您可以从一个特殊的端点获得:https://cloud.google.com/run/docs/authenticating/service-to-service#nodejs

然后您只需将函数的服务帐户添加到 Cloud 运行 容器的 IAM 列表中:@appspot.gserviceaccount.com

nodejs 示例使用已弃用的请求库,所以这是我使用 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));
    }

那你就可以直接在实际请求中使用token了:

    const url = `...`;
    const token = await getOAuthToken(url);

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

@luhu 的回答很有帮助。对于那些愿意先在本地使用 模拟器进行测试的人 ,我想补充一点。元数据服务器(现在实际上是 http://metadata.google.internal)正如他们所说的那样

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

作为变通方法,您可以使用 google-auth-library,如果您更喜欢坚持使用 axios,则可以直接获取令牌。请记住首先将 GOOGLE_APPLICATION_CREDENTIALS env 变量设置为指向 service account 秘密,因为这是使其工作的唯一方法(我已经测试过在 admin.initializeApp() 期间设置 credential 字段但是好像不太喜欢)。

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,
   },
  }
);