You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求无需向托管商暴露凭据的GCP服务账号认证优化方案

无需暴露GCP服务账号凭据的Cloud Function认证方案

针对你部署在Akash平台的Express服务需要调用GCP Cloud Function,但不想把服务账号凭据暴露给托管商的问题,以下是几个可行的方案:


方案1:使用工作负载身份联盟(Workload Identity Federation)

这是GCP官方推荐的无密钥认证方案,允许第三方平台(如Akash/Spheron)的服务直接通过身份联盟获取临时访问凭证,无需存储长期服务账号密钥。

配置步骤:

  1. 在GCP控制台创建工作负载身份池和对应的身份提供商,提供商类型选择「OpenID Connect(OIDC)」,填写Spheron/Akash提供的OIDC issuer URL(如果平台支持OIDC身份输出)。
  2. 为身份池中的身份绑定GCP IAM角色,授予调用目标Cloud Function的权限(比如roles/cloudfunctions.invoker)。
  3. 在Express服务的代码中,使用Google Auth库通过工作负载身份联盟认证,无需传入服务账号JSON:
var express = require("express");
var app = express();
require("dotenv").config();
const GoogleAuth = require("google-auth-library").GoogleAuth;
const cors = require("cors");

app.use(
  cors({ origin: process.env.ORIGIN, credentials: process.env.CREDENTIALS })
);

app.get("/hello", async function (req, res) {
  const auth = new GoogleAuth({
    // 使用工作负载身份联盟配置,无需硬编码凭据
    workloadIdentityPoolId: process.env.WORKLOAD_POOL_ID,
    providerId: process.env.WORKLOAD_PROVIDER_ID,
    audience: process.env.WORKLOAD_AUDIENCE,
    subjectToken: await getPlatformSubjectToken(), // 从Spheron/Akash获取当前实例的身份令牌
  });
  const url = process.env.RUN_APP_URL;

  const client = await auth.getIdTokenClient(url);
  const result = await client.request({ url });
  const resData = result.data;
  res.send(resData);
});

// 模拟从托管平台获取身份令牌的函数(具体实现需参考Spheron/Akash的文档)
async function getPlatformSubjectToken() {
  // 这里替换为平台提供的获取OIDC令牌的逻辑
  return process.env.PLATFORM_OIDC_TOKEN;
}

var server = app.listen(8081, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log("Example app listening at http://localhost:", port);
});

优势:

  • 无需存储长期服务账号密钥,托管商无法获取敏感凭据;
  • 临时凭证自动过期,降低泄露风险;
  • 符合GCP安全最佳实践。

方案2:将认证逻辑移至前端(类比Netlify静态客户端+Function模式)

如果你的应用架构允许,可让前端客户端直接完成身份认证并调用Cloud Function,Akash上的Express服务仅做路由转发或完全不参与认证流程:

配置步骤:

  1. 在GCP控制台配置Cloud Function的权限,允许经过Google OAuth/Firebase Auth认证的用户调用(添加allAuthenticatedUsers为cloudfunctions.invoker角色,或更精细的用户组权限)。
  2. 前端通过Google Sign-In或Firebase Auth获取ID Token,直接调用Cloud Function的HTTP端点:
// 前端示例代码(浏览器环境)
async function callCloudFunction() {
  const idToken = await firebase.auth().currentUser.getIdToken();
  const response = await fetch(process.env.CLOUD_FUNCTION_URL, {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${idToken}`
    }
  });
  const data = await response.json();
  return data;
}
  1. 如果需要Express服务做中间转发,仅需透传前端的ID Token,无需自身持有GCP凭据:
// 修改后的Express代码
app.get("/hello", async function (req, res) {
  const idToken = req.headers.authorization?.split(" ")[1];
  if (!idToken) {
    return res.status(401).send("Unauthorized");
  }
  const url = process.env.RUN_APP_URL;
  const result = await fetch(url, {
    headers: {
      "Authorization": `Bearer ${idToken}`
    }
  });
  const resData = await result.json();
  res.send(resData);
});

优势:

  • 后端服务完全不需要持有任何GCP凭据,彻底避免托管商访问敏感信息;
  • 符合静态前端+无服务器函数的架构模式,降低后端复杂度。

方案3:使用GCP Cloud Run作为中间代理(可选)

如果必须保留后端服务的认证逻辑,可将敏感的GCP认证逻辑迁移至GCP Cloud Run服务,Akash上的Express服务仅调用Cloud Run的公开接口,而Cloud Run通过内置的服务账号自动认证(无需手动存储凭据):

  1. 部署一个Cloud Run服务,内部完成调用Cloud Function的逻辑,Cloud Run使用默认服务账号(或自定义服务账号)并配置对应权限。
  2. Akash上的Express服务直接调用Cloud Run的HTTP端点,无需处理GCP认证:
// 修改后的Express代码
app.get("/hello", async function (req, res) {
  const cloudRunUrl = process.env.CLOUD_RUN_URL;
  const result = await fetch(cloudRunUrl);
  const resData = await result.json();
  res.send(resData);
});

优势:

  • 敏感认证逻辑完全在GCP生态内,第三方托管商无法接触;
  • Cloud Run自动处理服务账号认证,无需手动管理凭据。

内容的提问来源于stack exchange,提问作者ChristianOConnor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 03:30:40