Google Workspace の管理コンソールは、カレンダー操作全般を記録する Calendar ログイベント機能を提供しています。この記事では、外部ゲスト招待に絞った監査の運用設計と、GAS (Google Apps Script) を使った月次レポートの自動化例を整理します。
この記事を読んだほうが良い人
- Google Calendar の外部共有ポリシーを設定済みで、実際の外部招待件数・招待者の把握まで手が回っていない情シス担当者
- 機密会議への外部招待や不審なタイミングでの招待をシステム的に検知したい担当者
- GAS で月次の外部招待レポートを自動化したい担当者
Google Calendar 監査ログが記録する外部ゲスト招待の種別
Google Workspace の管理コンソールのレポートセクション(監査と調査)では、Calendar log events として以下のイベントを記録します。
外部ゲスト招待の監査に直接関係するイベントを整理すると以下の通りです。
| イベント名 | 分類(type) | 説明 |
|---|---|---|
add_event_guest |
event_change | ゲストの招待(組織内外どちらも記録) |
remove_event_guest |
event_change | ゲスト招待の取り消し |
change_event_guest_response |
event_change | 出欠回答の変更(手動) |
change_event_guest_response_auto |
event_change | 出欠回答の自動変更 |
create_event |
event_change | 予定の新規作成 |
delete_event |
event_change | 予定の削除 |
change_calendar_acls |
calendar_change | カレンダーのアクセス権変更 |
add_subscription |
subscription_change | カレンダーの購読追加 |
外部ゲスト招待の監査では add_event_guest が中心になります。このイベントには、招待先のメールアドレス(event_guest)、予定のタイトル(event_title)、予定 ID(event_id)などのパラメータが含まれます。Google Workspace 管理者向け公式開発者ドキュメント(Calendar Audit Activity Events)で確認できる内容です。
管理コンソールのフィルター機能を使えば「イベント名:add_event_guest」を指定して外部招待を手動確認することも可能です。ただし件数が多い組織では手動確認に限界があるため、後述の GAS による自動化が実務に合っています。
外部招待を可視化することで見えてくる情報漏洩リスクの検知軸
外部共有ポリシーを設定しても、ポリシーの範囲内で行われる外部招待がすべて適切かどうかまでは保証されません。監査の目的はすべての外部招待を禁止することではなく、リスクの高いパターンを早期に検知することです。
以下は組織規模 100 名前後の企業でよく使われる異常パターンの定義例です。
時間帯・曜日の逸脱
深夜(22時〜6時)や休日に作成された外部ゲスト招待は、フィッシング被害や誤操作の可能性を示唆します。通常の業務時間外に外部招待が多発しているケースでは、同時期のメール送信ログとの照合も検討する価値があります。
機密性の高い予定への外部招待
予定タイトルに「経営会議」「取締役」「M&A」「予算」「契約締結」などのキーワードを含む会議への外部招待は、定期的に確認する対象です。意図した招待であっても、情シス担当者が把握しておくことで、後から問題になったときの追跡が容易になります。
単一ユーザーからの大量招待
特定ユーザーが 1 日に多数の外部招待を実行しているケース、または退職予定者による外部ドメインへの一斉招待は、早期確認のトリガーとして設定します。件数の閾値は組織ごとに実態を見ながら決めることが現実的です。
初出ドメインへの招待
組織として過去に接触のないドメインへの招待や、フリーメールドメインへの機密性の高い会議招待も確認対象に含めます。
検知閾値の参考設定(100 名規模企業の目安)
3 ヶ月分のデータが溜まる前は、以下の表を出発点として設定し、自組織の実態と照らし合わせて調整します。
| 検知条件 | 参考閾値 | 優先度 |
|---|---|---|
| 深夜(22時〜6時)の外部招待 | 月 1 件以上 | 高 |
| 単一ユーザーの月間外部招待 | 50 件超 | 中 |
| 機密キーワードを含む予定への外部招待 | 月 1 件以上 | 高 |
| 初出ドメインへの招待 | 月 5 件超 | 低 |
閾値を厳しくしすぎると確認工数が増えてチェック自体が続かなくなります。まず「高」優先度の 2 条件だけを自動通知対象にして運用を始め、慣れてきたら「中」「低」を追加する段階的な導入を推奨します。
これらの定義は組織ごとに調整が必要で、最初から精緻な条件を作ることより、まず月次で「件数の推移・上位招待者・初出ドメイン」の 3 点を確認する習慣を作ることが先決です。
GAS で外部招待を可視化する月次レポートの実装
ここでは、Reports API と GAS を組み合わせて前月分の外部ゲスト招待を Spreadsheet に書き出すスクリプトの最小実装例を示します。
事前準備
スクリプトを動かす前に以下の 2 点を確認してください。
- Admin Reports API の有効化: GAS エディタのサービス追加画面から「Admin SDK API」を追加します。有効化しないと
AdminReports is not definedというエラーが返ります - 実行アカウントの権限: スクリプトを実行するアカウントに Google Workspace の管理者権限(レポート閲覧以上)が必要です。一般ユーザーアカウントで実行すると 403 エラーが返ります
また、GAS プロジェクトに紐づくスプレッドシートを事前に作成しておくか、スクリプト内でスプレッドシートを新規生成するように変更してください。後述のコードはアクティブなスプレッドシートを対象にしています。
月次外部招待レポートのスクリプト
Reports API の applicationName として calendar を使用し、eventName に add_event_guest を指定して外部招待イベントだけを取得します。
// 前月分の Calendar 外部ゲスト招待を取得してスプレッドシートに書き出す
// 実行前に Advanced Google Services で「Admin SDK API」を有効化すること
function reportExternalCalendarInvites() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('外部招待ログ')
|| ss.insertSheet('外部招待ログ');
const now = new Date();
const firstDay = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const lastDay = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59);
const ORG_DOMAIN = 'example.com'; // ← 自社ドメインに変更
let rows = [];
let pageToken = null;
do {
const params = {
startTime: firstDay.toISOString(),
endTime: lastDay.toISOString(),
eventName: 'add_event_guest',
maxResults: 1000
};
if (pageToken) params.pageToken = pageToken;
const res = AdminReports.Activities.list('all', 'calendar', params);
const items = res.items || [];
for (const item of items) {
const actor = item.actor?.email || '';
for (const evt of (item.events || [])) {
const p = {};
(evt.parameters || []).forEach(x => { p[x.name] = x.value; });
const guestEmail = p['event_guest'] || '';
const eventTitle = p['event_title'] || '';
const eventId = p['event_id'] || '';
if (guestEmail && !guestEmail.endsWith('@' + ORG_DOMAIN)) {
rows.push([
new Date(item.id.time), actor, guestEmail,
guestEmail.split('@')[1] || '', eventTitle, eventId
]);
}
}
}
pageToken = res.nextPageToken;
} while (pageToken);
sheet.clearContents();
sheet.appendRow(['招待日時', '招待者', 'ゲストメール', 'ゲストドメイン', '予定タイトル', '予定ID']);
if (rows.length > 0) sheet.getRange(2, 1, rows.length, 6).setValues(rows);
Logger.log(`${rows.length} 件の外部招待を記録しました`);
}
変更が必要な箇所は 1 点です。ORG_DOMAIN を自社の Google Workspace ドメインに置き換えてください。マルチドメイン環境の場合は、文字列比較をドメイン配列のチェックに拡張します。
Slack 通知を追加する
月次レポートの生成だけでなく、月間の外部招待件数が閾値を超えたときに Slack へ通知を飛ばすと、スプレッドシートの確認漏れを防げます。以下は Incoming Webhook を使った通知関数の追加例です。
// THRESHOLD: 月間外部招待件数のアラート閾値
// SLACK_WEBHOOK_URL: スクリプトプロパティへの保存を推奨
const THRESHOLD = 100;
const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/XXXX/YYYY/ZZZZ'; // ← 変更必須
function notifySlackIfNeeded(count) {
if (count < THRESHOLD) return;
const msg = `[Calendar 監査] 先月の外部ゲスト招待が ${count} 件でした(閾値: ${THRESHOLD} 件)。スプレッドシートを確認してください。`;
UrlFetchApp.fetch(SLACK_WEBHOOK_URL, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify({ text: msg })
});
}
reportExternalCalendarInvites() の末尾に notifySlackIfNeeded(rows.length) を追加すると連携できます。SLACK_WEBHOOK_URL は GAS のスクリプトプロパティに保存しておくと、コードにハードコードせずに済みます。
時間トリガーの設定
このスクリプトを毎月 1 日の午前 9 時に自動実行するよう GAS の時間ベーストリガーを設定します。GAS のトリガー管理画面から「月タイマー」を選択し、月の初日に実行する設定にするだけで、前月分のレポートが毎月自動で蓄積されます。
月次チェックの運用ポリシー設計と改善サイクル
レポートを取得するだけでは情報が溜まるだけになります。「誰が何をチェックし、どう動くか」を事前に決めておくことが、このような運用設計の肝です。
| フェーズ | 頻度 | 担当 | アクション |
|---|---|---|---|
| レポート生成 | 月 1 回(月初) | GAS 自動実行 | スプレッドシートに書き出し |
| 一次確認 | 月 1 回 | 情シス担当者 | 件数推移・上位招待者・初出ドメインの確認 |
| 二次確認(要確認案件) | 随時 | 情シス + ライン管理者 | 招待者本人への聞き取り |
| ポリシー見直し | 四半期 | 情シス + 経営 | 閾値・対象ドメインの更新 |
初回チェックでは以下の 3 点を確認すると全体感をつかみやすくなります。
- 件数の全体感: 月に何件の外部招待があるかを記録します。業種・部門構成によって大きく異なるため、初月の数字が自組織の正常値のベースラインになります
- 上位招待者: 外部招待件数が多い上位 10 名を確認します。営業職・法務担当なら正常である可能性が高く、バックオフィスで突出していれば確認対象です
- 初出ドメイン: 前月に登場しなかったゲストドメインを抽出し、取引実績があるドメインかどうかを確認します
要確認案件が見つかったときの対応フロー
一次確認で「確認が必要」と判断した案件が出てきた場合の対応手順を事前に決めておくと、実際に問題が起きたときに迷いません。以下の 4 ステップを雛形として使ってください。
- 情シス担当者がスプレッドシートの当該行を「要確認」としてマーク(列を追加してステータス管理するのが手軽)
- 招待した本人またはその上長にチャットで確認する。「○月○日に △△さんを〜会議に招待しています。業務上の招待であることをご確認いただけますか」という一文で十分
- 24 時間以内に応答が得られない、または意図しない招待と判明した場合は、管理コンソールのレポートセクションで詳細を確認し、必要であればアカウントの一時停止や招待の取り消しを検討する
- 同じパターンが月次チェックで繰り返し出る場合は、次のポリシー見直しサイクルで外部共有ポリシーの変更を検討する
対応フローはシンプルで構いません。重要なのは、確認から解決までの責任者と期限を明示しておくことです。「確認したかどうかわからなくなった」状態を防ぐだけで、実務上の価値の大半を担います。
3 ヶ月程度データが溜まると、「このドメイン・このユーザー・この時間帯は正常」という自組織の基準が見えてきます。その段階で GAS に Slack 通知を追加し、異常パターン件数が閾値を超えた月に自動通知する形に発展させることが、次の自然なステップです。
Calendar 監査ログで把握できること・できないこと
運用設計を整備する前に、Calendar 監査ログの能力範囲を正確に把握しておくことは大切です。期待値がずれたまま運用を始めると、見えないリスクを「見えている」と誤認することになります。
把握できること
- 誰がいつ、誰を招待したか(
add_event_guestイベント) - 招待した予定のタイトルと予定 ID
- 招待の取り消しが行われたか(
remove_event_guest) - 招待された側の出欠回答の変化(
change_event_guest_response)
Calendar 監査ログ単体では把握できないこと
- 予定の説明文(description)の内容
- 会議で共有された添付ファイルや資料の中身
- 外部ゲストが実際に会議に入室したかどうか(Meet ログと組み合わせる必要があります)
外部ゲストの実際の入室有無まで把握したい場合は、Meet ログイベントとカレンダーの予定 ID を突合する監査設計が別途必要になります。セキュリティ要件が厳しい組織にとっては次のフェーズの課題です。
他ログとの組み合わせで検知精度を上げる
Calendar 監査ログ単体の限界をカバーするには、他の Google Workspace 監査ログとの組み合わせが有効です。
- Drive 監査ログとの組み合わせ: カレンダー招待で外部ゲストを招いた後、同じユーザーが Drive で外部共有を行っていないかを照合することで、情報漏洩の経路を追いやすくなります。招待の直後に Drive 共有が増えているケースは要注意のパターンです
- Meet ログとの組み合わせ: Meet の入退室ログと Calendar の予定 ID を突合することで、外部ゲストが実際に入室した会議を特定できます。「招待されたが入室しなかった」と「招待されて入室した」では対応の優先度が異なります
これらの組み合わせ監査は、まず Calendar の月次チェックを 3 ヶ月ほど継続して自組織の正常値を把握してから着手する順序が現実的です。複数ログの突合を最初から実装すると確認工数が一気に増え、運用が続かなくなります。できることとできないことを明確にした上で運用ポリシーを設計することで、過剰な期待による負荷増大を防げます。
まとめ
外部共有ポリシーの設定は出発点に過ぎません。設定後の実態を把握し、異常を検知して改善するサイクルを回すことで、初めてポリシーが実効性を持ちます。
Calendar 監査ログの add_event_guest イベントを月次で取得し、件数推移・上位招待者・初出ドメインの 3 点を確認する習慣から始めてください。この記事のコードはそのまま動かせる最小実装なので、まず GAS プロジェクトに貼って試すことをお勧めします。完璧な監査体制を一気に構築するより、小さく始めて定着させる方が長続きします。次のステップは、3 ヶ月分のデータが溜まったタイミングで閾値を調整し、Slack 通知を追加することです。
Calendar 監査を GWS セキュリティ全体の設計に組み込む際は、ぜひ DRASENAS へご相談ください。
コーポレートITのご相談はお気軽に
この記事で書いたような業務改善・自動化の設計から実装まで、DRASENASではコーポレートITの現場に寄り添った支援を行っています。 「まず相談だけ」でも大歓迎です。DRASENAS 公式サイトからお気軽にどうぞ。
御社の IT 部門、ここにあります。
「ITのことはあまりわからない」── そのような状態からで、まったく問題ございません。まずはお気軽にご相談ください。