
AWS Lambda からサービスアカウントで Google APIs を叩くまでにやったこと
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンサルティング部の西野です。
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 ロールを作成しておきます。
AWSLambdaBasicExecutionRoleAmazonSSMReadOnlyAccess
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)については後述します。
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) がお送りしました。






