Google Meetは参加requestを検証済みキューと高リスクキューに振り分けるようになりました。データセンターのbotは後者に入ります。SAMLを使ってbotを実在のWorkspaceアカウントにログインさせる仕組みと、その設定方法を解説します。

AAmr El Shimy
··9 min read
認証済みGoogle Meet bot:脅威キューから抜け出す

2026年4月、Google Meetは参加requestを2つのキューに振り分けるようになりました。招待者と組織のメンバーは検証済みキューに入り、そのまま通されます。それ以外はすべて2つ目のキューに入り、ホストの画面には「潜在的な脅威あり(With potential threats)」というラベルで表示されます。このキューでは、デフォルトのボタンが「許可(Admit)」ではなく「拒否(Deny)」です。

録画botはデータセンターのIPで動作します。そのすべてが2つ目のキューに入ります。

まず、思いつく対処法から試しました。residential proxyはここでは通用しません。プールが共有されているため評判はすでに使い果たされており、Googleは同じようにフラグを立てます。botを検証済みキューに入れられる唯一の要素は、実在する組織に属する実在のGoogle Workspaceユーザーであることです。

そこで、それを構築しました。botはあなたが所有するWorkspaceアカウントにログインし、そのユーザーとしてミーティングに参加できるようになりました。

この機能はオプトインで、bot単位で指定します。requestにmeet_configを含めなければ何も変わりません。botはこれまでどおり匿名で参加します。

意外に思われる点

「認証済みbot」と聞くと、誰もがOAuthを思い浮かべ、自分のGoogleアカウントへのアクセス権を私たちに渡すことになると考えます。実際はそうではありません。

仕組みはSAMLです。あなたのWorkspaceに、私たちのログインendpointを指すLegacy SSO profileを設定します。botがGoogleのログインページにメールアドレスを入力すると、Googleはそのドメインがフェデレーションされていることを認識し、私たちにリダイレクトします。私たちは、あなたが自身のWorkspaceにアップロードした証明書に対応する秘密鍵でSAML assertionに署名し、ブラウザがそれをGoogleへPOSTで返すと、botはログインした状態になります。

MeetingBaaSにGoogle APIへのアクセス権を付与することは一切ありません。 あなたは自分が管理するWorkspaceに公開証明書をアップロードするだけです。私たちは対応する秘密鍵を保持し、それをただ1つの用途にのみ使用します。

一般に想定される3つのアプローチは、いずれもうまくいきません。

アプローチうまくいかない理由
ユーザー名とパスワード2FAのプロンプト、パスワードのローテーション、captcha、「通常と異なる場所」の確認が発生します。headlessブラウザはこれらをすべて突破できません。
Google OAuth(3LO)アカウントごとに対話的な同意ダイアログが必要です。それをクリックする人がいません。
サービスアカウントそもそもMeetの通話に参加者として参加できません。

SAMLはこれらすべてを回避します。assertion自体が認証そのものであるため、満たすべき第2要素が存在しません。

匿名のデータセンターbotはデフォルトで脅威キューに振り分けられますが、署名済みのSAMLアサーションにより、同じbotが実際のWorkspaceユーザーとして確認済みキューに移動します

リソースは1つではなく2つ

APIはworkspaceとloginに分かれています。この分割は恣意的なものではありません。

GoogleのLegacy SSO profileが保持する検証用証明書はWorkspaceごとに1つで、その中のすべてのユーザーで共有されます。仮に証明書をloginごとに持たせる設計にすると、botアカウントを追加するたびに、新しいキーペアを生成してGoogle Admin上の証明書を上書きする(この瞬間、古い証明書で登録済みのすべてのloginが壊れます)か、同じ証明書と鍵を作成requestごとに手作業で貼り付けるか、どちらかになってしまいます。

そのため、証明書はworkspaceに置き、その配下にIDをぶら下げる構成にしました。

/v2/meet-workspaces   → domain + SAML certificate and private key
/v2/meet-logins       → the Workspace users, attached via workspace_id

Workspaces

POST   /v2/meet-workspaces
GET    /v2/meet-workspaces
GET    /v2/meet-workspaces/:workspace_id
PATCH  /v2/meet-workspaces/:workspace_id
DELETE /v2/meet-workspaces/:workspace_id

作成方法は2通りです。キーペアの生成を私たちに任せる場合。

