Google Workspaceの動的グループで楽をしよう【GAS】
大規模な組織変更や、異動の時期。その度に部門のグループアドレスのメンバーを入れ替えたりするのは地味に大仕事だったりします。連動するGoogle Driveに対してもアクセスが出来なくなったり、異動したのに元の部署のドライブが見える状態のままになったりと、セキュリティ的にも問題が生じかねません。
そこでGoogle Workspaceに用意されている動的グループ機能を利用してこれらグループアドレスのメンテを自動化し、安全に運用するノウハウをまとめてみました。
※2023年12月15日発表で、動的グループの上限数が100から500まで拡大されました。
今回利用するサービス等
この機能は、Google Workspace Enterprise Standard以上もしくは、他のプランにてCloud Identity Premiumをサブスクリプションで追加してる場合に利用することが可能です。
また、スクリプトから動的グループを作りたい場合は、Cloud Identity APIを利用する必要があり、クエリで利用するカスタム属性についても同様です。Cloud Identityに関する記事は以下のエントリーを参照してください。
※Microsoft365だと、Azure Active DirectoryことEntra IDの動的グループメンバーシップルールがそれに該当すると思います。
動的グループとは?
概要
通常のグループアドレスは人間がそのメンバーを手動で管理する必要があります。よって、追加されてる以上はその人は閲覧が可能で投稿も可能です。また、グループアドレスでDriveにアクセス権限を付与管理してる場合、そのドライブへのアクセスも可能になります。
一方動的グループとは、Google Workspaceのディレクトリに於いてユーザの属性等を利用して条件指定し、その条件に合致したメンバーをグルーピングしてるものなので、一度作成すると基本メンテナンスフリーになります。もちろん、ユーザ個々人のディレクトリ上の属性情報は手動で更新も良いですが、Admin SDKのAdminDirectory.Users.updateを利用して一括で更新するという手法も使えます。
グループアドレスのメンバーを弄るよりも個々人の属性値を修正した方が遥かに楽なので、適合するプランを利用してる組織では使わない手はありません。但し、次項の制限事項があるため、フラットではない組織で階層構造が深い組織の場合で細かく運用を分けたいといった場合には別途運用テクニックが必要です
制限事項
動的グループは、通常のグループアドレスと異なり制限事項があります。主な制限事項は以下の通りです。
- 手動でユーザの追加をすることは出来ません
- グループアドレスを動的グループのメンバーに追加する事は出来ません(対象はユーザのみです)
- グループアドレスに対する権限管理はグループメンバーのみ、ウェブ上の全てのユーザ、組織全体のみで細かな権限管理は出来ません。
- Admin Console上からでなければ作成することは出来ません
- 動的グループは標準で500個まで作成可能です(それ以上の場合はサポートに問い合わせして、枠を拡張する必要があります)
特に運用上障害になるのが、2.の部分。手動で組織部門のグループアドレスを作って運用してる場合、階層構造をグループアドレスで再現するために、グループアドレスの中に別の下位組織のグループアドレスを追加したり、上位組織直下所属のメンバーを別途入れていたりと入り乱れてるケースが多いですが、こういった運用は出来ません。必ず所属するのはメンバーである必要があります。
つまり、これをどうにかしようとするには前述にあるように別途運用テクニックが必要なのです。
動的グループの作成
動的グループは2021年にGoogle Workspaceにリリースされた機能で、クエリ式を持ってしてグループを作成するものです。但し現時点ではユーザの属性値に対してイコール/ノットイコールでしか条件式は作成できません(Likeみたいな文字を含むといった指定はできない)。また、現在ベータ版ですがユーザにカスタム属性として追加することも可能になっています。
通常の作成
動的グループを作成するのはそこまで難しくありません。以下の手順で作成することが可能です。
- Admin Consoleへログインする
- 左サイドバーからディレクトリ=>グループを開く
- 動的グループを作成をクリックする
- Conditionから属性値を選択する。今回は部門(organization.department)を選択してみた
- Equalsがイコール、Equal ignore caseがノットイコールになります。
- 条件を追加でAND、ORの指定で別の属性値を同時に指定する事も出来ます。
- Valueに属性値と一致もしくは非一致するワードを入力。今回は情報システム部として指定してみた。
- プレビューをクリックすると、属性値を一致したメンバーがきちんと出ていればオッケー
- 動的グループを作成をクリックすると作成が完了する。
- 必要ならばグループの設定変更してアクセス権限を変更しておきます。
図:動的クエリ作成画面
カスタム属性
Google Workspaceに標準で用意されてる属性値では足りない場合にテナント管理者が追加する事が出来る追加の属性がカスタム属性です。カスタムで追加することで、動的グループの標準の属性に加えることが可能です。以下は手動で属性値を加える手順になります。
- Admin Consoleへログインする
- 左サイドバーからディレクトリ=>ユーザを開く
- ユーザリスト右上にあるその他のオプション=>カスタム属性を管理しますをクリックする
- カスタム属性を追加をクリックする
- カテゴリ名と説明文を適当に入力。
- カスタムフィールドは名前は基本英語で入力したほうがGASからの値は入れやすいです(例えばorgHonbu, orgBumonといった形で)
- フィールドタイプはテキストや数値等を選べます。今回は全部テキストで。
- 公開設定は基本今回の場合、組織に公開で行います。
- 値の数は単一の値でセットします。複数の値をセットするようなパターンも可能です。
これでディレクトリのユーザ情報に対して、入力欄が下の方に出現します。また、動的クエリの属性対象選択のプルダウンにも出てくるようになるので、カスタム属性でクエリを作成することが可能になります。
図:カスタム属性を追加する画面
図:追加された属性入力欄
図:動的クエリの属性選択欄に出てきた
運用テクニック
概要
前述の項目で何回か出てきた「運用テクニック」についてですが、動的グループにグループアドレスをメンバーとして所属させることは出来ません。よって、必ず所属するのは通常のユーザのアドレスである必要があります。そうなるとこれまで手動で運用してきた時のように、グループアドレスの中にグループアドレスを入れたり、上位組織直下所属のメンバーを追加したりといった入り乱れた運用が出来ません(というかこの手法自体が悪手なんですが)。
動的グループで階層構造を実現しつつメンテナンスフリーにするには通常のグループアドレスも必要になります。
ここでは3階層の構造を持つ組織(本部=部門=課)の場合について説明してみたいと思います。
通常のグループを併用した方法
この手法はこれまでの階層構造のグループアドレスの構造を利用しつつ、動的グループを活用する方法です。既存のグループアドレスから移行しやすい方法ですが、組織変更が生じた場合にはグループアドレス内の構造を1個ずつ遡って変更が必要となります。
- 本部、部門のメールアドレスに対してはユーザアドレスは一切登録はしない。下位組織のグループアドレスのみとする(ここは通常のグループアドレス)
- ユーザは原則、一番下の組織である課のグループアドレスに所属させる(ここを動的グループで作成しておく)
- 本部や部門直下所属のような人たちについては直下専用のグループアドレスを別途作成する(ここも動的グループで作成しておく)
こうすることで、グループアドレスとユーザが入り乱れる事がなく、必ずユーザは動的グループに所属させることになるので、ユーザのディレクトリ上の組織部門を変更する事で、対象のグループアドレスがどれなのかを意識することなく変更をすることが出来るようになります。
カスタム属性を使った方法
前述のカスタム属性を使った手法です。Admin Console上のディレクトリに於けるユーザに対してカスタム属性を付けることで、グループアドレスを全て動的グループで作成する方法です。前述の方法と異なり組織変更が生じても基本、グループアドレス内の構造を辿っての修正が不要で、条件を使って構築する為、組織変更があった場合は、ユーザの属性変更とグループアドレスの条件式変更だけで済みます。
- ユーザに本部、部門、課の3つのカスタム属性を追加する
- 本部の動的グループは本部に対象の本部が入ってるかどうかだけをクエリで構築する(本部以下のメンバーが全てヒットする)
- 部門の動的グループは部門に対象の部門が入ってるかどうかだけをクエリで構築する(部門以下のメンバーが全てヒットする)
- 課の動的グループは課に対象の課が入ってるかどうかだけをクエリで構築する(課のメンバーのみがヒットする)
非常に単純なクエリ構造なので部直下といったことを意識したりそのためのグループアドレスを別途作成は必要ありません。グループの中にグループアドレスを入れて階層化も必要ありません。非常にシンプルです。AND条件で複雑にする必要もありません。
動的グループで設定をまとめる
管理コンソールでは組織部門単位で設定するだけじゃなく、設定グループという形でグループアドレスを元にGoogle Workspaceの設定を別途行うことが可能になっています。この時のグループアドレスとしても動的グループを利用可能です。但し、この場合利用できるグループアドレスは「セキュリティグループ」である必要があるため、動的グループを作ったあとに設定で「セキュリティ」のチェックをしておかないと、設定対象グループとして出てきません。
例えば、メアドの先頭にadminと付いてるメアドを条件に動的グループを作り、これらを管理者専用の設定として、設定グループとして個別にGoogle Workspaceの設定を行うといったような使い方が可能です。グループのメンバーのメンテナンスが不要になりますし、組織部門間で対象者を移動させてといったことも不要になるのでオススメです。
セキュリティをつける手順は以下の通り
- 管理コンソールにログインする
- 左サイドバーからディレクトリ=>グループを開く
- 作成した動的グループを見つけて「右パネルに出てる設定」をクリックする
- 一番上にある「グループ情報」をクリックする
- ラベルをクリックする
- セキュリティにチェックを入れて、保存をクリックする
図:セキュリティでないと設定グループで使えない
付け替える場合の注意点
古いグループアドレスを置き換えたい場合、既存の同名のグループアドレスを一度削除して、作り直す必要があります。この場合問題になるのは、Google Driveにつけてしまったグループアドレスでのアクセス権限はどうなるか?問題です。アドレス自体削除してしまってるので、アクセス権限が消えてしまい再度、必要な共有ドライブに対して全部付け替えが必要か?となります。これを検証しました。
- 共有ドライブには該当の通常のグループアドレスでアクセス権限がついています。
- 1.のグループアドレス自体を削除してみる
- 1.のグループアドレスと同じアドレス名で動的グループで作り直す
実際にこの状態で共有ドライブのメンバー設定を見てみると、「削除されたアカウント」と表示されたままになってる。
よって、同名のグループアドレス名でグループアドレス=>動的グループで差し替える場合には、必ず元の共有ドライブのリストを取得しておいて、同じドライブに対してグループアドレスでアクセス権限を付与し直す必要があります。
Google Apps Scriptを使う
個々人の属性情報を取得・更新する
属性値の取得にはAdminDirectory.Users.getを利用し、値の更新についてはAdminDirectory.Users.updateを使って更新を行います。スプレッドシートにユーザのリストを用意しておいて、そこから更新を掛けます。カスタム属性値についても同様です。
標準の属性値の変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//ユーザリソースを構築 var userResource = { "phones": [ { "value": "ここに電話番号を入れる", "type": "work" } ], organizations: [ { department:"ここに組織の所属部門名を入れます", title : "ここに役職名を入れる", description : "ここに従業員の種類を入れる" } ], } //属性値を更新する try{ AdminDirectory.Users.update(userResource, "対象のメールアドレスを入れる"); }catch(e){ console.log(e.message) } |
- userResourceを構築し、AdminDirectory.Users.updateにてメールアドレスを加えて実行するとディレクトリの内容が書き換わります。
- userResourceは必要なものだけを入れていくのですが、Admin Console上の表記がどの標準属性と対応しているのか?は見極めが必要です
- 上記の例では、標準属性の電話番号と組織部門の内容の一部を更新しています。
カスタム属性値の変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function setCustomProp(){ //ユーザリソースを構築 var userResource = { customSchemas:{ employee: { bumon2: '部門2', bumon: '部門1', honbu: '本部', section: 'セクション' } } } //Admin SDKでアップデートする try{ AdminDirectory.Users.update(userResource, "ここにメールアドレスを入れる"); }catch(e){ console.log(e.message) } } |
- 今回はemployeeという名でカスタム属性値を作り、その中にbumon等のフィールドを設けています。
- AdminDirectory.Users.updateで更新を掛ける点は変わらず
- userResourceの構築は前述のgetで取得した内容をそのまま構築でも記述します。カスタム属性のフィールドが存在し対応してるものがどれなのか?よく見極めてセットしましょう。
属性値の取得
1 2 3 4 5 6 7 8 9 |
function userinfogetter(){ let ret = AdminDirectory.Users.get( "ここに対象のメールアドレスを入れる", { "projection": "full" } ) console.log(ret) } |
- employeeという名前でカスタム属性を作り、bumon等のフィールドを設けています。
- ユーザの属性値を取得する場合には、AdminDirectory.Users.getを使いますが、標準属性しか取れないので、オプションとしてprojectionをfullで指定するとカスタム属性まで含めて取得可能です。
- 取得した内容は以下のような形になりますが、必ずしもカスタム属性で名付けた内容とField名が一致しないケースがあるので一度取得してどれがどのフィールドと対応してるのかを見極めましょう。
12345678910customSchemas:{employee:{bumon2: '下位の部門名',bumon: '部門名',honbu: '本部名',section: '課の名前'}},
ドライブにアクセス権限を付与する
作成した動的グループを共有ドライブに一括で付与したいといった場合には、Drive APIを利用して共有ドライブを操作する必要があります。但し、アクセス権限の設定について、そのテナントで「管理者以外はアクセス権限を操作させない」というポリシーを適用してる場合、通常のユーザが権限変更することは出来ませんので、スクリプトの実行は「特権管理者」で行う必要があります。
付け替えや付与自体のコードは以下のエントリーでまとめていますので、Drive.Permissions.insertを利用して付与する事が可能です。
動的グループを作成する
スクリプトをもって動的グループを作成するには通常のグループ作成であるAdminDirectoryでは作成が出来ません。利用するにはちょっとした準備とREST APIを叩く必要があります。Cloud Identity APIを使いますがGoogle WorkspaceのテナントにCloud Identity FreeやPremiumをサブスクで追加していなくても使えますので、このために別途追加は不要です。
事前準備
顧客IDを調べる
ソースコードで利用するGoogle Workspaceの顧客IDを調べます。以下の手順で調べることが可能です。
- Admin Consoleを開く
- 左サイドバーからアカウント => アカウント設定を開く
- プロファイルに顧客IDが記載されてるのでこれを控えておく
APIを有効にする
Google Cloud Console側でAPIを有効化する必要性があります。
- GCPのプロジェクトを開く
- 左サイドバーからAPIとサービスにて、「APIとサービスの有効化」をクリックする
- Cloud Identityと検索すると出てくるので、クリックします。
- 有効化をクリックします。
- 認証情報の作成は不要です
図:有効化をしておくだけでOK
GASのプロジェクトを紐付けする
Google Apps ScriptとCloud Consoleのプロジェクトを紐付けする作業が必要です。以下の手順でプロジェクトの変更を行います。
- Cloud Console側のプロジェクトのホームを開き、「プロジェクト番号」を控えておく
- Google Apps Scriptのスクリプトエディタを開く
- サイドバーからプロジェクト設定を開く
- GCPプロジェクトの「プロジェクトを変更」をクリック
- GCPのプロジェクト番号に、1.の番号を入力して、プロジェクトを設定をクリック
- これで紐付けが完了しました。
図:プロジェクトの移動も必須の作業です
appscript.jsonの編集
appscript.jsonに以下のような感じで、oauthScopesを追加して起きます。appscript.jsonの表示は、サイドバーのプロジェクト設定より、「appsscript.json」マニフェスト ファイルをエディタで表示するにチェックを入れると表示されるようになります。GCPのAPIを使う為に必要です。
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/cloud-identity.groups" ] } |
ソースコード
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
function createDynamicGroup(){ //作成するグループアドレス let groupaddr = "ここに作成するグループアドレスを入れる" //顧客IDの指定 let customer_id = "ここに顧客IDをいれる"; //作成エンドポイント let endpoint = "https://cloudidentity.googleapis.com/v1/groups?initialGroupConfig=EMPTY"; //OAuth Tokenを取得 let token = ScriptApp.getOAuthToken(); //リクエストボディ let body = { "parent":"customerId/" + customer_id, "groupKey": {"id": groupaddr}, "displayName":"グループアドレスの表示名をいれる", "description": "ここにグループアドレスの説明文を入れる", "labels": { "cloudidentity.googleapis.com/groups.discussion_forum": "" }, "dynamicGroupMetadata": { "queries": [ { "resourceType": "USER", "query": "user.custom_schemas.employee.honbu_name=='カスタム属性の本部名を入れる'" } ] } } //ヘッダ情報 let header = { Authorization: "Bearer " + token } //リクエストオプション let options = { headers: header, method: "POST", contentType: "application/json", payload: JSON.stringify(body), muteHttpExceptions: true } //URLリクエスト let response = UrlFetchApp.fetch(endpoint,options); //レスポンス内容を取得 let ret = response.getContentText(); console.log(ret) } |
- groupaddrにxxxxx@hoge.comという形式で新規作成するグループアドレスを入れる
- customer_idに取得しておいた顧客IDを入れる
- エンドポイントのベースは「https://cloudidentity.googleapis.com/v1/groups」ですが、クエリパラメータに?initialGroupConfig=EMPTYを追加する必要性があります。
- リクエストボディのparentは顧客IDをつなげて、「customerId/xxxx」といった形で入力する
- groupKeyに作成するgroupaddrを入れてあげる
- labelsはソースコード内の文字列で固定的に入れておく
- dynamicGroupMetadataが重要で、resourceTypeはUSERで良いのですが、queryは実際のAdmin Consoleの動的グループ作成画面で構築すると下に式が出てくるので、これをそのまま入れてあげます。今回のケースではカスタム属性のhonbu_nameが指定の本部名のメンバーを取得するようクエリを作っています。
- あとはUrlfetchAppでPOSTでリクエストを投げると動的グループをGASで作成することが可能です。
関連リンク
- Cloud IdentityでGoogleグループからメンバーを追加・削除するGoogle Apps Scriptを書いた
- 動的グループを使用してメンバーを自動的に管理する
- 動的グループの作成と更新
- Method: groups.create
- Cloud Identity API
- メンバークエリの作成とテスト - カスタム属性を使う
- 動的グループ用のメンバーシップ クエリを作成する
- Retrieve custom attribute from user profile in Google API Scripts- Google Admin Directory
- Google API Cloud identity groups().create(): what is the field customer_id?
- google_cloud_identity_group
- Use the Google Cloud Identity API for Google Groups
- Create membership expiration in Google Groups for Google Workspace
- グループ メンバーの有効期限の設定が可能に(ベータ版)
- Cloud Identity Groups API(ベータ版)を使用してプログラムでグループを管理する
- Method: groups.memberships.modifyMembershipRoles
- Time limited, auto-expiring group memberships for users on Google Cloud
- St3ph-fr/my-apps-script-utils