Cloud Run部署Flask应用遇google.auth.DefaultCredentialsError问题排查
Cloud Run Flask应用使用Secret Manager存储ServiceAccount密钥认证失败问题解决
问题描述
在Cloud Run上托管Flask Web应用,将ServiceAccount密钥(JSON文件)存储到Secret Manager中,代码获取密钥payload后通过os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = payload设置认证环境变量,部署后访问页面出现内部服务错误,日志报错:
File "/usr/local/lib/python3.10/site-packages/google/auth/_default.py", line 121, in load_credentials_from_file raise exceptions.DefaultCredentialsError( google.auth.exceptions.DefaultCredentialsError: File {"
使用gcloud secrets versions access 1 --secret="<secret_id>"命令可正常访问该密钥,怀疑是直接使用payload内容而非文件路径导致问题。
核心原因
GOOGLE_APPLICATION_CREDENTIALS环境变量要求的是ServiceAccount密钥文件的本地路径,而非密钥的JSON字符串内容。直接将JSON字符串赋值给该变量时,谷歌认证库会把这个字符串当作文件路径去读取,自然找不到对应文件,从而抛出错误。
解决方案
方法1:临时写入文件(快速验证方案)
将获取到的密钥内容写入临时文件,再将文件路径赋值给环境变量:
import tempfile import os from google.cloud import secretmanager # 从Secret Manager获取密钥 def access_secret_version(): client = secretmanager.SecretManagerServiceClient() # 替换为你的项目ID和Secret ID name = "projects/你的项目ID/secrets/你的Secret ID/versions/1" response = client.access_secret_version(request={"name": name}) payload = response.payload.data.decode("UTF-8") return payload @app.route('/page/page_two') def some_random_func(): payload = access_secret_version() # 创建临时JSON文件存储密钥内容 with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f: f.write(payload) temp_file_path = f.name os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = temp_file_path # 执行需要认证的操作... # 可选:操作完成后删除临时文件,Cloud Run实例销毁时会自动清理文件系统 os.unlink(temp_file_path)
方法2:直接构建认证凭证(推荐方案)
跳过环境变量,直接用密钥内容构建ServiceAccount凭证,避免文件操作:
import json from google.cloud import secretmanager from google.oauth2 import service_account # 从Secret Manager获取密钥 def access_secret_version(): client = secretmanager.SecretManagerServiceClient() name = "projects/你的项目ID/secrets/你的Secret ID/versions/1" response = client.access_secret_version(request={"name": name}) payload = response.payload.data.decode("UTF-8") return payload @app.route('/page/page_two') def some_random_func(): payload = access_secret_version() # 将JSON字符串解析为字典 service_account_info = json.loads(payload) # 根据业务需求添加权限范围 credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=["https://www.googleapis.com/auth/cloud-platform"] ) # 在调用Google服务时直接传入凭证 # 示例:初始化Cloud Storage客户端 # from google.cloud import storage # storage_client = storage.Client(credentials=credentials) # 后续业务逻辑...
方法3:Cloud Run最佳实践(无需手动管理密钥)
Cloud Run支持直接为服务分配ServiceAccount,自动提供身份认证,无需在代码中处理密钥:
- 登录GCP控制台,进入你的Cloud Run服务页面
- 点击「编辑 & 部署新修订版本」,切换到「容器、变量和秘密」标签
- 在「服务帐号」下拉框中选择一个拥有所需权限(如访问Secret Manager、目标GCP服务)的ServiceAccount
- 完成部署后,应用会自动使用该身份进行认证,无需任何密钥相关代码
内容的提问来源于stack exchange,提问作者user20977191
相关产品推荐
相关产品推荐