{
  "name": "Acme Production",
  "domain": "bots.acme.com",
  "generate_keypair": true
}

もしくは、自分で用意したものを持ち込む場合。

{
  "name": "Acme Production",
  "domain": "bots.acme.com",
  "cert_pem": "-----BEGIN CERTIFICATE-----...",
  "private_key_pem": "-----BEGIN PRIVATE KEY-----..."
}

どちらか一方を渡してください。両方を渡した場合も、どちらも渡さなかった場合もvalidationエラーになります。作成時には、証明書と鍵が実際にパースできること、鍵が証明書と一致すること、そしてドメインが有効なホスト名でまだ登録されていないことを確認します。

どちらの方法を選んだ場合でも、responseには必ずcert_pemが含まれます。これがGoogle Adminに貼り付ける必要のある値だからです。private_key_pemは、どのendpointからも、いかなる場合も返されることはありません。

domainは作成後は変更できません。それ以外はすべてPATCHで更新でき、証明書と鍵をまとめてローテーションすることも可能です。

Logins

POST   /v2/meet-logins
GET    /v2/meet-logins
GET    /v2/meet-logins/utilization
GET    /v2/meet-logins/:credential_id
PATCH  /v2/meet-logins/:credential_id
DELETE /v2/meet-logins/:credential_id
{
  "workspace_id": "f0e1d2c3-b4a5-6789-0123-456789abcdef",
  "name": "Production Bot Pool — Account 1",
  "email": "bot1@bots.acme.com",
  "email_group": "bots@bots.acme.com"
}

メールアドレスのドメインは、親となるworkspaceのドメインと一致するか、そのサブドメインである必要があります。emailworkspace_idは変更できません。loginを移動したい場合は、削除して新しく作成してください。

email_groupは任意ですが、設定する価値があります。同じグループを共有するloginは1つのround-robinプールを形成します。さらに、そのグループのアドレスをカレンダーの招待に入れておけば、割り当てられたbotは招待者として扱われ、ロビーを通過する最速の経路になります。

どちらのリソースも、独自のメタデータ用にextraオブジェクトを受け取ります。この値でフィルタすることもできます。

GET /v2/meet-logins?extra=environment:production

botでの使い方

{
  "meeting_url": "https://meet.google.com/abc-defg-hij",
  "bot_name": "Recording Bot",
  "meet_config": {
    "email_group": "bots@bots.acme.com",
    "fallback": "fail"
  }
}

meet_configの解決ルールは次のとおりです。

送信する内容動作
null(デフォルト)匿名bot。loginもSAMLも使わず、これまでどおりの動作です。
{ "email_group": "X" }グループX内のアクティブなloginをround-robinで使用します。
{ "credential_id": "Y" }login Yに固定します。
両方を指定し、グループが空でない場合email_groupが優先され、credential_idは無視されます。
{ "email_group": "" }のみチーム上のすべてのアクティブなloginをround-robinで使用します(グループによる絞り込みなし)。
{ "email_group": "", "credential_id": "Y" }login Yに固定されます。空のグループはグループではないため、credential_idが優先されます。

割り当てでは、アクティブなセッション数が最も少ないloginを選び、同数の場合は最後に使用された時刻が最も古いものを選びます。スロットの確保はアトミックな条件付き更新で行うため、同時に起動した2つのbotが同じスロットを取ることはありません。

プールが飽和した場合の挙動はfallbackが決めます。デフォルトは"fail"で、FST_ERR_MEET_LOGIN_UNAVAILABLEを返します。"anonymous"は何も告げずに未認証での参加にフォールバックします。検証済みの参加よりもとにかく録画を残すことが重要な場合は、こちらが適切な選択です。

キャパシティ

各loginには同時セッション数の上限があり、デフォルトは20です。これはGoogleがthrottlingを始めるとされる水準よりも意図的に低く設定してあり、自身のトラフィックを計測した上で引き上げられる下限値と考えてください。

GET /v2/meet-logins/utilizationを呼べば、全体像を1回で把握できます。

{
  "logins_total": 5,
  "logins_active": 5,
  "logins_invalid": 0,
  "concurrent_sessions": 47,
  "concurrent_capacity": 100,
  "utilization_pct": 47,
  "by_email_group": [
    { "email_group": "bots@bots.acme.com", "logins": 5, "concurrent": 47, "capacity": 100 }
  ]
}

