我如何在 AWS Lambda 中从 Python 授权 Google API

How do I auth to Google API in AWS Lambda from Python

我有一些简单的 Python 代码 运行 作为 REST 服务,我用它来自动创建 Google 日历条目。代码的授权部分如下所示:

    store = file.Storage('token.json')
    creds = store.get()
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        creds = tools.run_flow(flow, store)
    calendar_service = build('calendar', 'v3', credentials=creds)

我正在尝试将其移至 AWS Lambda 函数。与 Lambda 函数相同的代码 运行 导致以下错误。

[ERROR] OSError: [Errno 30] Read-only file system: 'token.json'
Traceback (most recent call last):
  File "/function/app-google-calendar.py", line 54, in handler
    insert_result = calendar_service.events().insert(calendarId=MENU_CALENDAR_ID, body=new_event).execute()
  File "/function/googleapiclient/_helpers.py", line 131, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/function/googleapiclient/http.py", line 922, in execute
    resp, content = _retry_request(
  File "/function/googleapiclient/http.py", line 190, in _retry_request
    resp, content = http.request(uri, method, *args, **kwargs)
  File "/function/oauth2client/transport.py", line 186, in new_request
    credentials._refresh(orig_request_method)
  File "/function/oauth2client/client.py", line 761, in _refresh
    self._do_refresh_request(http)
  File "/function/oauth2client/client.py", line 802, in _do_refresh_request
    self.store.locked_put(self)
  File "/function/oauth2client/file.py", line 85, in locked_put
    f = open(self._filename, 'w')

根本原因似乎很清楚。也就是说,Lambda 文件系统是只读的。然而,我一直无法找到文档或示例来说明如何在不需要文件系统写入权限的情况下执行此 oauth 舞蹈。

使用 ssm 或 secrets manager 来存储凭据甚至环境变量比使用文件要好得多。这可能会变得复杂。

    parameter = client.get_parameter(Name='/Google/token', WithDecryption=True)
    print(parameter)
    return parameter ['Parameter']['Value']

在调试过程中,我遇到了一些其他奇怪的错误,在调查这些错误时发现我的根本原因是我的 Mac 和 Lambda 之间的架构不匹配。我在 docker build 命令中添加了 --platform=linux/amd64

这仍然不是我的原始文件系统 R/W JSON 令牌文件的问题。 /tmp 是可写的,但看起来它在映像启动时已被擦除干净,因此在构建映像时将凭据文件放在那里是行不通的。我最终将以下内容添加到 handler:

def handler(event, context):

    # Note moving token.json and credentials.json from same directory as python code to /tmp
    # because python code directory is not R/W and the Oauth dance to auth to google requires
    # the token file to be rewritten. Do this only if in lambda environment. We need to do this here and
    # not when the image is built, because /tmp seems to be wiped when the function image is starting
    if len(event) > 0:
        # We know we're in the lambda environment
        copyfile('/function/token.json', '/tmp/token.json')
        store = file.Storage('/tmp/token.json')
    else:
        # running locally
        store = file.Storage('token.json')