埋め込み Looker コンテンツに対する行レベルのセキュリティの実装

著者: シニア データ アナリストの Christopher Seymour、デベロッパー リレーションズ エンジニアの Dean Hicks

はじめに

Looker の埋め込み機能は、Looker プロダクトの最も強力で価値の高い機能の 1 つです。このガイドをお読みの方は、すでに Looker コンテンツをアプリケーションに組み込んでいるか、近い将来に組み込む可能性があります。

このガイドは、Looker の埋め込み機能の設計をより深く理解し、ユーザーにデータを配信するための強力で安全なアプリケーションを構築できるようにすることを目的としています。このトピックについては詳しく説明しますが、読みづらくなりますが、このガイドは単純な問題を簡単に修正できるものではなく、Looker の埋め込み全体をより適切に管理するための構成要素であることに留意してください。

ユースケースの概要

このガイドでは、お客様の会社が Looker コンテンツをプロダクトに埋め込む一般的なユースケースについて説明します。

この署名付き埋め込みのユースケースでは、自身が Looker インスタンスの管理者であると想定します。使用する埋め込みユーザーには、会社に関連するデータのみへのアクセスを許可する顧客(または「ブランド ユーザー」)アカウント所有者の 2 種類があり、複数の特定のお客様のデータにアクセスできます。 プロダクトを使用するすべての顧客に表示されるいくつかのタイルを含むダッシュボードがありますが、ダッシュボードにそのお客様に固有のデータのみが表示されるように、顧客ごとに自動的にフィルタする必要があります。このドキュメントの例では、HooliPied Piper の 2 つの架空の会社を使用します。

製品というテーブルがあるとします。このテーブルには、ブランド別の製品指標が表示されます。各ブランドは、署名付き埋め込みアプリケーションの異なる埋め込みユーザー(異なる external_user_id を持つ)に対応しています。各埋め込みユーザーには自分のブランドのデータのみを表示できるため、ブランド ユーザー属性のアクセス フィルタを使用する単純な Explore を作成します。

explore: products {
  access_filter: {
    field: products.brand
    user_attribute: brand
  }
}

この Explore に基づくシンプルなダッシュボードに、2 つのタイルがあります。1 つはブランドの名前を示し、もう 1 つはブランドの製品数を表示します。

create_sso_embed_url エンドポイントを使用して、埋め込みユーザーごとにこのダッシュボードの埋め込み URL を生成します。この例では、Ped Piper と Hooli の 2 つのブランドを使用しています。以下は、external_user_id pied_piper を指定して Pied Piper の create_sso_embed_url 呼び出しで使用するリクエスト本文です。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "pied_piper",
  "first_name": "PiedPiper",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Pied Piper"}
}

Pied Piper 用に生成した URL では、ダッシュボードが次のように表示されます。

次に、Hooli の create_sso_embed_url 呼び出しで使用されるリクエスト本文と external_user_id hooli を示します。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "hooli",
  "first_name": "Hooli",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Hooli"}
}

Hooli 用に生成された URL では、次のようにダッシュボードが表示されます。

Voilà!ダッシュボードは、各埋め込みユーザーのブランド ユーザー属性の値に従ってフィルタされます。

さらに詳しく

驚きの機能ですね。1 人のアカウント所有者に複数のブランドへのアクセス権を付与するにはどうすればよいですか?自分のデータが関連性の高いユーザーだけに表示されるようにするには、どうすればよいですか?

お客様はLooker の署名付き埋め込み機能は、デベロッパーがユーザー向けに強力な独自の仕様に基づくデータ エクスペリエンスを作成できるようにすると同時に、データモデルとコンテンツ アクセス ポリシーで定義されたデータ ガバナンスを維持できるように設計されています。

その強力なデータ エクスペリエンスを提供するには、データ ガバナンスを徹底的に行うことが非常に重要です。以下では、最適なユーザー エクスペリエンスを設計するためのコンセプトとベスト プラクティスをご紹介します。まずは、これらの仕組みの概要を説明します。

