HDE BLOG

コードもサーバも、雲の上

Power BI embedded で RLS (Row Level Security) を使ってみる

HDEはマルチテナントクラウドサービスを展開していますが、サービスのログは全テナント分が一箇所に集まってきます。これらのログを各テナントに提供すべくPower BI embeddedに可能性を探りました。このブログではPower BI embeddedのRLS (Row Level Security)を使って、アクセス毎にそれぞれのテナントのログを表示させるウェブアプリケーションの実装を紹介します。

必要なもの

このブログで使用したものは以下の通りです。

RLS (Row Level Security)とは?

上記リポジトリにサンプルの PBIX ファイルをおきました。これは無料のWindowsデスクトップアプリケーションであるPower BI Desktopで作ったものです。ぜひ開いて中身を見て下さい。一般的にPBIXファイルにはデータやモデル、レポートが含まれています。このPBIXファイルにはサービスへのログイン情報がデータとして含まれています。ここではログイン日時とテナント名(domain)のみを残し、IPアドレス、ユーザーエージェントなどの、ここで使用しない情報は取り除いてあります。さらにテナントは "tokyo.example.com" と "osaka.example.com" だけに絞っています。ちなみにPBIXファイルを開けない人向けに参照用に生データもリポジトリに置いておきました。

このPBIXファイルは毎時のログイン数を表示する簡単なレポートを含んでいます。

f:id:michael-wangsa:20180926120036p:plain

このレポートは全テナントのログを表示しています。これから作成するウェブアプリケーションでは、テナントAのユーザーにはテナントAのログのみ、テナントBのユーザーにはテナントBのログのみ表示といった具合にアクセスしたユーザーことに表示を切り替えることを可能にします。

つまり"tokyo.example.com"のユーザーは以下のようなレポートを見ることになります。

tokyo.example.com
tokyo.example.com

"osaka.example.com"のユーザーが見るレポートはこちらです。

osaka.example.com
osaka.example.com

Power BIのRLSを使うためには「ロール」の設定が必要になります。このサンプルでは「viewer」というロールを設定しています。このロールでは、「domain」が外部から入力される「USERNAME()」に一致する行のみ表示することができます。 それではRLSを実装するウェブアプリケーションをみていきましょう。

f:id:michael-wangsa:20180926120228p:plain

ウェブアプリケーションの概要

以下のようなフローになっています。

f:id:michael-wangsa:20180926120246p:plain

  1. ウェブアプリケーションは、Power BIのAPIを実行するのに必要なアクセストークンをAzure ADから取得します。
  2. ウェブアプリケーションはロールやテナント情報をPower BIに送信し、Embed tokenを取得します。
  3. ウェブアプリケーションはEmbed tokenをブラウザに返します。
  4. ブラウザ(powerbi.js)はEmbed tokenをPower BIに送り、レポートを取得します。

次は、ウェブアプリケーションとPower BI embeddedを作成します。

App registration

App registrationsは、Power BIのAPIを呼ぶのに必要です。

Azureポータルから「App registrations」を検索し新規作成します。「New application registration」は下記のように記載します。なぜ「Native」を選択するのか気になりますが、ここではスルーして下さい。あとで触れます。

Azure ADの権限を以下のように付与します。

f:id:michael-wangsa:20180926120307p:plainf:id:michael-wangsa:20180926120317p:plainf:id:michael-wangsa:20180926120352p:plain

さらにPower BIの権限も以下のように付与します。

f:id:michael-wangsa:20180926120412p:plainf:id:michael-wangsa:20180926120425p:plain

「Grant permission」を忘れずにクリックして下さい。

f:id:michael-wangsa:20180926120755p:plainf:id:michael-wangsa:20180926120813p:plain

「Application ID」はあとで必要になるのでコピーしておいて下さい。

Power BI embeddedの作成

AzureポータルからPower BI embeddedを作成します。「capacity administrator」にはPower BI Proのライセンスを付与したユーザーを指定します。

Power BI embeddedが作成されたら https://app.powerbi.com/ にアクセスし「app workspace」を作成します。ここでワークスペース名を指定し、「dedicated capacity」にはAzure上で作成したPower BI embeddedを指定します。ワークスペース名はウェブアプリケーション内で指定するので忘れないようにして下さい。

f:id:michael-wangsa:20180926120536p:plainf:id:michael-wangsa:20180926120514p:plainf:id:michael-wangsa:20180926120932p:plain

さらに「Files」メニューからPBIXファイルをアップロードします。

f:id:michael-wangsa:20180926120943p:plain

ローカルでウェブアプリケーションの実行

クローンしたリポジトリのディレクトリに移動し、アプリケーションをインストールします。

pip install .

環境変数は以下のように設定します。

export PBI_AUTHORITY="https://login.microsoftonline.com/common"
export PBI_RESOURCE="https://analysis.windows.net/powerbi/api"
export PBI_WORKSPACE_NAME="Power BI embedded sample"
export PBI_REPORT_NAME=powerbi-embedded-sample
export PBI_VIEW_ROLE=viewer
export PBI_USERNAME=${username}
export PBI_PASSWORD=${password}
export PBI_CLIENTID=${client_id}

「PBI_USERNAME」および「PBI_PASSWORD」はPower BI ProライセンスユーザーのログインIDとパスワードです。「PBI_CLIENTID」はAzure ADに登録したアプリケーションのIDです。 「PBI_WORKSPACE_NAME」はPower BIのワークスペース名、「PBI_REPORT_NAME」はPBIXのフィル名です。

そして下記コマンドでウェブアプリケーションを実行します。

powerbi-embedded-sample

http://localhost:8000/"」にアクセスするとテナント名「tokyo.example.com」と「osaka.example.com」のリンクが表示されます。リンクはそれぞれのテナントのPower BI RLSで生成されたレポートが表示されます。本来はそれぞれ認証が必要なのですが、ここでは省略しています。


以上がPower BI embeddedによるRLSの紹介になりますが、少々気になることがあります。アプリケーションのタイプに「Native」を指定し、環境変数にパスワードを指定したことからわかる通り、このウェブアプリケーションのOAuth 2.0のグラントフローは「password」になります。この手のアプリケーションであれば「client credentials」が適しているはずですが。 崎村先生が指摘している通り、パスワードグラントは使うべきではありません。これはどうやらAzure ADとPower BIの間に問題がありそうです。Power BIはライセンスが付与されたユーザー権限でアクセスする必要がある一方で、Azure ADのclient credentialsグラントでは特定のユーザーのアクセストークンが取得できないようです。Azure ADか、Power BIのライセンス体系にアップデートがない限り、パスワードグラントを使うしかなさそうです。