GCP基于服务账号的服务器间认证:Django权限验证问询
我们在GCP上运行两个Django后端应用A和B,均提供Web可访问的URL,多数端点需登录访问。需求是让B的/server-secure安全端点仅对A开放,且要验证请求确实来自A。目前已经能通过Google Auth Python库生成并解码实例令牌,核心问题是:除了解码令牌后校验email字段匹配指定服务账号外,是否有更优方案?能否通过创建access-to-server-B这类自定义角色,仅允许拥有该角色的服务账号发起的请求通过?
更优方案:替代硬编码服务账号邮箱的校验方式
直接校验令牌的email字段虽然可行,但硬编码邮箱会导致后续维护不便(比如更换服务账号需要改代码)。更可靠的方案有两种:
1. 校验令牌的azp字段
令牌中的azp(Authorized Party)字段是令牌的授权对象标识,对应发起请求的服务账号的邮箱或唯一ID,由Google认证颁发,比email字段更精准(避免服务账号别名导致的匹配问题)。解码令牌后直接校验azp是否为应用A的服务账号标识即可。
2. 自定义角色+IAM权限校验(推荐)
这是最灵活、符合GCP最佳实践的方案,完全可以创建access-to-server-B自定义角色,通过IAM权限校验来控制访问:
步骤1:创建自定义IAM角色
在GCP控制台的IAM角色页面,创建名为access-to-server-B的自定义角色,添加一个自定义权限(比如custom.serverB.access)——这个权限不需要绑定GCP原生服务的操作,仅作为我们应用层面的权限标识。
步骤2:给应用A的服务账号授予该角色
在IAM中找到应用A对应的服务账号,将access-to-server-B角色绑定到该账号上。后续如果要新增/移除访问权限,直接在IAM中调整绑定即可,无需修改代码。
步骤3:在应用B中实现权限校验逻辑
解码令牌后,调用GCP IAM的testIamPermissions API,检查发起请求的服务账号是否拥有custom.serverB.access权限:
from google.cloud import iam_v2 from google.oauth2 import id_token import google.auth.transport.requests import os def has_server_b_access(token): request = google.auth.transport.requests.Request() try: # 解码令牌,验证合法性并获取服务账号信息 token_info = id_token.verify_token(token, request, audience="https://your-app-b-domain.com") service_account_email = token_info.get("email") if not service_account_email: return False except ValueError: # 令牌无效 return False # 初始化IAM客户端 client = iam_v2.IamClient() # 构建服务账号的资源路径 project_id = os.getenv("GCP_PROJECT_ID") resource = f"projects/{project_id}/serviceAccounts/{service_account_email}" # 要校验的自定义权限 target_permission = "custom.serverB.access" # 调用IAM权限校验API response = client.test_iam_permissions( request={"resource": resource, "permissions": [target_permission]} ) # 返回是否拥有指定权限 return target_permission in response.permissions
注意事项
- 应用B运行所使用的服务账号,需要拥有
iam.serviceAccounts.testIamPermissions权限,可以给它授予roles/iam.serviceAccountViewer角色,或者自定义包含该操作的角色。 - 生成令牌时,
target_audience要设置为应用B的实际URL(比如https://your-app-b-domain.com),而不是示例中的PubSub地址,这样令牌是专门针对B的,能避免被滥用。
方案优势对比
| 方案 | 优势 | 劣势 |
|---|---|---|
硬编码校验email | 实现简单,无额外API调用 | 维护不便,更换服务账号需改代码 |
校验azp字段 | 精准可靠,无额外API调用 | 仍需硬编码标识,权限调整需改代码 |
| 自定义角色+IAM校验 | 权限管理灵活,无需硬编码,符合GCP最佳实践 | 需要调用IAM API,增加少量延迟 |
内容的提问来源于stack exchange,提问作者Harith