Looker の署名付き埋め込みの基本

埋め込みコンテキストにおける Looker のユーザー認証と管理は、基本的には非埋め込みコンテキストと同じ方法で、根本的に他のほとんどのウェブ アプリケーションと同様に機能するという点に注意することが重要です。

Looker の署名付き埋め込みのコンテキストでは、署名付き認証ステップ、ユーザー設定、ダッシュボード自体がすべて 1 つの長く複雑な URL に統合されているため、混乱を招く可能性があります。ただし、この URL はセッションを確立するために使用されます。これは URL が短縮された後も適用されます。このコンセプトを念頭に置くことは、優れたデータ エクスペリエンスの構築における成功に大いに役立ちます。

署名付き埋め込み URL の構造

Pied Piper のリクエスト本文を含む create_sso_embed_url 呼び出しによって生成される署名付き埋め込み認証 URL は次のとおりです。

https://mylookerinstance.cloud.looker.com/login/embed/%2Fembed%2Fdashboards%2F17?permissions=%5B%22access_data%22%2C%22see_user_dashboards%22%5D&models=%5B%22thelook%22%5D&signature=iG6vcKBgnA50jaL2iShFeQHwFPN7wvTx7Rz6r%2FtFuvE%3D&nonce=%22967729518a7dbb8a178f1c03a3511dd1%22&time=1696013242&session_length=300&external_user_id=%22pied_piper%22&access_filters=%7B%7D&first_name=%22Pied%22&last_name=%22Piper%22&user_attributes=%7B%22brand%22%3A%22Pied+Piper%22%7D&force_logout_login=true

同じ URL をデコードして個別の行に分割すると、次のようになります。

https://mylookerinstance.cloud.looker.com/login/embed/
/embed/dashboards/17
?permissions=["access_data","see_user_dashboards"]
&models=["thelook"]
&signature=iG6vcKBgnA50jaL2iShFeQHwFPN7wvTx7Rz6r/tFuvE=
&nonce="967729518a7dbb8a178f1c03a3511dd1"
&time=1696013242
&session_length=300
&external_user_id="pied_piper"
&access_filters={}
&first_name="PiedPiper"
&last_name="User"
&user_attributes={"brand":"Pied Piper"}
&force_logout_login=true

この URL にアクセスすると、次のことが起こります。

  1. Looker は external_user_id = pied_piper の既存のユーザー アカウントを探します。存在しない場合、Looker はその external_user_id を使用して新しいユーザー アカウントを作成します。

  2. 権限、モデル、グループ(指定されている場合)、ユーザー属性値(指定されている場合)など、既存のユーザーのアカウントの詳細は、URL で指定されたアカウントの詳細で上書きされます。

  3. Looker はユーザーを認証し、ブラウザにセッション Cookie を保存してそのユーザーのセッションを確立します。

  4. その後、Looker は、create_sso_embed_url 呼び出しで指定されたターゲット URL またはリダイレクト URL にリダイレクトします。

    https://mylookerinstance.cloud.looker.com/embed/dashboards/17

    このリダイレクト URL は、エンコードされた相対 URL として元の署名付き埋め込み URL で確認できます。

    %2Fembed%2Fdashboards%2F17

