🪪

Identity Platform でマルチテナンシー機能を使う

2023/12/05に公開

Identity Platform でマルチテナンシー

この記事は Digital Identity技術勉強会 #iddance Advent Calendar 2023 の 5 日目の記事です。

Google Cloud が提供している IDaaS「Identity Platform」のマルチテナンシー機能を使って、テナントごとのログインを実装する方法をご紹介します。

Identity Platform の概要

まずはこの記事でメインで扱う Identity Platform について、クイックにご紹介したいと思います。

Identity Platform は Google Cloud で提供している認証サービスです。モバイルアプリ、Web アプリに認証機能をかんたんに導入できます。Firebase Authentication の上位版という位置付けで、Firebase Authentication の機能に加えて下記の機能も提供しています。

Firebase Authencation を知っている(または使っている)方は多いと思いますが、より高度な機能を使いたい場合は Identity Platform にアップグレードが可能です。ユーザーの移行も必要ないほか、クライアント側で使う必要がある SDK も Firebase Authencation で使っている SDK をそのまま使うことができるので、かんたんにアップグレードできます。

マルチテナンシー

マルチテナンシーはテナントごとにログイン方法および設定を分けることができる機能で、主に B to B サービスで活用できます。

例えばテナント A は自社社員の ID 管理基盤を持っており、OIDC Provider の機能を持っているとします。またテナント B も OIDC Provider の機能を持っているとします。これらのテナントがそれぞれのテナント内のユーザーとして SSO するには、それぞれの OIDC Provider ごとに設定を管理し、ログイン先のテナントごとに切り替えられる必要があります。

マルチテナンシーの機能を使うと、サポートされているプロバイダをテナントごとに管理することができます。ログイン時にログイン先のテナント情報を渡すことで、プロバイダ切り替えることができます。

Identity Platform のマルチテナンシー機能のイメージ

https://cloud.google.com/identity-platform/docs/multi-tenancy-quickstart?hl=ja

Identity Platform の作成

まずは Identity Platform を使うための準備を行います。Google Cloud プロジェクトは作成済みの前提で進めます。次の URL にアクセスします。

https://console.cloud.google.com/customer-identity/providers

Google Cloud プロジェクト内でまだ API を有効化していない場合は下図の画面が出るので [IDENTITY PLATFORM を有効化] をクリックします。

API の有効化

マルチテナンシーの設定

マルチテナンシーの設定は [設定] メニューの [セキュリティ] タブから設定できます。[テナントを許可] をクリックし、マルチテナンシー機能を有効化します。

マルチテナンシーの有効化

テナントの設定

[テナント] メニューを開くと、テナントの追加と設定が行えます。[テナントを追加] をクリックし、1つ目のテナントを追加します。

テナントの追加

[名前] は tenant-a としました。

テナントの設定

作成が完了するとテナント ID が払い出されます。

作成されたテナントの確認

鉛筆マークをクリックすると、テナントで有効化するプロバイダの設定画面が表示されます。今回は Email / Password 方式を有効化します。

テナントのプロバイダの設定

Email / Password を有効化するか確認ダイアログが表示されるので、確認し作成します。

Email / Password の有効化

ログインするユーザーの登録方法は、ユーザー自身で登録するか管理側から登録するか、2つの方式が用意されています。自分で登録することを制限することももちろん可能です。

今回は予めユーザーを管理画面から作成しておくことにします。

ユーザーの作成

メールアドレスとパスワードを入力するだけで追加できます。

ユーザーの作成

同様の手順で、2つ目のテナントも tenant-b という名前で作成しておきます。ユーザーはテナント A とテナント B を切り替えていることがわかるよう、異なるメールアドレスのユーザーを作成しておきます。

2つのテナントの作成

サンプルアプリの作成とデプロイ

それぞれのテナントで切り替えてログインできるか確認するため、サンプルアプリを作成します。サンプルアプリとしてシンプルな HTML ファイルを作成し、Firebase Hosting を使ってホスティングします。

Firebase Hosting と Identity Platform をそれぞれ同じ Google Cloud プロジェクト内に作成すると、Identity Platform 自体への認証情報やプロジェクトの指定が省略できるので便利です。

