GCP Cloud Run部署Twitter自动化机器人遇认证错误求助
问题概述
正在开发基于GCP Cloud Run、Cloud Scheduler和Cloud Storage的Twitter自动化发推机器人。此前未将推文内容放在单独文件时代码可正常运行,部署后出现运行问题。执行gcloud run deploy前已准备好所有必要文件,Cloud Storage存储桶中已有surrealism.json和keyhole.json文件。
预期工作流程:指定时间到后,Cloud Scheduler触发Cloud Run程序;Cloud Run获取keyhole.json中的信息以运行代码;surrealism.json存储待发布的推文内容。若流程理解有误请指出。
错误信息
google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see https://cloud.google.com/docs/authentication/getting-started
相关代码
import random import tweepy import json import os from google.cloud import storage # Download service account key file from Google Cloud Storage storage_client = storage.Client() bucket = storage_client.bucket('rich_peoples_thing') blob = bucket.blob('keyfile.json') key_data = blob.download_as_string() # Load key data as JSON key_dict = json.loads(key_data) # Set environment variable for credentials os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = json.dumps(key_dict) # Download quotes file from Google Cloud Storage blob = bucket.blob('surrealism.json') quotes_data = blob.download_as_string() # Decode JSON data quotes = json.loads(quotes_data) # Authenticate with Twitter API auth = tweepy.OAuthHandler(api_key, api_secret) auth.set_access_token(access_token, access_token_secret) api = tweepy.API(auth) # Check if the list of quotes has already been tweeted if not quotes: api.update_status('Phase 1 completed') else: # Choose a random quote quote = random.choice(quotes) # Post the quote as a new tweet api.update_status(quote) # Remove the tweeted quote from the list quotes.remove(quote) # Encode quotes data as JSON quotes_data = json.dumps(quotes) # Upload updated quotes file to Google Cloud Storage blob.upload_from_string(quotes_data)
排查方向与修复方案
核心逻辑错误:凭证初始化顺序颠倒
代码中先创建storage.Client()再设置GOOGLE_APPLICATION_CREDENTIALS环境变量,此时客户端已尝试自动获取凭证,必然失败。正确顺序是先配置凭证再初始化客户端,但更优的方式是利用GCP的内置身份机制,无需手动处理密钥文件。禁止用Cloud Storage存储服务账号密钥
这是严重的安全风险,Cloud Run默认自带服务账号,只需给该账号配置Cloud Storage的读写权限即可:- 找到Cloud Run服务使用的默认服务账号(格式一般为
[你的项目ID]-compute@developer.gserviceaccount.com) - 给该账号添加针对
rich_peoples_thing存储桶的Storage Object Admin权限(或更细粒度的读写权限)
- 找到Cloud Run服务使用的默认服务账号(格式一般为
代码修复建议
删掉从Cloud Storage下载密钥文件及设置环境变量的代码段,直接用默认凭证初始化存储客户端:# 利用Cloud Run默认服务账号凭证初始化,无需手动配置 storage_client = storage.Client() bucket = storage_client.bucket('rich_peoples_thing')另外,Twitter API的密钥(
api_key、api_secret等)不要硬编码在代码中,应通过Cloud Run的环境变量配置,避免泄露。流程理解纠正
Cloud Run无需从Cloud Storage读取keyhole.json来运行代码,GCP内部通过服务账号身份认证实现权限控制,不需要手动下载密钥文件。
内容的提问来源于stack exchange,提问作者deandrehaijiel

