从云功能调用(私有)云功能
Calling (private) cloud function from cloud function
使用下面的测试代码,我一直收到 403。在同一个项目中调用一个函数是只有我一个人还是太复杂了?我做了一些研究 and 。
我已经在这两个函数的默认服务帐户上设置了云函数调用程序。而 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})
};
基于您的 post,我创建了一个适合我的示例。我创建了两个 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. I also found this medium article 有帮助。
Cloud Functions 有两种安全类型
- 基于身份的安全性:如果您在没有 allow-unauthenticated 参数的情况下部署 Cloud Functions,则必须发送带有
Authorization: bearer <token>
header 的请求,其中令牌是身份令牌至少具有云函数调用者角色。您还可以添加具有云函数调用者角色的 allUsers
用户,使函数 public 可访问(不需要安全性 header)
- 基于网络的安全性:这次,只有来自您的项目 VPC 或您的 VPC SC 的请求才允许访问 Cloud Functions。如果您尝试从未经授权的网络访问云功能,您会收到 403(您的错误)。
如果需要,您可以结合使用这两种安全解决方案。在您的代码中,您正确地添加了安全性 header。但是,您的请求被网络检查拒绝。
解决方案不是那么简单,不是免费的,我完全同意你的看法,这种模式应该更简单。
为此,您必须在该函数上创建一个 serverless VPC connector and attach it on your functions that perform the call. You also have to set the egress to ALL。就这些了
结果如下:由于无服务器 VPC 连接器,来自您的函数的流量将被路由到您的 VPC。 Cloud Functions URL 始终是 public URL,您必须将出口设置为 ALL,以便通过无服务器路由前往 public URL 的流量VPC 连接器。
使用下面的测试代码,我一直收到 403。在同一个项目中调用一个函数是只有我一个人还是太复杂了?我做了一些研究
我已经在这两个函数的默认服务帐户上设置了云函数调用程序。而 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})
};
基于您的 post,我创建了一个适合我的示例。我创建了两个 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. I also found this medium article 有帮助。
Cloud Functions 有两种安全类型
- 基于身份的安全性:如果您在没有 allow-unauthenticated 参数的情况下部署 Cloud Functions,则必须发送带有
Authorization: bearer <token>
header 的请求,其中令牌是身份令牌至少具有云函数调用者角色。您还可以添加具有云函数调用者角色的allUsers
用户,使函数 public 可访问(不需要安全性 header) - 基于网络的安全性:这次,只有来自您的项目 VPC 或您的 VPC SC 的请求才允许访问 Cloud Functions。如果您尝试从未经授权的网络访问云功能,您会收到 403(您的错误)。
如果需要,您可以结合使用这两种安全解决方案。在您的代码中,您正确地添加了安全性 header。但是,您的请求被网络检查拒绝。
解决方案不是那么简单,不是免费的,我完全同意你的看法,这种模式应该更简单。
为此,您必须在该函数上创建一个 serverless VPC connector and attach it on your functions that perform the call. You also have to set the egress to ALL。就这些了
结果如下:由于无服务器 VPC 连接器,来自您的函数的流量将被路由到您的 VPC。 Cloud Functions URL 始终是 public URL,您必须将出口设置为 ALL,以便通过无服务器路由前往 public URL 的流量VPC 连接器。