ステップ 1 ~ 3 はバックグラウンドで自動的に行われ、すべてのエンドユーザーが最終結果(ダッシュボード自体)に表示されますが、これらのステップは基本的に、埋め込み以外の通常の Looker ユーザーが認証するステップと同じです。ユーザーが、ユーザー名とパスワードの認証情報を使用してログインするとします。このプロセスは次のようになります。

  1. Looker 管理者の場合は、[Admin - Users] パネルに移動し、検索バーを使用して、このユーザーのユーザー アカウントがすでに存在するかどうかを確認します。そうでない場合は、新しいユーザー アカウントを作成します。

  2. 自分(Looker 管理者)が [Admin - Users] パネルでユーザーの横にある [Edit] をクリックし、権限、モデル、グループ、ユーザー属性値などの値でユーザーをプロビジョニングします。

  3. ユーザーが https://mylookerinstance.cloud.looker.com/login のログインページにアクセスし、ユーザー名とパスワードを入力します。Looker はユーザーを認証し、ブラウザにセッション Cookie を保存してそのユーザーのセッションを確立します。

  4. その後、Looker はランディング ページ(通常は https://mylookerinstance.cloud.looker.com/browse)にリダイレクトします。

セッション Cookie はブラウザ ウィンドウのすべてのタブに適用されます。ユーザーが https://mylookerinstance.cloud.looker.com/browse から開始して新しいブラウザタブを開き、ユーザーの権限でアクセスできる任意のページに移動すると、元のブラウザタブですでに確立されているセッション Cookie を使用して、ページが想定どおりに読み込まれます。

埋め込みユーザーも同様です。埋め込みユーザーには、UI でアクセスできるページがさらに制限されます。アクセスできる URL は、/embed 接頭辞が付いた Look、ダッシュボード、Explore の URL のみです。ただし、ユーザー アカウントの詳細によってアクセス権が付与されているダッシュボードには、引き続き手動で移動できます。元の署名付き埋め込み URL から、1 つのブラウザタブで https://mylookerinstance.cloud.looker.com/embed/dashboards/17 にリダイレクトされるとします。次に、新しいブラウザタブを開き、同じフォルダ(したがって、アクセス制限が同じ)にある別の埋め込みダッシュボード https://mylookerinstance.cloud.looker.com/embed/dashboards/19 を読み込みます。

元の署名付き埋め込み URL で指定されたリダイレクト URL はダッシュボード 17 用ですが、ブラウザタブに URL を手動で入力すれば、ダッシュボード 19 が想定どおりに読み込まれることを確認できます。別のダッシュボードを読み込むために、別の署名付き埋め込み URL は必要ありません。

ここでの重要なインサイトは、URL で確立されたすべてのユーザー アカウントの詳細(権限、ユーザー属性など)が、元の署名付き URL で指定された特定のダッシュボードだけでなく、ユーザー セッション全体に適用されることです。つまり、その名前が示すように、ユーザー属性はダッシュボードの機能ではなくユーザーの機能であり、1 つの特定のタブだけでなく、アプリケーション全体の特定のユーザーのアクセスレベルを決定するために使用する必要があります。

アカウント所有者のユースケース

カスタマイズ可能な他のソリューションと同様に、使用すべきではないアプローチも存在します。念のため、複数のブランドを所有または管理するアカウント所有者がいる場合について考えてみましょう。この例では、アカウント所有者が Pied Piper と Hooli の両方のブランドを管理しています。そのため、アプリでは前述の create_sso_embed_url 呼び出しで同じ入力を使用して両方の external_user_ids の URL を生成し、アカウント所有者がアクセスする各ダッシュボードを読み込むための新しいタブを作成します。デベロッパーがこのようなソリューションを実装することはよくあり、結果としてユーザーのワークフローは不正確となります。

  1. Pied Piper ダッシュボードのタブに移動します。
  2. Hooli ダッシュボードのタブに移動します。
  3. Pied Piper ダッシュボードのタブに戻ります。
  4. Pied Piper ダッシュボードで [再読み込み] ボタンをクリックします。

Pied Piper ダッシュボードには Hooli のデータが表示されます。

同様の方法を試すこともできますが、代わりに両方の create_sso_embed_url 呼び出しに同じ external_user_id test_user を使用してください。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "test_user",
  "first_name": "Test",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Pied Piper"}
}

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "test_user",
  "first_name": "Test",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Hooli"}
}

ただし、動作はまったく同じです。タブが Pied Piper ダッシュボードで再読み込みされると、代わりに Hooli のデータが表示されます。

