You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AWS Lambda函数中授权Google Drive API并解决只读文件系统问题?

问题描述

我正在编写一个与API网关集成的Lambda函数,需连接Google Drive。本地使用googleapiclient库的代码可正常运行,通过OAuth2及credentials.json、client_secret.json文件实现Google Drive连接。但将这些文件上传至Lambda后,代码报错提示文件系统只读,且代码正尝试写入credentials.json。请问如何解决该问题?能否将文件存储在S3等远程位置?或有无办法让认证代码无需修改credentials.json?

原代码:

from googleapiclient import discovery, errors
from googleapiclient.http import MediaIoBaseDownload, MediaFileUpload
from httplib2 import Http
from oauth2client import client, file, tools

credentials_file_path = './credentials.json'
clientsecret_file_path = './client_secret.json'

SCOPE = 'https://www.googleapis.com/auth/drive'

store = file.Storage(credentials_file_path)
credentials = store.get()

if not credentials or credentials.invalid:
    flow = client.flow_from_clientsecrets(clientsecret_file_path, SCOPE)
    credentials = tools.run_flow(flow, store)
http = credentials.authorize(Http())
drive = discovery.build('drive', 'v3', http=http)
解决方案

核心原因

Lambda的文件系统仅/tmp目录具备可写权限,其余目录均为只读。你的代码中file.Storage(credentials_file_path)会尝试将refresh token写入credentials.json,但默认路径不在/tmp,因此触发只读错误。


方案1:临时存储至Lambda的/tmp目录

将credentials.json的存储路径改为/tmp/credentials.json,该目录支持写入,但注意:

  • 函数执行结束后/tmp目录会被清理
  • 并发执行的Lambda实例拥有独立的/tmp,无法共享credentials

修改后的代码片段:

credentials_file_path = '/tmp/credentials.json'
clientsecret_file_path = './client_secret.json'  # client_secret.json无需修改,可放在代码包根目录

方案2:S3持久化存储credentials(推荐)

如果需要在多次函数调用间复用refresh token,可将credentials.json存储在S3,每次调用时下载至/tmp,更新后再上传回S3:

  1. 前置准备:

    • 将初始credentials.json上传至目标S3桶
    • 为Lambda执行角色添加S3的GetObject和PutObject权限
  2. 修改后的代码:

import boto3
from googleapiclient import discovery, errors
from googleapiclient.http import MediaIoBaseDownload, MediaFileUpload
from httplib2 import Http
from oauth2client import client, file, tools

# 配置S3信息
S3_BUCKET = 'your-bucket-name'
S3_CRED_KEY = 'credentials.json'
LOCAL_CRED_PATH = '/tmp/credentials.json'
clientsecret_file_path = './client_secret.json'
SCOPE = 'https://www.googleapis.com/auth/drive'

# 初始化S3客户端
s3 = boto3.client('s3')

# 从S3下载credentials到/tmp,不存在则创建空文件
try:
    s3.download_file(S3_BUCKET, S3_CRED_KEY, LOCAL_CRED_PATH)
except s3.exceptions.NoSuchKey:
    with open(LOCAL_CRED_PATH, 'w') as f:
        pass

store = file.Storage(LOCAL_CRED_PATH)
credentials = store.get()

if not credentials or credentials.invalid:
    flow = client.flow_from_clientsecrets(clientsecret_file_path, SCOPE)
    credentials = tools.run_flow(flow, store)
    # 将更新后的credentials上传回S3
    s3.upload_file(LOCAL_CRED_PATH, S3_BUCKET, S3_CRED_KEY)

http = credentials.authorize(Http())
drive = discovery.build('drive', 'v3', http=http)

方案3:使用服务账号替代用户OAuth2授权(无需写入credentials)

如果业务场景允许(比如访问服务账号自身Drive或共享文件),可以用服务账号认证彻底规避credentials写入问题:

  1. 前置准备:

    • 在Google Cloud控制台创建服务账号,下载服务账号密钥JSON文件
    • 将密钥文件放入Lambda代码包,或存储在S3/Secrets Manager
    • 给服务账号分配对应的Drive权限(如共享文件给服务账号邮箱)
  2. 修改后的代码:

from google.oauth2 import service_account
from googleapiclient.discovery import build

SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = './service-account-key.json'  # 放在代码包根目录,只读即可

credentials = service_account.Credentials.from_service_account_file(
    SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive = build('drive', 'v3', credentials=credentials)

注意:若需访问Google Workspace用户的Drive,需额外启用域范围授权。


内容的提问来源于stack exchange,提问作者Sarah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:10:43