【问题标题】:Calling (private) cloud function from cloud function从云函数调用(私有)云函数
【发布时间】:2022-02-22 20:43:59
【问题描述】:

我不断收到带有以下测试代码的 403。只是我还是在同一个项目中调用函数过于复杂?我做了一些研究herehere

我已在默认服务帐户上为这两个函数设置了云函数调用程序。还有allow internal traffic

所以我尝试了下面的两个代码。令牌在第一个函数中打印到日志中,为什么我仍然得到 403?

脚本1:

const axios = require("axios");
/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.helloWorld = async (req, res) => {
  console.log(JSON.stringify(process.env));

  const sample_api_url = `https://someRegionAndSomeProject.cloudfunctions.net/sample-api`;
  const metadataServerURL =
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=";
  const tokenUrl = metadataServerURL + sample_api_url;

  // Fetch the token
  const tokenResponse = await axios(tokenUrl, {
    method: "GET",
    headers: {
      "Metadata-Flavor": "Google",
    },
  });

  const token = tokenResponse.data;

  console.log(token);

  const functionResponse = await axios(sample_api_url, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
  });
  
  const data = functionResponse.data;
  console.log(data);
  res.status(200).json({ token, data });
};

脚本2:

const {GoogleAuth} = require('google-auth-library');
/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.helloWorld = async (req, res) => {

const url = 'https://someRegionAndSomeProject.cloudfunctions.net/sample-api';
const targetAudience = url;
const auth = new GoogleAuth();
const client = await auth.getIdTokenClient(targetAudience);
const response = await client.request({url});

res.status(200).json({data: response.data})

};

【问题讨论】:

    标签: node.js google-cloud-functions google-auth-library


    【解决方案1】:

    Cloud Functions 有 2 种类型的安全性

    • 基于身份的安全性:如果您在不使用 allow-unauthenticated 参数的情况下部署 Cloud Functions,则必须发送带有 Authorization: bearer <token> 标头的请求,其中 token 是至少具有云函数调用者角色的身份令牌.您还可以添加具有云函数调用者角色的 allUsers 用户,以使函数可公开访问(无需安全标头)
    • 基于网络的安全性:这一次,仅允许来自您的项目 VPC 或您的 VPC SC 的请求访问 Cloud Functions。如果您尝试从未经授权的网络访问云功能,则会收到 403(您的错误)。

    您可以根据需要组合这两种安全解决方案。在您的代码中,您正确添加了安全标头。但是,您的请求被网络检查拒绝了。


    解决方案不是那么简单,不是免费的,我完全同意你的观点,这种模式应该更简单。

    要实现这一点,您必须创建一个serverless VPC connector 并将其附加到执行调用的函数上。您还必须在该功能上设置egress to ALL。就是这样

    结果如下:来自您的函数的流量将通过无服务器 VPC 连接器路由到您的 VPC。 Cloud Functions URL 始终是公共 URL,您必须将出口设置为 ALL,才能通过无服务器 VPC 连接器将前往公共 URL 的流量路由。

    【讨论】:

    • 感谢您的解释。对我来说,选项 1 已经足够好了,而且改变奏效了。希望将来可以更轻松地使用它。
    【解决方案2】:

    根据您的帖子,我创建了一个适合我的示例。我创建了两个 GCP 函数“func1”和“func2”。然后,我确定了如何从 func1 调用 func2,其中 func2 仅公开以由 func1 运行的服务帐户身份调用。

    func1的最终代码如下:

    const func2Url = 'https://us-central1-XXX.cloudfunctions.net/func2';
    const targetAudience = func2Url;
    const {GoogleAuth} = require('google-auth-library');
    const auth = new GoogleAuth();
    
    async function request() {
      console.info(`request ${func2Url} with target audience ${targetAudience}`);
      const client = await auth.getIdTokenClient(targetAudience);
      const res = await client.request({url: func2Url});
      console.info(res.data);
      return res;
    }
    
    
    exports.func1 = async (req, res) => {
      let message = `Hello from func1`;
      try {
        let response = await request();
        res.status(200).send(`${message} + ${response.data}`);
      }
      catch(e) {
        console.log(e);
        res.status(500).send('failed');
      }
    };
    
    

    此处使用的主要配方如 Google 文档 here 中所述。我还发现这个medium article 很有帮助。

    【讨论】:

    • 感谢您的努力。我的问题是allow internal traffic only,就像@guillaume blaquiere 的回答一样
    猜你喜欢
    • 2019-01-18
    • 2017-08-04
    • 1970-01-01
    • 2021-06-04
    • 2019-06-01
    • 2021-10-04
    • 1970-01-01
    • 2021-09-12
    相关资源
    最近更新 更多