SupersetをSPCSでうごかしたい
記事探したけどなかった。
SPCS
Snowflakeの中でコンテナ動かせるサービス。
以下のが基礎がわかりやすい。基本的に何でも動きます。
https://speakerdeck.com/__allllllllez__/jin-ri-karashi-merareru-spcsnokihon
Apache Superset
OSSのBIツールです。ちょい大変だけどPythonで設定したらなんでもできます。SSOだってi18nだってできます。
割と前からあって、継続的に開発されていて現役です。Redashとは違います。
https://superset.apache.org
Snowflakeにも昔からつながります。
https://dev.classmethod.jp/articles/try-connect-to-snowflake-with-apache-superset/
直近だとこんな記事あった
https://qiita.com/suu_dev/items/82fec21aab7196014aeb
で、Snowflakeはとてもいいんですが、ダッシュボードがもうちょーっと充実していると嬉しいので安価にたてれるSupersetをSPCSでやると、ユーザー権限とかもいい感じにできるのでいい感じになるのではということです。
ポイント
Supersetの設定
Supersetは立てるときにsuperset_config.pyにPythonコードで設定を書くというストロングスタイルです。なので、なんでもカスタマイズ可能です。i18nもデフォルト対応してるのにsuperset_config.pyに書く必要があるというありさま。
ユーザー
SPCSのなかのサービスではリクエストに Sf-Context-Current-User ヘッダーを付与されるので、これをSuperset側でみてやって、ユーザーがこれってみることができます。これやってやるとSSOも不要です。
Superset 側は AUTH_REMOTE_USER(superset/config/superset_config.py)で、WSGI 環境変数 REMOTE_USER を見てログインする感じの実装してやればいいです。
以下の感じのコードを書いて
class SnowflakeRemoteUserMiddleware:
"""Copy Sf-Context-Current-User into REMOTE_USER with optional mapping."""
def __init__(self, app: Callable[[dict[str, Any], Callable], Any]):
self.app = app
self.map = json.loads(os.getenv("SF_SUPERSET_USER_MAP", "{}"))
self.default_policy = os.getenv("SF_USER_UNMAPPED_POLICY", "create")
self.fallback_user = os.getenv("SF_FAKE_REMOTE_USER")
def __call__(self, environ: dict[str, Any], start_response: Callable):
sf_user = environ.get("HTTP_SF_CONTEXT_CURRENT_USER") or self.fallback_user
if sf_user:
mapped = self._resolve_user(sf_user)
if mapped is None:
start_response("403 Forbidden", [("Content-Type", "text/plain")])
return [b"Superset access denied: user mapping missing"]
environ["REMOTE_USER"] = mapped
return self.app(environ, start_response)
def _resolve_user(self, sf_user: str) -> str | None:
key = sf_user.upper()
if key in self.map:
return self.map[key]
policy = self.default_policy.lower()
if policy == "deny":
return None
normalize = os.getenv("SF_USERNAME_NORMALIZER", "lower")
if normalize == "identity":
return sf_user
return sf_user.lower()
ADDITIONAL_MIDDLEWARE = [SnowflakeRemoteUserMiddleware]とかやってサービス立ち上げると
からの
みたいにSuperset側での認証不要でSnowflakeのユーザーでそのままSupersetのユーザーとすることができます。おんなじ感じでロールもなんかできるはずです(未)
その辺は適当に動く状態にしたgithubのレポジトリがあるのでそっち参照でよろしくおねがいします。
Snowflakeへの接続
Supersetではデータベースへは内部でsqlalchemy使って接続文字列をGUIで組み立てて接続する仕組みになっています。
データベース接続設定のできるロールを持つユーザーでデータベースへ接続ってやるとでてきます。
デフォルトだとSnowflakeコネクタははいってないので最初に設定でコネクタはrequirements.txtに書いておく必要があります。
で、SPCS特有の問題なんですが、SPCSの中からSnowflakeのデータベースにつなぐのに、ネットワーク設定が必要です。普通にやると。なので、External Access IntegrationをAccount Adminとかで作ってやって、自分のSnowflake宛のインターネット接続を許可してやる必要があります。なお、同じノリで任意の外部サービスにつなぐこともできます。
とはいえ折角Snowflakeの中に閉じているので中からアクセスしたいです。SPCSの中からSnowflakeのデータベースを叩くにはSPCS が注入する OAuth トークン(/snowflake/session/token)で 同一アカウントへ“内側”接続する方式を使います。
Supersetでは設定だけじゃなくてデータベース接続エンジンなんかもオーバーライドできるのでSPCSのトークンがあったらオーバーライドしてアカウントとかの設定を無視してヘッダーからトークンとってきてつなぐみたいなSnowflakeエンジンを書いてオーバーライドしてやると、EAIしなくても接続可能です。
なんか一応できました。
かなり無茶苦茶で洗練もされてませんが、こんな感じ
sqlalchemyにはじかれるのでダミーのアカウントとかを記載したデータベース接続を作ってやって
で、超適当だけど、こんな感じのダッシュボードも簡単にできてしまいます。

細かい使い方とかは他の記事見てくださいな。
その他
PostgresでメタデータのデータベースもってるのでPostgressをいまはSPCSでまとめて立ててるけど、Postgres Snowflakeに逃がせるはずで、たぶんだいぶはかどるはず。
まとめ
- SnowflakeのSPCSのなかでSupersetを動かしてみたよ
- SPCSのユーザーヘッダーとか使ってログインとかできるよ




