Google Cloud Functions から Google Workspaces のユーザー一覧を取得するときにうまくいかない
TL;DR
- Google Cloud Functions の role に service account を指定し
- Application Default Credentials を使用して
- Google Workspaces の Admin SDK の users.list を呼び出すとうまくいかない
解決策として、 ドメイン全体の委任がないサービス アカウントとして認証する。具体的には 特定の管理者ロールを割り当てる - Google Workspace 管理者 ヘルプ の「サービス アカウントにロールを割り当てる」に記載されている通りに service account にロールを割り当てればよい。
手順の概要
- GCP 側で Service Account を作成する
- Google Workspace の管理コンソールの アカウント > 管理者ロール から 新しいロールを作成 で必要な権限を持つ管理者ロールを作成する
- 一覧から 2 で作成した新しいロールの右側の 管理者を割り当て を選択する
- 管理者の割当画面から サービス アカウントへの割り当て をクリックし 1 で作成した Service Account のメールアドレスを入力する
- GCP の APIs and Services で Admin SDK API を有効にしておく
- Cloud Function を作成するときに 1 で作った Service Account を Runtime service account に設定する
- googleapis/google-api-nodejs-client の Applicaiton Default credentials に書いてあるように authClient を作って呼び出す(下記のソースコード参照)
const {google} = require('googleapis');
const auth = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/admin.directory.user.readonly']
});
const authClient = await auth.getClient();
const admin = google.admin({version: 'directory_v1', auth: authClient});
await admin.users.list({
domain: 'example.com'
}, (err, result) => {
if (err) {
console.error('Error: ' + err.message);
res.send('error');
return;
}
console.log(result);
res.send(result.data.users);
});
理由とか
node.js - Not Authorized To Access This Resource/API (GCP) - Stack Overflow に記載がある通り、 Admin SDK API では 管理者を想定しているAPI があり、そのような API を呼び出すためにはなりすまし(impersonate)アカウントが必要となる。(管理者を想定している API かどうかは Administrator privilege definitions - Google Workspace Admin Help を見ると分かる。)
ドメイン全体の委任(domain-wide delegation)をしている場合、 Token 取得の時にリクエストにメールアドレスを突っ込んであげればいいようだが、go - Query GSuite Directory API with a Google Cloud Platform service account - Stack Overflow にあるように Cloud Functions の OAuth scope はカスタマイズできないようだ。適当にメールアドレスを指定してなりすませるのはセキュリティ的にもうれしくない。
そこで、ドメイン全体の委任の代わりに Service Account に Google Workspaces の管理者ロールを割り当てればいい。ただし、そのためには既定の管理者ロールではなく、カスタム管理者ロールを作成する必要がある。
カスタム管理者ロールは2020年8月にリリースされたようだが今日まで知らずにはまったのでここにメモしておく。
Discussion