![[新機能]Streamlit in Snowflake のアプリをロールを介さず個別ユーザーに共有できるようになったので試してみた](https://devio2024-media.developers.io/image/upload/f_auto,q_auto,w_3840/f_auto,q_auto/v1790874280/eyecatch/wsr0koxw01pat9lxglvp.png)
[新機能]Streamlit in Snowflake のアプリをロールを介さず個別ユーザーに共有できるようになったので試してみた
かわばたです。
2026年10月12日に、Streamlit in Snowflake アプリを個別ユーザーに共有する機能 が一般提供になりました。これまで共有先はロールだけだったため、「この人にだけダッシュボードを見せたい」場合でも専用ロールを作る運用が必要でした。
本記事では、TPC-H サンプルデータの簡易ダッシュボードを Snowsight の Workspaces から trial アカウントにデプロイします。そのうえで、SQL・Share ダイアログ・Workspaces のデプロイダイアログの 3 つの経路で 1 人のユーザーに共有し、閲覧者側の見え方を確認します。
【公式ドキュメント】
Share Streamlit in Snowflake apps with users(リリースノート)
Sharing Streamlit in Snowflake apps
ユーザー単位共有の概要
Streamlit in Snowflake アプリの共有は、アプリ本体と格納先の DB・スキーマへの USAGE 権限で制御します。今回の GA で、その付与先にロールだけでなくユーザーを直接指定できます。
| ロールへの共有(従来) | ユーザーへの共有(今回 GA) | |
|---|---|---|
| 付与先 | GRANT ... TO ROLE |
GRANT ... TO USER |
| Snowsight の操作 | Share ダイアログでロール名を検索 | 同じダイアログでユーザー名を検索 |
| 権限レベル | View only / View and share | 同じ(View and share は WITH GRANT OPTION 相当) |
| DB・スキーマの USAGE 不足 | 別途付与 | ダイアログ内の Grant USAGE ボタンで付与 |
| 通知 | なし | Snowsight 内通知。メール検証済みならメールも届く |
| 有効条件 | ロールが有効なセッション | secondary roles がすべて有効なセッション |
付与の経路は 3 つあります。SQL の GRANT、デプロイ済みアプリの Share ダイアログ、そして Workspaces のデプロイダイアログの Sharing 欄です。本記事では 3 つとも試します。閲覧者は、どの経路で付与されてもブラウザからアプリを開きます。アプリの URL は 2 種類あります。
| URL | 形式 | 表示 |
|---|---|---|
| App-builder URL | https://app.snowflake.com/<org>/<account>/#/streamlit-apps/<db>.<schema>.<app> |
Snowsight のツールバー付き。権限に応じて Edit / Share ボタンが出る |
| App-viewer URL | https://app.snowflake.com/streamlit/<org>/<account>/#/apps/<url_id> |
アプリ画面のみ。USAGE を持つ全員が開ける |
<url_id> は SHOW STREAMLITS または DESCRIBE STREAMLIT の url_id 列で確認できます。
前提条件
- 閲覧者にはアプリ本体、DB、スキーマの 3 つに USAGE が必要です(ロール経由でもユーザー直接でも可)
- ユーザーへの直接付与は、セッションで secondary roles がすべて有効なときだけ作用します
- Workspaces からデプロイするアプリはコンテナランタイムで動きます。アプリ所有ロールにコンピュートプールの USAGE と、デプロイ先スキーマの CREATE STREAMLIT が必要です
- 政府リージョンでは利用できません。エディション要件はドキュメントに記載がありません(trial アカウントで動作を確認済み)
2026年10月22日に、AWS 東京リージョンの trial アカウントで検証しました。操作はすべて Snowsight のブラウザ画面で行い、SQL は Workspace の SQL ファイルから実行しています。
事前準備
ロール・DB・閲覧者ユーザーの作成
アプリ所有ロール SIS_APP_OWNER と格納先 DB を作ります。閲覧者用のロールはあえて作りません。
USE ROLE ACCOUNTADMIN;
CREATE ROLE SIS_APP_OWNER;
GRANT ROLE SIS_APP_OWNER TO ROLE SYSADMIN;
GRANT ROLE SIS_APP_OWNER TO USER <自分のユーザー名>;
CREATE DATABASE SIS_SHARE_DB;
CREATE SCHEMA SIS_SHARE_DB.APPS;
GRANT OWNERSHIP ON SCHEMA SIS_SHARE_DB.APPS TO ROLE SIS_APP_OWNER COPY CURRENT GRANTS;
GRANT OWNERSHIP ON DATABASE SIS_SHARE_DB TO ROLE SIS_APP_OWNER COPY CURRENT GRANTS;
-- データとコンピュートの権限はアプリ所有ロールにだけ付ける
GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE SIS_APP_OWNER;
GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE_SAMPLE_DATA TO ROLE SIS_APP_OWNER;
GRANT READ SESSION ON ACCOUNT TO ROLE SIS_APP_OWNER;
共有先のユーザー SIS_VIEWER を 1 人作ります。ロールは一切付与しません(既定の PUBLIC のみ)。共有の付与に認証情報は要りませんが、閲覧者としてブラウザからサインインするためにパスワードを設定します。
CREATE USER SIS_VIEWER TYPE = PERSON DISPLAY_NAME = 'SIS Viewer'
PASSWORD = '<任意のパスワード>' MUST_CHANGE_PASSWORD = FALSE;
SHOW USERS で確認すると、新規ユーザーの default_secondary_roles は ["ALL"] でした。allowed_interfaces は [ALL] です。
Workspaces からダッシュボードをデプロイする
SNOWFLAKE_SAMPLE_DATA.TPCH_SF1 の注文を年で絞り、KPI・月次推移・地域別・優先度別の 4 つを表示する簡易ダッシュボードです。
ダッシュボードスクリプト
import streamlit as st
from snowflake.snowpark.context import get_active_session
st.set_page_config(page_title="TPC-H Sales Dashboard", layout="wide")
session = get_active_session()
SAMPLE = "SNOWFLAKE_SAMPLE_DATA.TPCH_SF1"
YEARS = list(range(1992, 1999)) # TPC-H の注文日は 1992-01-01 〜 1998-08-02
@st.cache_data(ttl=600)
def run_query(sql: str, params: tuple):
"""集計クエリの結果をキャッシュする(閲覧者が変わっても同じ結果なので共有してよい)。"""
return session.sql(sql, params=list(params)).to_pandas()
def session_context():
"""閲覧者ごとに異なる値なのでキャッシュしない。"""
row = session.sql(
"SELECT CURRENT_USER() AS CURRENT_USER, CURRENT_ROLE() AS CURRENT_ROLE"
).collect()[0]
return row["CURRENT_USER"], row["CURRENT_ROLE"]
# ---- Sidebar -------------------------------------------------------------
with st.sidebar:
st.header("Filters")
year = st.selectbox("Order year", YEARS, index=YEARS.index(1997))
st.divider()
st.caption("Session context (owner's rights)")
try:
current_user, current_role = session_context()
st.write(f"CURRENT_USER(): `{current_user}`")
st.write(f"CURRENT_ROLE(): `{current_role}`")
except Exception as exc: # READ SESSION が無い場合など
st.caption(f"context unavailable: {exc}")
# ---- Header ----------------------------------------------------------------
st.title("TPC-H Sales Dashboard")
st.caption(f"Source: {SAMPLE} / Year: {year}")
# ---- KPI -------------------------------------------------------------------
kpi = run_query(
f"""
SELECT COUNT(*) AS ORDERS,
ROUND(SUM(O_TOTALPRICE), 2)::FLOAT AS REVENUE,
ROUND(AVG(O_TOTALPRICE), 2)::FLOAT AS AVG_ORDER
FROM {SAMPLE}.ORDERS
WHERE YEAR(O_ORDERDATE) = ?
""",
(year,),
).iloc[0]
c1, c2, c3 = st.columns(3)
c1.metric("Orders", f"{int(kpi['ORDERS']):,}")
c2.metric("Revenue", f"${kpi['REVENUE'] / 1e6:,.1f}M")
c3.metric("Avg order value", f"${kpi['AVG_ORDER']:,.0f}")
# ---- Monthly trend -----------------------------------------------------------
monthly = run_query(
f"""
SELECT TO_CHAR(DATE_TRUNC('month', O_ORDERDATE), 'YYYY-MM') AS ORDER_MONTH,
ROUND(SUM(O_TOTALPRICE), 2)::FLOAT AS REVENUE
FROM {SAMPLE}.ORDERS
WHERE YEAR(O_ORDERDATE) = ?
GROUP BY 1
ORDER BY 1
""",
(year,),
)
st.subheader("Monthly revenue")
st.line_chart(monthly, x="ORDER_MONTH", y="REVENUE")
# ---- Region / priority -------------------------------------------------------
left, right = st.columns(2)
region = run_query(
f"""
SELECT r.R_NAME AS REGION,
ROUND(SUM(o.O_TOTALPRICE), 2)::FLOAT AS REVENUE
FROM {SAMPLE}.ORDERS o
JOIN {SAMPLE}.CUSTOMER c ON o.O_CUSTKEY = c.C_CUSTKEY
JOIN {SAMPLE}.NATION n ON c.C_NATIONKEY = n.N_NATIONKEY
JOIN {SAMPLE}.REGION r ON n.N_REGIONKEY = r.R_REGIONKEY
WHERE YEAR(o.O_ORDERDATE) = ?
GROUP BY 1
ORDER BY 2 DESC
""",
(year,),
)
with left:
st.subheader("Revenue by region")
st.bar_chart(region, x="REGION", y="REVENUE")
priority = run_query(
f"""
SELECT O_ORDERPRIORITY AS PRIORITY, COUNT(*) AS ORDERS
FROM {SAMPLE}.ORDERS
WHERE YEAR(O_ORDERDATE) = ?
GROUP BY 1
ORDER BY 1
""",
(year,),
)
with right:
st.subheader("Orders by priority")
st.bar_chart(priority, x="PRIORITY", y="ORDERS")
with st.expander("Region detail"):
st.dataframe(region, use_container_width=True, hide_index=True)
Snowsight の Workspaces でアプリを作り、デプロイします。
- Projects » Workspaces を開き、My Workspace で + Add new » Streamlit app を選びます。
streamlit_app.py、pyproject.toml、snowflake.yml、.streamlit/config.tomlの入ったフォルダが作られます - エディタのロールを
SIS_APP_OWNER、ウェアハウスをCOMPUTE_WHにし、streamlit_app.pyを上のコードに置き換えます


-
Run を押すと、自分だけが見られる開発用アプリでプレビューできます。開発用アプリは他のユーザーに共有できません

-
Deploy を押すと、ダイアログが開きます。Location は
SIS_SHARE_DBとAPPS、Execution はコンピュートプールとクエリ用ウェアハウスです

- Sharing 欄は空のまま Deploy を押します。ここでロールやユーザーを指定する方法は、後の節で試します
デプロイすると SIS_SHARE_DB.APPS に Streamlit オブジェクトができ、Projects » Streamlit の一覧から開けます。アプリは所有者権限で動くため、閲覧者にサンプルデータやコンピュートの権限は付与しません。

SIS_VIEWERでは確認できない

試してみた
SQL でユーザーに直接共有する
公式ドキュメントどおり、3 つの USAGE を TO USER で付与します。実行ロールは DB・スキーマ・アプリを所有する SIS_APP_OWNER です。
USE ROLE SIS_APP_OWNER;
GRANT USAGE ON DATABASE SIS_SHARE_DB TO USER SIS_VIEWER;
GRANT USAGE ON SCHEMA SIS_SHARE_DB.APPS TO USER SIS_VIEWER;
GRANT USAGE ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD TO USER SIS_VIEWER;
SHOW GRANTS TO USER SIS_VIEWER;

granted_to が USER の行として記録されます。SHOW GRANTS ON STREAMLIT <アプリ名> でも同じ行が見えるので、アプリ側からの棚卸しもできます。
閲覧者 SIS_VIEWER でブラウザから Snowsight にサインインします。Projects » Streamlit の一覧にアプリが出て、開くとダッシュボードが表示されます。ツールバーに Edit / Share はありません。SQL で付与した場合、Snowsight の通知は届きません。

権限の効き方は、閲覧者 SIS_VIEWER のセッションで SQL を実行しても確かめられます。持っているロールは PUBLIC だけなのに、SHOW STREAMLITS にアプリが出ます。
SELECT CURRENT_USER(), CURRENT_ROLE(), CURRENT_SECONDARY_ROLES();
-- SIS_VIEWER | PUBLIC | {"roles":"","value":"ALL"}
SHOW STREAMLITS IN ACCOUNT;
-- SALES_DASHBOARD | SIS_SHARE_DB | APPS | TPC-H Sales Dashboard | owner: SIS_APP_OWNER

secondary roles を切ると見えなくなる
ドキュメントには、ユーザーへの直接付与は secondary roles がすべて有効な場合にだけ効果を持つとあります。閲覧者のセッションで切り替えて確かめます。
USE SECONDARY ROLES NONE;
SHOW STREAMLITS IN ACCOUNT; -- No data
SHOW DATABASES LIKE 'SIS_SHARE_DB'; -- No data
USE SECONDARY ROLES ALL;
SHOW STREAMLITS IN ACCOUNT; -- SALES_DASHBOARD が再び表示される
ユーザーの既定値側も試します。管理者で DEFAULT_SECONDARY_ROLES = () にしてから、閲覧者で新しいセッションを開始しました。
-- 管理者
ALTER USER SIS_VIEWER SET DEFAULT_SECONDARY_ROLES = ();
-- 閲覧者(新しいセッション)
SELECT CURRENT_SECONDARY_ROLES(); -- {"roles":"","value":""}
SHOW STREAMLITS IN ACCOUNT; -- No data
SHOW GRANTS TO USER SIS_VIEWER; -- No data(自分への付与も見えない)

('ALL') に戻すと、次のセッションからアプリも自分への付与も見えます。
注意:
DEFAULT_SECONDARY_ROLES = ()のユーザーには、Share ダイアログで共有しても権限が有効になりません。
View and share で再共有できる
Snowsight の「View and share」は WITH GRANT OPTION 相当です。SQL で付け直し、閲覧者本人が別ユーザーに再共有できるか試します。再共有の相手として、権限を何も持たないユーザー SIS_VIEWER2 を用意します。
-- 管理者: 再共有の相手を用意する
CREATE USER SIS_VIEWER2 TYPE = PERSON DISPLAY_NAME = 'SIS Viewer 2'
PASSWORD = '<任意のパスワード>' MUST_CHANGE_PASSWORD = FALSE;
-- アプリ所有ロール: View and share 相当に付け直す
GRANT USAGE ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD
TO USER SIS_VIEWER WITH GRANT OPTION;
-- 閲覧者(SIS_VIEWER、ロールは PUBLIC のみ): 別ユーザーへ再共有する
GRANT USAGE ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD TO USER SIS_VIEWER2;
SHOW GRANTS ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD;
再共有は成功し、granted_by にユーザー名、granted_by_role_type に USER が記録されました。誰が誰に共有したかを後から追えます。

ただし、これだけでは SIS_VIEWER2 の Projects » Streamlit の一覧にアプリは出ません。閲覧には DB とスキーマの USAGE も要りますが、View and share の閲覧者が再共有できるのはアプリの USAGE だけだからです。DB・スキーマの USAGE は、それらを付与できる所有者側が別途付けます。
View and share を渡しても、閲覧者同士で共有が完結するわけではありません。DB・スキーマの USAGE はロールで広めに配っておき、アプリ単位の共有だけをユーザーに任せる運用が現実的だと考えます。
-- アプリ所有ロール(SIS_APP_OWNER): 再共有先が開けるようにする
GRANT USAGE ON DATABASE SIS_SHARE_DB TO USER SIS_VIEWER2;
GRANT USAGE ON SCHEMA SIS_SHARE_DB.APPS TO USER SIS_VIEWER2;
共有を止める
Snowsight のゴミ箱アイコンに相当する操作は、アプリの USAGE だけの REVOKE です。
CASCADE を付けると再共有先の分もまとめて取り消せます。再共有先だけ残したい場合は、所有者が再共有先へ直接 USAGE を付け直してから取り消します。
USE ROLE SIS_APP_OWNER;
-- SIS_APP_OWNER
REVOKE USAGE ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD FROM USER SIS_VIEWER CASCADE;
SHOW GRANTS ON STREAMLIT SIS_SHARE_DB.APPS.SALES_DASHBOARD; -- OWNERSHIP の 1 行だけになる

閲覧者側では SHOW STREAMLITS が空になります。一方で SHOW DATABASES LIKE 'SIS_SHARE_DB' には DB が残ったままです。
次の Share ダイアログの検証に備えて、DB・スキーマの USAGE も取り消し、付与なしの状態に戻しておきます。
REVOKE USAGE ON SCHEMA SIS_SHARE_DB.APPS FROM USER SIS_VIEWER;
REVOKE USAGE ON DATABASE SIS_SHARE_DB FROM USER SIS_VIEWER;
Snowsight の Share ダイアログから共有する
同じ閲覧者 SIS_VIEWER に、何も付与していない状態から Snowsight で共有します。
-
Projects » Streamlit » SALES_DASHBOARD を開き、Share を選びます

-
Grant to a role or person に
SIS_VIEWERと入力し、候補から選びます -
DB・スキーマの USAGE が無いため、ユーザー名の横に警告アイコンが出ます
-
Grant USAGE を押すと、Done を押す前に DB・スキーマの USAGE が付与されます
-
右のドロップダウンで View only を選び、Done を押します

共有された SIS_VIEWER で Snowsight にサインインすると、通知にアプリ共有の案内が届きます。SQL で付与したときとの違いはこの通知だけで、アプリの見え方は同じです。

Workspaces のデプロイダイアログから共有する
3 つ目の経路は、Workspaces からデプロイするときに Sharing 欄で共有先を指定する方法です。閲覧者を付与なしの状態に戻してから試します。
- Workspace でアプリのフォルダを開きます
- Sharing 欄に
SIS_VIEWER2を追加し、権限レベルを View only にします - DB・スキーマの USAGE が無いため警告アイコンが出ます。Grant USAGE を押して付与します
- Save Grants を押します。

付与の結果は SQL で確認できます。
SHOW GRANTS TO USER SIS_VIEWER2;

共有先のリストは Workspace の snowflake.yml に保存され、以降のデプロイでも同じ付与が繰り返されます。デプロイのたびに Share ダイアログで付け直す手間がありません。

閲覧者をアプリ専用ユーザーにする
閲覧だけさせたいユーザーには ALLOWED_INTERFACES を設定します。app-viewer URL を渡しただけでは、Snowsight の他の画面にも入れるためです。
USE ROLE ACCOUNTADMIN;
ALTER USER SIS_VIEWER SET ALLOWED_INTERFACES = (STREAMLIT);
設定後の SIS_VIEWER が開けるのは、権限のあるアプリの app-viewer URL だけです。Snowsight のホームやワークスペースに移動するとアクセスエラーになります。

app-viewer URLでは閲覧可

ALTER USER ... UNSET ALLOWED_INTERFACES で [ALL] に戻ります。
制限事項・注意点
制限事項・注意点
- ユーザーへの直接付与は secondary roles がすべて有効なセッションでだけ有効です。
USE SECONDARY ROLES NONEを実行したセッションではアプリが見えなくなります - 共有停止(ゴミ箱アイコン / REVOKE)で取り消されるのはアプリの USAGE だけです。DB・スキーマの USAGE は残ります
- SQL で付与した場合、Snowsight 内通知もメール通知も送られません
- Share ダイアログの警告アイコンは、ユーザーへの直接付与の有無だけで表示が決まります。ロール経由で USAGE を持つユーザーは、警告が出ていても Grant USAGE なしでアプリを開けます
- app-viewer URL を受け取った閲覧者は、既定では URL を書き換えて Snowsight の他の画面にも入れます。閲覧専用ユーザーには
ALLOWED_INTERFACES = (STREAMLIT)を設定してください - Workspaces のアプリはコンテナランタイムのみ対応です。開発用アプリ(Run で動くもの)は共有できず、共有するには先にデプロイが必要です
- デプロイダイアログで指定した共有先は Workspace の
snowflake.ymlに保存され、以降のデプロイでも同じ USAGE が付与されます。デプロイ済みアプリの編集と再デプロイはアプリの所有者だけができます - 政府リージョンでは利用できません
最後に
ロールを作らずに、SQL の GRANT ... TO USER 3 文、Share ダイアログ、デプロイダイアログのどれからでもダッシュボードを共有できました。
付与は secondary roles 経由で評価されるため、閲覧者側のセッション設定も含めて案内するのが確実です。
閲覧専用の相手には ALLOWED_INTERFACES = (STREAMLIT) を組み合わせると安全です。
この記事が何かの参考になれば幸いです!










