AWS Lambda からサービスアカウントで Google APIs を叩くまでにやったこと

Google APIs を完全に理解したい人生だった。
2020.06.29

コンサルティング部の西野です。

AWS Lambda からサービスアカウントを使用して Google APIs を叩く機会がありましたので、その手順を紹介します。

やりたいこと

G Suite ドメイン内のユーザーによって Google Drive 上に保存されたファイルの名称を AWS Lambda 経由で取得することをゴールとします。

構成図

  • server-to-server (Lambda to Google API) で API をコールするためサービスアカウントを用いる
  • AWS リージョンはアジアパシフィック(東京)/ ap-northeast-1 を使用
  • API コール用のサービスアカウントキーを SSM Parameter Store に SecureString として保存する
  • Lambda 関数のランタイムは Python 3.8
  • Lambda 関数は実行のたびにサービスアカウントキーを Parameter Store から取得する(①&②)
  • API コールにはgoogle-api-python-clientを使用する(③)

サービスアカウントの作成と権限の設定

サービスアカウントの作成

まずは API コールに必要なサービスアカウントを作成していきます。

以下の作業は G Suite の管理者権限を持つアカウントから実施してください。

下記のページにアクセスし、プロジェクトを作成します。
Google APIs | リソースの管理

プロジェクト名は任意のものでOKです。

つづいてこのプロジェクトにサービスアカウントを作成します。

ハンバーガーボタン(画面左上) -> APIとサービス -> 認証情報 とクリックしてください。

次の画面で 認証情報を作成 -> サービスアカウント をクリックしてください。

任意のサービスアカウント名を付与し、作成をクリックしてください。

この画面では何も入力せずに 続行 をクリックします。

この画面でも何も入力せずに 完了 をクリックしてください。

サービスアカウントキーの作成

作成したサービスアカウントの右側にペンのマークがあるので、ここをクリックします。

鍵を追加 -> 新しい鍵を作成 をクリックします。

JSON にチェックを入れた後、作成をクリックします。JSON ファイルダウンロード用のダイアログが出現しますのでそのままダウンロードしてください。 当該 JSON には API コールのためのキーが含まれていますので、流出等にご注意ください。

権限(ドメイン全体の委任)の設定

続いてサービスアカウントに対して権限(ドメイン全体の委任)を設定していきます

Google の管理コンソールへアクセスし、セキュリティをクリックしてください。
管理コンソール

画面下部のAPI 権限 -> ドメイン全体の委任を管理 をクリックしてください。

新しく追加 をクリックします。

APIのクライアント ID と OAuth スコープ(https://www.googleapis.com/auth/drive)を入力します。
※クライアント ID は先ほどダウンロードした JSON ファイルに記載されている21桁の番号です。
入力が済んだら「承認」をクリックします。

ここまで Google 上での設定は完了です。

Parameter Storeへサービスアカウントキーを保存

サービスアカウントキーを Parameter Store に保存します。

名前 タイプ
Google-API-Credential 完全な文字列 (SecureString) サービスアカウント作成時にダウンロードした JSON

IAMロールの作成

IAM ロールは Lambda 関数の実行および Parameter Store からのパラメータ取得に必要です。
事前に下記の AWS 管理ポリシーを持つ Lambda 用の IAM ロールを作成しておきます。

  • AWSLambdaBasicExecutionRole
  • AmazonSSMReadOnlyAccess

Lambda関数の作成

Google Client Library のインストール(ローカル開発環境)

Python Quickstartを参考に必要なライブラリをインストールします。

後に Lambda 関数にアップロードするため、-tオプションを付与しインストール先をカレントディレクトリ以下にしています。

$ pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib -t ./

コード

Google Drive 上にアップロードされたファイル名を取得するためのコードです。

3つの環境変数(REGION・SUBJECT・PARAM_KEY)については後述します。

lambda_function.py

import json
import os
import boto3
from google.oauth2 import service_account
from googleapiclient.discovery import build

REGION = os.environ.get('REGION')
SUBJECT = os.environ.get('SUBJECT')
PARAM_KEY = os.environ.get('PARAM_KEY')
SCOPES = ['https://www.googleapis.com/auth/drive']

def lambda_handler(event, context):
    param_value = get_parameters(PARAM_KEY)

    service_account_info = json.loads(param_value)
    credentials = service_account.Credentials.from_service_account_info(
        service_account_info, scopes=SCOPES)
    
    delegated_credentials = credentials.with_subject(SUBJECT)
    service = build('drive', 'v3', credentials=delegated_credentials, cache_discovery=False)
    results = service.files().list(
        pageSize=10, fields="nextPageToken, files(id, name)").execute()

    items = results.get('files', [])
    for item in items:
        print(item['name'])

def get_parameters(param_key):
    ssm = boto3.client('ssm', region_name=REGION)
    response = ssm.get_parameters(
        Names=[
            param_key,
        ],
        WithDecryption=True
    )
    return response['Parameters'][0]['Value']
    

zip ファイルの作成

下記コマンドでカレントディレクトリ以下のすべてのファイルを zip ファイル化します。
※カレントディレクトリ以下には上述のコードと依存ライブラリのすべてが配置されている前提です。

$ zip -r lambda_function.zip ./*

Lambda 関数の設定

下記の設定で Lambda 関数を作成します。

  • ランタイム: Python3.8
  • IAMロール: 先の手順で作成した IAM ロール
  • タイムアウト時間: 15秒(実行に3秒以上かかったためデフォルト値から変更)
  • 環境変数
    • REGION: ap-northeast-1
    • SUBJECT: G Suite ドメイン内ユーザーのメールアドレス
    • PARAM_KEY: Google-API-Credential

zip ファイルのアップロード

Lambda関数 -> 関数コード -> アクション ->.zip ファイルをアップロード をクリックし、先の手順で作成した zip ファイルを Lambda 関数にアップロードします。

動かしてみる

任意のテストイベントを作成し、Lambda 関数を実行してみます。

ラー油とペットの画像ファイル名をしっかり取得できました。

終わりに

このブログがほんの少しでも世界を良くできれば嬉しいです。 コンサルティング部の西野(@xiyegen)がお送りしました。

参考ブログ