何が起きているのでしょうか。各ブランドのダッシュボードにそのブランドのデータのみを表示するにはどうすればよいですか?

埋め込み以外の観点から同じアプローチ

前のセクションで説明したように、署名付き埋め込みユーザー セッションは、通常の埋め込み以外の Looker ユーザー セッションと基本的に同じように機能します。そのため、通常の埋め込み以外の Looker ユーザーのコンテキストで、前述の問題のあるアプローチを再構築しておくと役立ちます。セッションとステップごとの詳細を確認することで、このソリューションをより堅牢に実装する方法を理解できます。Looker UI にアクセスできる標準の BI ユーザーに指示を出す場合、そのワークフローは次のようになります。

  1. [Admin - Users] ページで、2 つの異なるユーザー アカウントを作成します。
    1. 最初のユーザー アカウントの編集ページで、brand ユーザー属性値を pied_piper に設定します。
    2. 2 番目のユーザー アカウントの編集ページで、brand ユーザー属性値を hooli に設定します。
  2. 両方のユーザー アカウントのアカウント設定メールを、アカウント所有者に送信します。
  3. アカウント所有者は、アカウントごとに個別のメールとパスワードの認証情報を設定します。
  4. アカウント所有者にダッシュボードへのリンクを付与します(https://mylookerinstance.cloud.looker.com/dashboards/17)。ブランド間でダッシュボードを切り替えるには、別のタブのログインページに戻り、他のユーザー アカウントのメールとパスワードの認証情報を入力してから、そのタブで再度ダッシュボードに表示されます。

アカウント所有者が手順に従います。ただし、2 番目のブラウザタブで Hooli ユーザー アカウントのユーザー名とパスワードを入力した後で、Piped Piper ダッシュボードがすでに読み込まれている最初のタブに戻り、[再読み込み] ボタンをクリックします。驚いたことに、ダッシュボードには Hooli のデータが表示されています。同じシナリオが埋め込みのコンテキストで表示されているだけですので、これは驚くべきことではありません。

後者の実装(異なるユーザー属性のセットで同じ external_user_id test_user を使用する)も、同じ方法で簡単に分割できます。このワークフローに相当する UI は次のようになります。

  1. アカウント所有者のユーザー アカウントを 1 つ作成します。
  2. そのユーザー アカウントの pied_piper 属性値として pied_piper を設定します。
  3. アカウント所有者に、Pied Piper から Hooli にダッシュボードを切り替えるよう連絡してもらう必要があることを伝えます。すると、そのユーザー アカウントの編集ページに移動して、brand 属性値を pied_piper から hooli mid-session に変更します。
  4. ユーザー属性を編集したら、新しいタブでダッシュボードを再度読み込んで、Hooli データを確認できます。

ここで、こう考えるかもしれません。

大変な作業のようです。単一のユーザー アカウントを割り当て、ダッシュボードのデータをブランドごとに個別にフィルタできるようにすることはできませんか?

はい、できます。これらのシナリオが、埋め込み以外のコンテキストではすでに自明であるが、埋め込みコンテキストの抽象化によって難読化される可能性がある原則を説明しています。1 人のユーザーを、単一のユーザー属性値のセットを持つ単一の Looker ユーザー アカウントに関連付ける必要がありますこれは、署名付き埋め込みのドキュメントにある external_user_id の説明でも明確に示されています。

Looker では、署名付き埋め込みユーザーの区別に external_user_id が使用されるため、各ユーザーに一意の ID を割り当てる必要があります。

任意の文字列を持つユーザーの external_user_id は、そのユーザーに固有のものであれば作成できます。各IDは、権限、ユーザー属性、モデルのセットに関連付けられています。1 つのブラウザが一度にサポートできるのは、1 つの external_user_id またはユーザー セッションだけです。セッション内でユーザーの権限やユーザー属性を変更することはできません。

これらのベスト プラクティスを活用する

この例に上述の原則を適用すると、アプリケーション全体でアカウント所有者がアクセスする必要があるすべてのデータに対するアクセス権を付与する単一のユーザー属性値が必要になります。これを行うには、brand 属性にカンマ区切りの値 Pied Piper,Hooli を使用します。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "test_user",
  "first_name": "Test",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Pied Piper,Hooli"}
}

