Google Apps ScriptでCloud Functionsに実行制限付でアクセス 2021年版【GAS】

以前、Google Apps ScriptからCloud Functionsを実行する記事を書いたのですが、当時はCloud Functionsになぜか「実行制限」が標準で装備されておらず、Cloud Storageを利用した手法が公式からアナウンスされてる状態でした。

しかし、最近見てみたらIAMを利用した実行制限が装備されていたので、今回はこの標準で装備されてる実行制限を利用してCloud Functionsの関数を利用してみようと思います。

今回使用するスプレッドシート等

前回のサンプルシートにコードを追加し、メニューを追加しています。今回実行するのは、gcf_check関数になります。

事前準備

プロジェクトを移動

今回の発表直前の2019年4月8日より、Google Apps ScriptからCloud Platform Projectへ直接アクセスが出来なくなりました。これまでにデプロイしてるものについては、これまで通り「リソース」⇒「Google Cloud Platform API ダッシュボード」からアクセスが可能です。

今回の変更はスプレッドシート上で動かすスクリプトやGoogleの拡張サービスを利用しないタイプのスクリプトであれば特に問題はありませんが、「Apps Script API」や「Google Picker API」、「Cloud SQL接続」などGCP上のAPIを利用する場合には以下の手順を踏んで、Google Apps Scriptにプロジェクトを連結する必要があります。これまでは、自動的にGCP上にGoogle Apps Script用のプロジェクトが生成されていたのですが、今後は自分の組織(もしくはGCPプロジェクト)上で作成されたプロジェクトでなければならないということです。詳細はこちらのページを見てください。

連結する手順は以下の通り

  1. Google Cloud Consoleを開く
  2. 左上にある▼をクリックする
  3. ダイアログが出てくるので、新規プロジェクトを作るか?既存のプロジェクトを選択する。この時、Google Workspaceであれば選択元は「自分のドメイン」を選択する必要があります。
  4. プロジェクト情報パネルから「プロジェクト番号」をコピーする
  5. 対象のGoogle Apps Scriptのスクリプトエディタを開く
  6. サイドバーからプロジェクト設定を開く
  7. プロジェクトを変更ボタンをクリック
  8. GCPのプロジェクト番号に、4.の番号を入れてプロジェクトを設定をクリック

今回のこの変更だと1つ作ったプロジェクトに集約する必要があるので、クォータについてプロジェクト毎のカウントだったので問題なかったものが、集約されることで、クォータに引っ掛かる可能性があります。

図:プロジェクト番号をコピーしておきます

図:プロジェクト変更画面

appscript.jsonの編集

appscript.jsonに以下のような感じで、oauthScopesを追加して起きます。appscript.jsonの表示は、サイドバーのプロジェクト設定より、「appsscript.json」マニフェスト ファイルをエディタで表示するにチェックを入れると表示されるようになります。

{
  "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万回までは無償で利用が可能のようです。以下の手順で準備します。サービスアカウントは事前に作っておきましょう。

  1. 右上のハンバーガーメニュー(≡)をクリックし、サーバーレス項目にあるCloud Functionsをクリック
  2. 関数を作成をクリック
  3. 関数名を入れて、us-central1のリージョン、トリガーはHTTP認証が必要にチェックが入った状態にする
  4. この時、URLが生成されてるのでコピーしておく
  5. 保存をクリックする
  6. 続けて下にある「ランタイム、ビルド、接続の設定」をクリック
  7. メモリは512MBを指定、使用するサービスアカウントの指定をして次へをクリック
  8. Cloud Build APIをオンにしろといわれるので、APIを有効化する
  9. ランタイムでは、今回はNode.js 12を指定、エントリポイントは最初に実行する関数名を指定します。今回はsecureFunctionとしました。
  10. これでとりあえず、準備は完了。とりあえずデプロイボタンを押します。但しこのデプロイは緑色のチェックマークがついたら成功なのですが、かなり時間が掛かります。

図:以前とだいぶUIが変わっている

図:サービスアカウントとRAMの指定

権限管理

この関数を実行できるアカウントを制限します。Cloud Functionsのプロジェクト一覧画面から行います。

  1. 自分が作成したプロジェクトのチェックを入れる
  2. 上部にある権限をクリック
  3. メンバーを追加をクリック
  4. 新しいメンバーに対象者のメアドを入れる
  5. ロールを選択をクリックし、Cloud Functions→Cloud Functions起動元を選ぶ
  6. 保存するをクリック

これで、オーナーである自分と追加したメンバーだけが実行できるようになります。

図:権限管理一覧

図:実行ユーザを追加

ソースコード

GAS側コード

//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側コード

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の実行結果を受け取れた

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)