如何使用自行生成并上传的服务账号密钥完成GCP Go库认证?
如何使用自行生成的密钥对构建GCP服务账号凭据JSON并完成Golang SDK认证
一、可以自行构建服务账号凭据JSON,关键字段说明
GCP支持BYOK(自带密钥)场景,你可以基于自己生成的密钥对构建符合ADC格式的JSON文件,核心字段如下:
必填字段
type: 固定为"service_account"private_key: 你本地生成的PEM格式私钥(需将换行符转义为\n)client_email: 租户提供的目标服务账号邮箱(必须是租户上传公钥对应的服务账号)token_uri: 固定为"https://oauth2.googleapis.com/token"(默认宇宙域googleapis.com下)auth_uri: 固定为"https://accounts.google.com/o/oauth2/auth"auth_provider_x509_cert_url: 固定为"https://www.googleapis.com/oauth2/v1/certs"universe_domain: 固定为"googleapis.com"(若租户使用自定义宇宙域需调整)
建议补充字段(提升兼容性)
project_id: 租户服务账号所属的GCP项目IDprivate_key_id: 租户上传公钥后,GCP返回的密钥ID(需租户提供)client_id: 租户服务账号的客户端ID(可从租户处获取,或通过GCP API查询)client_x509_cert_url: 自动拼接格式为"https://www.googleapis.com/robot/v1/metadata/x509/{client_email}"(注意邮箱需URL编码,比如@转%40)
示例JSON
{ "type": "service_account", "project_id": "tenant-project-123", "private_key_id": "abc123xyz456", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...\n-----END PRIVATE KEY-----\n", "client_email": "my-service-account@tenant-project-123.iam.gserviceaccount.com", "client_id": "123456789012345678901", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my-service-account%40tenant-project-123.iam.gserviceaccount.com", "universe_domain": "googleapis.com" }
二、密钥对生成与租户协作步骤
- 生成密钥对:用OpenSSL生成RSA 2048/4096位密钥对
# 生成私钥 openssl genrsa -out private_key.pem 2048 # 导出公钥 openssl rsa -in private_key.pem -pubout -out public_key.pem - 租户上传公钥:让租户在GCP控制台操作:
- 进入IAM & Admin → 服务账号 → 选择目标账号
- 切换到「密钥」标签页 → 点击「添加密钥」→ 「上传公钥」
- 上传你的
public_key.pem,GCP会返回该密钥的ID(private_key_id),需租户提供给你
- 收集租户信息:向租户索要服务账号邮箱、项目ID、客户端ID(可选)
三、Golang SDK认证示例
你可以直接在代码中加载自定义的JSON凭据,或写入文件后通过环境变量指定:
代码中直接加载凭据
package main import ( "context" "encoding/json" "fmt" "cloud.google.com/go/storage" "golang.org/x/oauth2/google" "google.golang.org/api/option" ) func main() { // 替换为你的自定义凭据JSON credsJSON := []byte(`{ "type": "service_account", "project_id": "tenant-project-123", "private_key_id": "abc123xyz456", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...\n-----END PRIVATE KEY-----\n", "client_email": "my-service-account@tenant-project-123.iam.gserviceaccount.com", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my-service-account%40tenant-project-123.iam.gserviceaccount.com", "universe_domain": "googleapis.com" }`) // 解析凭据 creds, err := google.CredentialsFromJSON(context.Background(), credsJSON, storage.ScopeFullControl) if err != nil { panic(fmt.Errorf("解析凭据失败: %v", err)) } // 创建GCP客户端(以Storage为例) client, err := storage.NewClient(context.Background(), option.WithCredentials(creds)) if err != nil { panic(fmt.Errorf("创建Storage客户端失败: %v", err)) } defer client.Close() // 验证:列出租户项目下的存储桶 buckets, err := client.Buckets(context.Background(), "tenant-project-123") if err != nil { panic(fmt.Errorf("列出存储桶失败: %v", err)) } fmt.Println("存储桶列表:") for _, bucket := range buckets { fmt.Println(bucket.Name) } }
通过环境变量加载
将自定义JSON写入文件(比如custom-service-account.json),然后设置环境变量:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/custom-service-account.json"
之后Golang SDK会自动通过ADC机制加载该凭据。
四、为何GCP允许上传密钥对?
GCP支持上传自定义公钥是为了满足**BYOK(Bring Your Own Key)**场景需求:
- 企业需自行控制密钥生命周期,避免密钥由云服务商托管
- 密钥存储在本地或企业自有HSM(硬件安全模块)中,符合合规要求
- 支持跨云或混合云场景下的密钥复用
注意事项
- 私钥需严格保密,绝不泄露给租户或第三方
- 租户必须为服务账号授予对应GCP API的权限,否则你的微服务会因权限不足被拒绝
- 仅支持RSA算法(2048/4096位),暂不支持ECDSA等其他算法
- 若租户删除上传的公钥,你的私钥将无法再完成认证,需提前处理这种异常情况
内容的提问来源于stack exchange,提问作者Russel Vela
相关产品推荐
相关产品推荐