この構文が機能するためには、ユーザー属性が [String Filter (advanced)] に設定されていることを確認する必要があります。

データアクセス レベルに変更が加えられた場合、ユーザーのユーザー属性のセットを変更できます。たとえば、アカウント所有者が 3 番目のブランドの所有権を取得している場合は、brand ユーザー属性に指定したカンマ区切りリストにその 3 番目のブランドを追加できます。こうすることで、ユーザーがログアウトして再度ログインしたときに、変更が適用されます。

ダッシュボード結果のフィルタリング

わかりました。ユーザー属性では、ユーザーがアプリケーション全体でアクセスできるすべてのデータを指定する必要があります。しかし、この方法でユーザー属性を指定すると、これらすべてのブランドのデータがダッシュボードに表示されます。特定のダッシュボードの結果を特定のブランドに絞り込むにはどうすればよいですか?

特定のダッシュボードをフィルタする正しい方法は、通常のダッシュボード フィルタを使用することです。(これは明白なように思えるかもしれませんが、埋め込みコンテキストでフィルタを適用する唯一の方法としてのユーザー属性に行き詰まる人々もいます。おそらく、user_attributes は署名付き埋め込み URL のパラメータであり、フィルタはそうではないためです)。

必ずフィルタ値を必須にして、プルダウンなどの単一選択コントロール オプションのいずれかを使用してください。

必要なすべてのタイルの正しいフィールドにフィルタが適用されていることを確認します。

プルダウンで選択できるオプションはユーザー属性によって制限されるため、アカウント所有者はこれらの 2 つの値(この 2 つのみ)を選択できます。

ダッシュボードフィルタの事前入力

これで、ダッシュボードを特定のブランドでフィルタできるようになりました。ただし、ユーザーがアプリでそのブランドのダッシュボードを読み込んだときに、フィルタの値をすでに特定のブランドに設定したいとします。

ここでも、埋め込み以外のコンテキストでこれがどのように機能するかを考えておくと役立ちます。特定のフィルタ値がすでに適用されているダッシュボードへのリンクを他のユーザーに送るにはどうすればよいですか?フィルタ値を選択すると、そのフィルタ値がダッシュボードの URL に表示されます。

create_sso_embed_url 呼び出し用の target_url に URL のその部分を含めます。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17?Brand=Hooli",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "test_user",
  "first_name": "Test",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Pied Piper,Hooli"}
}

Embed SDK を使用している場合は、withFilters を使用して、埋め込みコンテンツに適用する初期フィルタを指定できます。

https://looker-open-source.github.io/embed-sdk/classes/EmbedBuilder.html#withFilters

独自のカスタム スクリプトを使用している場合は、パスがエンコードされる前にフィルタを URL に追加していることを確認してください。一部の値はすでにフィルタ文字列でエンコードされている可能性があります(たとえば、?Brand=Pied+Piper に + としてエンコードされるスペースがある場合)。それらの値は最終ページ URL では二重エンコードされます。詳しくは、SO 埋め込みダッシュボード - URL の一部としてダッシュボード フィルタを設定しますか?をご覧ください。こうしたニュアンスに関するディスカッションの Looker コミュニティ投稿。フィルタの適用がうまくいかない場合は、こちらのコミュニティ投稿で質問をご投稿ください。

ダッシュボード フィルタの非表示

ダッシュボードに初期フィルタを設定する方法はわかりましたが、アカウント所有者がダッシュボード フィルタを自分で変更しないようにしたいのですが、フィルタ値は、アカウント所有者がどのダッシュボードにアクセスしたかによってのみ決定する必要があります。ダッシュボード フィルタを非表示にするにはどうすればよいですか?

