如何为VM实例中的自定义Docker容器配置与Cloud Run一致的认证授权?
问题背景与需求
原Cloud Run部署场景
目前有一个需认证的Google Cloud Run(GC Run)实例,访问该实例需通过服务账号或持有访问令牌的用户身份认证,具体分为两种场景:
- 外部/Google服务调用:通过Google Console IAM获取服务账号凭据,用于外部后端程序的身份标识。当数据库内容变更时,该程序会向GC Run发起请求,核心代码如下:
const {URL} = require('url'); const googleAuthLib = require('google-auth-library'); const targetAudience = new URL(process.env.URL_OF_GCRUN_INSTANCE); const credentials = JSON.parse(process.env.CREDENTIALS_SECRET); const auth = new googleAuthLib.GoogleAuth({credentials}); const client = await auth.getIdTokenClient(targetAudience);
- 开发者测试调用:使用
gcloud auth print-access-token命令获取访问令牌,携带令牌发起请求。
两种场景下,凭据都需要具备「Cloud Run Invoker」权限才能成功访问实例。
迁移需求
计划将该GC Run实例迁移至Google Cloud VM实例中的容器(容器在指定端口如9091提供原服务),要求完全复用原GC Run的授权机制:
- 无需修改应用源代码
- 现有调用服务、开发者无需调整任何逻辑
解决方案
推荐以下几种无需修改应用代码的实现方式,均能复用原授权逻辑:
方式一:使用Cloud IAP(身份感知代理)保护VM容器服务
这是最贴合原Cloud Run认证逻辑的方案,步骤如下:
- 配置VM与Cloud IAP:
- 将VM实例加入到一个后端服务中,设置端口映射到容器的9091端口
- 启用Cloud IAP保护该后端服务,将访问权限配置为原「Cloud Run Invoker」对应的成员(服务账号或用户)
- 调整访问入口:
- 所有请求通过Cloud IAP的转发地址访问,而非直接访问VM的公网IP
- 兼容性验证:
- 外部服务原有代码无需修改:
getIdTokenClient会自动针对IAP的目标受众获取令牌,IAP会验证令牌的有效性和权限 - 开发者仍可使用
gcloud auth print-access-token获取令牌,在请求头中携带Authorization: Bearer <token>即可访问
- 外部服务原有代码无需修改:
方式二:在容器前部署轻量认证代理
如果不想依赖Cloud IAP,可在VM容器前添加一个轻量认证代理,负责验证请求中的令牌:
- 部署认证代理:
- 编写简单的Node.js/Go代理服务,监听VM的公网端口(如80),将合法请求转发到容器的9091端口
- 代理中使用Google Auth Library完成验证:
- 验证令牌的受众(Audience)可设置为原GC Run的URL或自定义的VM服务标识
- 验证令牌的颁发者为Google账号服务
- 检查令牌对应的身份是否具备「Cloud Run Invoker」权限
- 适配调用方:
- 外部服务只需将
targetAudience改为代理的URL,其余代码完全不变 - 开发者仍使用
gcloud auth print-access-token获取令牌,请求代理地址即可
- 外部服务只需将
方式三:Cloud Load Balancer + IAP(高可用场景)
如果需要更高的可用性和负载能力,可结合Cloud Load Balancer和IAP:
- 将VM实例作为负载均衡的后端服务,启用IAP保护负载均衡器
- 所有请求通过负载均衡器的IP/域名访问,IAP负责完成认证和授权,逻辑与方式一一致
内容的提问来源于stack exchange,提问作者Wer Bn
相关产品推荐
相关产品推荐