まずは HTML ファイルを用意します。公式サンプルとしても提供されているものがありますが、少し複雑な処理も行なっているので必要最低限の処理に留めたサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Identity Platform Multi-tenant Example</title>

  <!-- Firebase と Firebase Auth UI のインポート -->
  <script src="/__/firebase/9.22.1/firebase-app-compat.js"></script>
  <script src="/__/firebase/9.22.1/firebase-auth-compat.js"></script>
  <script src="https://www.gstatic.com/firebasejs/ui/6.1.0/firebase-ui-auth.js"></script>
  <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.1.0/firebase-ui-auth.css" />
  <script src="/__/firebase/init.js"></script>

  <script type="text/javascript">
    let ui = null;
    function initApp() {
      ui = new firebaseui.auth.AuthUI(firebase.auth());
      firebase.auth().onAuthStateChanged(function(user) {
        const container = document.getElementById('login-container');
        if (user) {
          const message = document.createElement('p');
          container.innerHTML = "ステータス : ログイン済み";
          container.appendChild(message);
          const button = document.createElement('button');
          button.innerHTML = "ログアウト";
          button.addEventListener('click', () => {
            firebase.auth().signOut();
          });
          container.appendChild(button);
        } else {
          const message = document.createElement('p');
          container.innerHTML = "ステータス : 未ログイン";
          container.appendChild(message);
        }
      });
      const searchParams = new URLSearchParams(window.location.search);
      const tenantId = searchParams.get("tenant_id");
      firebase.auth().tenantId = tenantId;
      ui.reset();
      ui.start('#firebaseui-auth-container', {
        'signInOptions': [firebase.auth.EmailAuthProvider.PROVIDER_ID],
        'credentialHelper': 'none',
        'signInFlow': 'popup',
        'callbacks': {
          'signInSuccessWithAuthResult': function(authResult, redirectUrl) {
            return false;
          }
        }
      });
    }
    window.onload = function() {
      initApp();
    };
  </script>
</head>
<body>
<div>
  <main>
    <div id="login-container"></div>
    <div id="firebaseui-auth-container"></div>
  </main>
</div>
</body>
</html>

このサンプルではテナントの指定をクエリパラメータでしています。テナントごとに URL が変わるので、アクセスするだけでテナントの指定まで完了しているような振る舞いをイメージしました。

const searchParams = new URLSearchParams(window.location.search);
const tenantId = searchParams.get("tenant_id");
firebase.auth().tenantId = tenantId;

このアプリは firebase deploy コマンドを実行するだけでホスティングできます。

Firebase プロジェクトが作成されている前提で、HTML ファイルを配置しているディレクトリで下記コマンドを実行します。対話式でプロジェクトの指定や使用するサービスが設定できます。

$ firebase login
$ firebase init

デプロイごとに下記コマンドを実行するとホスティングができます。HTML ファイルなので 1 ~ 2 分程度で完了します。

$ firebase deploy --only hosting

動作確認

動作を確認してみましょう。

https://<Project ID>.web.app/?tenant_id=<Tenant ID> にアクセスします (<Project ID><Tenant ID> は自分の環境に合わせて置き換えてください)。

まずはテナント A のログインを試します。tenant_id パラメータの指定をテナント A の tenant_id に設定し、テナント A 内に作成したユーザーのメールアドレスとパスワードでログインします。

テナント A のユーザーでログイン

ログインに成功しました。

テナント A のユーザーでログイン

なお、ログアウトした状態でテナント B のユーザーでログインしようとすると新規登録フォームになるので、テナント A に存在していないユーザーであることがわかります。

存在しないユーザーでのログイン

続いて tenant_id をテナント B に変えて、テナント B に登録したユーザーのメールアドレスでログインしてみます。

テナント B のユーザーでログイン

ログインに成功しました。

テナント B のユーザーでログイン

まとめ

今回はマルチテナンシーの機能をかんたんに試すため Email / Password 方式で実装しましたが、OIDC や SAML といったプロバイダも設定することができます。

BtoB サービスにおいてはそういったプロバイダをサポートすることで、各社の ID 基盤を使った SSO が可能になるので利便性が向上すると思います。ぜひ試してみてください。

明日は iamkdada
さんの「OpenID Foundation の SSF、CAEP、RISC の概要と Microsoft Entra ID での実装について」です。お楽しみに!

Google Cloud Japan

Discussion