utilization_pctを監視してください。常時70を超えているようならWorkspaceユーザーを増やすべきです。トラフィックの裾野がすでにfallbackに達しているからです。

loginが不良状態になったとき

workspaceとloginはどちらもactiveまたはinvalidというstateを持ちます。invalidを設定するのはシステムだけで、botのログインが今後も失敗し続ける形で失敗したときにのみ設定されます。たとえば、SAML assertionが拒否された場合(多くはGoogle Admin上の証明書が私たちのものと一致しなくなっているケース)や、Workspaceユーザーが停止・削除された場合です。一時的なタイムアウトでは状態は変わりません。

無効化されたloginは新たな割り当てを受け取らなくなり、last_error_messagelast_error_at、および該当のbot情報を含むfailure_dataオブジェクトを記録します。再有効化は、根本原因を修正した上で手動で行う設計にしています。

PATCH /v2/meet-logins/:credential_id
{ "state": "active" }

PATCHが受け付けるのは"active"のみです。自分で"invalid"を設定しようとすると、requestのvalidationで400として拒否されます。

実行中のセッションが残っているloginやworkspaceを削除しようとすると、稼働中のbotからcredentialを取り上げる代わりに409を返します。workspaceを削除すると、その配下のloginにも削除が波及します。

セットアップ

専用のWorkspaceまたはサブドメインを用意する

別のGoogle Workspaceを使うか、少なくともbots.acme.comのような専用のサブドメインを使ってください。メインの組織は使わないでください。

Google AdminのSSO設定は組織全体に適用されます。従業員がログインするWorkspaceで私たちを指定してしまうと、従業員のログインまでリダイレクトされます。SSO profileは無料プランでは利用できないため、有料プランが必要です。

workspaceを作成する

curl -X POST https://api.meetingbaas.com/v2/meet-workspaces \
  -H "x-meeting-baas-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "bots.acme.com", "generate_keypair": true}'

responseに含まれるcert_pemを控えておいてください。

Google AdminでSSOを設定する

セキュリティ(Security)→ サードパーティのIdPによるシングルサインオンの設定(Set up single sign-on with a third party IdP)→ SAMLプロファイルを追加(Add SAML profile)→ Legacy SSO profile。

項目
ログインページのURL(Sign-in page URL)https://api.meetingbaas.com/v2/meet-sso/sign-in
ログアウトページのURL(Sign-out page URL)https://api.meetingbaas.com/v2/meet-sso/sign-out
検証用証明書(Verification certificate)手順2で取得したcert_pem
ドメイン固有の発行元を使用(Use a domain-specific issuer)はい(Yes)

プロファイルを有効化し、SSOプロファイルの割り当てを管理(Manage SSO profile assignments)から割り当ててください。

Workspaceユーザーを作成する

botプールの同時実行スロット1つにつき、Google Workspaceユーザーを1つ用意します。

各ユーザーは、動作させる前に一度だけ、Googleの「Welcome to Google Workspace」オンボーディングを対話的に完了させる必要があります。この手順は見落とされがちで、証明書の問題のように見えて実はそうではないログイン失敗を引き起こします。ついでにmyaccount.google.comでアカウントの言語をEnglish (United States)に設定しておいてください。

任意で、Google グループを作成してbotユーザーを追加し、そのグループをカレンダーの招待に加えておくとよいでしょう。

各loginを登録する

curl -X POST https://api.meetingbaas.com/v2/meet-logins \
  -H "x-meeting-baas-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "...",
    "name": "bot1",
    "email": "bot1@bots.acme.com",
    "email_group": "bots@bots.acme.com"
  }'

botを送信する

POST /v2/botsの呼び出しにmeet_configを追加すれば、botがそのままミーティングに入っていく様子を確認できます。

事前に知っておきたい制限が1つあります

Googleは参加者リストにWorkspaceユーザー自身の名前を表示し、bot_nameに渡した値を上書きします。表示名が重要な場合、現時点での唯一の回避策は、表示したい名前ごとにWorkspaceユーザーを用意することですが、これはあまりスケールしません。現在検討中です。

関連記事

トラフィックに見合ったloginプールのサイズ設計や、あなたの環境で専用サブドメインが十分かどうかについてご質問はありますか?お問い合わせください。

関連ブログgoogle-meet