これにはテーマを使用できます。テーマは有料機能であるため、Looker インスタンスでまだ有効にしていない場合は、Looker のセールスチームに連絡して有効にしてもらう必要があります。

この機能を有効にしたら、[Admin - Themes] ページの [ダッシュボードのコントロール] セクションに移動し、[フィルタバーを表示] オプションの選択を解除します。

次に、テーマをデフォルトとして設定するか、特定のダッシュボードの URL でテーマを適用します。この場合も、create_sso_embed_url 呼び出しの target_url に入ります。

{
  "target_url": "https://mylookerinstance.cloud.looker.com/embed/dashboards/17?Brand=Hooli&theme=test_theme",
  "session_length": 300,
  "force_logout_login": true,
  "external_user_id": "test_user",
  "first_name": "Test",
  "last_name": "User",
  "permissions": ["access_data","see_user_dashboards"],
  "models": ["thelook"],
  "user_attributes": {"brand":"Pied Piper,Hooli"}
}

一部の埋め込み SDK コード スニペットなど、埋め込みダッシュボード フィルタを非表示にする方法について詳しくは、この YouTube チュートリアルのカスタム フィルタを使用して Looker を埋め込むをご覧ください。

最終的な結果は、元の質問のユーザー エクスペリエンスと同じになります。

現在は、アプリに埋め込まれているそれぞれのターゲット URL にフィルタ値がエンコードされているため、各ブランドのダッシュボードには、タブを行き来しても、適切なブランドにフィルタされたダッシュボードが常に表示されます。

他のユーザーとしての sudo の実行

現在、ユーザー エクスペリエンスは当初の想定にかなり近いものになりました。ただし、このユースケースでは、アカウント所有者は external_user_id=pied_piperexternal_user_id=hooli の個々のユーザーには異なる権限やユーザー設定があるため、UI に異なるオプションが表示され、ユーザー エクスペリエンス全体で若干異なります。アカウントの所有者に対して、すべてが pied_piper pied_piper とまったく同様に表示されるようにして、ユーザーに対して、アカウント所有者が実際にはこれらのユーザーとしてログインしたかのように表示されるようにしたいと思います。どうすればいいですか?

ご希望されている内容は「sudo」と呼ばれます。アカウント所有者に各ブランド ユーザーとして「sudo」を許可する場合は、同様の sudo 関数をアプリに構築して、アカウント所有者が Pied Piper ユーザーとして sudo を実行した場合は external_user_id=pied_piper の埋め込み URL を読み込み、アカウント所有者が Hooli ユーザーとして sudo を実行した場合は external_user_id=hooli の埋め込み URL を読み込みます。また、アプリで API を使用する場合は、login_user API エンドポイントを使用して、ブランド ユーザーとして sudo を行うこともできます。

ただし、非埋め込みコンテキストについてもう一度考えてみましょう。[Admin - Users] ページで、複数のタブで複数の非埋め込みユーザーとして sudo を同時に行うことはできません。sudo セッションは、他のすべてのユーザー セッションと同様に、ブラウザ ウィンドウ全体に適用されます。そのため、sudo は、同時に 1 人だけのユーザーとして sudo を設計する必要があります。考えてみると、この設計は、sudo を実行しているユーザーのエクスペリエンスを完全に模倣しています。たとえば、pied_piper ユーザーは Pied Piper ダッシュボードにのみアクセスでき、追加タブで追加ダッシュボードを開くことはできません。そのため、このユーザーとして sudo を実行している場合は、別のタブで別のダッシュボードを開くことはできません。

まとめ

このガイドがお役に立てば幸いです。Looker の署名付き埋め込みコンテンツを作成する準備が整ったと感じていらっしゃることでしょう。Google は、Looker を最も柔軟で堅牢な組み込み型データ分析サービスの開発に取り組んでおります。皆様からのご意見をお待ちしています。ご質問がある場合や詳細については、Looker コミュニティに参加し、コミュニティ イベントにご参加ください。