Google Apps ScriptでCloud Functionsに実行制限付でアクセス 2021年版【GAS】
以前、Google Apps ScriptからCloud Functionsを実行する記事を書いたのですが、当時はCloud Functionsになぜか「実行制限」が標準で装備されておらず、Cloud Storageを利用した手法が公式からアナウンスされてる状態でした。
しかし、最近見てみたらIAMを利用した実行制限が装備されていたので、今回はこの標準で装備されてる実行制限を利用してCloud Functionsの関数を利用してみようと思います。
目次
今回使用するスプレッドシート等
前回のサンプルシートにコードを追加し、メニューを追加しています。今回実行するのは、gcf_check関数になります。
事前準備
プロジェクトを移動
図:プロジェクト変更画面
appscript.jsonの編集
appscript.jsonに以下のような感じで、oauthScopesを追加して起きます。appscript.jsonの表示は、サイドバーのプロジェクト設定より、「appsscript.json」マニフェスト ファイルをエディタで表示するにチェックを入れると表示されるようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "timeZone": "Asia/Tokyo", "dependencies": { }, "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8", "oauthScopes": [ "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/drive" ] } |
Cloud Functionの準備
まず、Cloud FunctionsでPuppeteerを利用できるようにします。事前に請求先アカウント、サービスアカウントが必要ですが、最初の200万回までは無償で利用が可能のようです。以下の手順で準備します。サービスアカウントは事前に作っておきましょう。
- 右上のハンバーガーメニュー(≡)をクリックし、サーバーレス項目にあるCloud Functionsをクリック
- 関数を作成をクリック
- 関数名を入れて、us-central1のリージョン、トリガーはHTTP、認証が必要にチェックが入った状態にする
- この時、URLが生成されてるのでコピーしておく
- 保存をクリックする
- 続けて下にある「ランタイム、ビルド、接続の設定」をクリック
- メモリは512MBを指定、使用するサービスアカウントの指定をして次へをクリック
- Cloud Build APIをオンにしろといわれるので、APIを有効化する
- ランタイムでは、今回はNode.js 12を指定、エントリポイントは最初に実行する関数名を指定します。今回はsecureFunctionとしました。
- これでとりあえず、準備は完了。とりあえずデプロイボタンを押します。但しこのデプロイは緑色のチェックマークがついたら成功なのですが、かなり時間が掛かります。
図:以前とだいぶUIが変わっている
図:サービスアカウントとRAMの指定
権限管理
この関数を実行できるアカウントを制限します。Cloud Functionsのプロジェクト一覧画面から行います。
- 自分が作成したプロジェクトのチェックを入れる
- 上部にある権限をクリック
- メンバーを追加をクリック
- 新しいメンバーに対象者のメアドを入れる
- ロールを選択をクリックし、Cloud Functions→Cloud Functions起動元を選ぶ
- 保存するをクリック
これで、オーナーである自分と追加したメンバーだけが実行できるようになります。
図:権限管理一覧
図:実行ユーザを追加
ソースコード
GAS側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
//cloud functionsの関数のURL var url = "ここにCloud FunctionsのURLを入力する"; //Cloud Functionsの関数を実行する function run_gcffunction() { //uiを取得 var ui = SpreadsheetApp.getUi(); //idtokenを取得する var idtoken = ScriptApp.getIdentityToken() //リクエストヘッダを構築 var header = { Authorization: "Bearer " + idtoken } //POSTで関数を実行する var response = UrlFetchApp.fetch(url, { method: 'POST', headers:header, muteHttpExceptions: true }); //サーバーレスポンスコードを取得する var resCode = response.getResponseCode(); //リターンされて来たバイナリデータをドライブに作成する if (resCode === 200) { //終了メッセージ ui.alert("GCFを実行できました\n" + response.getContentText()); }else{ //エラーメッセージ ui.alert(resCode + "エラーが発生しました。"); } }こ |
- 今回はいつものOAuth2.0認証ではなく、idtokenを利用してリクエストをしています。
- 取得したidtokenをheadersにて、Berer でAuthorizationとして含めます。
- あとはいつもどおり、POSTにてリクエスト。
- 成功するとresponsecodeの200が返ってくる。getContentTextにてGCF側からのレスポンス内容が取得できます。
GCF側コード
1 2 3 4 |
exports.secureFunction = (req, res) => { let message = req.query.message || req.body.message || 'Hello World!'; res.status(200).send(message); }; |
今回は特に何もやらせるわけではなく、使えるかどうかのテストなので、デフォルトのコードの関数名だけsecureFunctionに変更してるだけです。きちんと実行できれば、ステータスコード200が返ってきます。
実行結果
Google Workspaceでの注意点
Google Workspaceの場合権限で組織外のメンバーを入れてもデフォルトで実行できず、初回実行時の認証で403エラーが出ます。また、ファイルをコピーして、gmailアカウントで認証自体はできますが、権限を追加していても、実行すると401エラーが返ってきます。
Google Workspaceで使う場合には注意が必要です。詳細はこちらのページのドメインで制限された共有を参照してください。
図:403エラー
組織内メンバーが実行した場合
権限に組織内メンバーが追加されていれば、ステータスコード200が返ってきて無事にメッセージを受け取れます。これまでのような、OAuth認証で、Access Tokenを使った認証でも実行はできるので、どちらを利用するかはお好みで。
但し、APIキーでの簡易なアクセスは出来ないので、Power Automate Desktopなどからの利用の場合、OAuth2.0認証は大変なので、間にGoogle Apps Scriptで処理を挟んで、リクエストさせるようにすると良いと思います(但し運用は注意が必要.セキュリティ的には非推奨)
図:無事にGCFの実行結果を受け取れた