シークレットを管理し、Streamlitアプリを設定する

Streamlitアプリは、しばしば API キー、パスワード、およびその他の認証情報などの機密情報にアクセスする必要があります。Streamlitアプリでシークレットをどのように管理するかは、使用しているランタイム環境によって異なります。 Streamlit in Snowflake は、ウェアハウスとコンテナランタイムの両方でシークレットにアクセスするための安全な組み込みメカニズムを提供します。Streamlitの構成では、各ランタイムにも異なる制限があります。

Streamlitライブラリでは、アプリは .streamlit/ ディレクトリを使用して構成とシークレットを保存します。

  • .streamlit/config.toml:テーマ、レイアウト、サーバーの動作などのアプリの設定をカスタマイズします。

  • .streamlit/secrets.toml:API キーや認証情報などの機密情報を保管します(ローカル開発の場合)

Streamlit in Snowflake はこれらのファイルをサポートしていますが、ランタイム環境に応じていくつかの制限があります。次のテーブルは、ウェアハウスとコンテナランタイムにおけるこれらのファイルのサポートをまとめたものです。

機能

ウェアハウスランタイム

コンテナランタイム

config.toml サポート

構成オプションの限られたサブセット

構成オプションのより広範なサブセット

secrets.toml サポート

サポート対象外

サポートされていますが、非シークレットの環境変数に対してのみ推奨されます。

secrets.toml の場合、 Streamlit in Snowflake は、機密情報の管理に推奨される、より安全な組み込みのシークレット管理システムを提供します。次のセクションでは、アプリでSnowflakeのシークレットを使用する方法について説明します。

Snowflakeへの接続の管理

Snowflakeへの接続を管理するには、 st.connection("snowflake") を使用します。これにより、ローカルの開発環境とデプロイされたアプリの両方からSnowflakeに接続できます。

import streamlit as st

conn = st.connection("snowflake")
session = conn.session()

session.sql("SELECT 1").collect()
Copy

ウェアハウスのランタイムでは、Snowparkのアクティブなセッションを取得する get_active_session() 関数を使用できます。

import streamlit as st
from snowflake.snowpark.context import get_active_session

# ONLY IN WAREHOUSE RUNTIMES
session = get_active_session()
session.sql("SELECT 1").collect()
Copy

重要

get_active_session() はスレッドセーフではなく、コンテナランタイムでは使用できません。

コンテナランタイムのシークレット

コンテナランタイムはストアドプロシージャ環境の外部で実行されるため、 _snowflake モジュールにアクセスできません。コンテナランタイムでシークレットにアクセスするには、 _snowflake モジュールを使用する SQL 関数を作成する必要があり、Streamlitアプリからこれらの関数を呼び出します。Cortex用 API 呼び出しの場合は、 requests を使用する必要があります。

古いStreamlitアプリをコンテナランタイムにアップグレードした場合、次の _snowflake 関数はストアドプロシージャに置き換える必要があります。これについては次のセクションで説明します。

  • get_generic_secret_string

  • get_oauth_access_token

  • get_username_password

  • get_cloud_provider_token

  • get_secret_type

さらに、次の _snowflake 関数は、セッショントークンで認証された手動 API 呼び出しに置き換える必要があります。これは後のセクション コンテナランタイム内でのCortex Agentの呼び出し で説明します。

  • send_snow_api_request

コンテナランタイムでシークレットにアクセスする

コンテナランタイムでシークレットにアクセスするには、以下の手順を実行します。

  1. Snowflakeアカウントにシークレットを作成します。CREATE SECRET をご参照ください。

    CREATE OR REPLACE SECRET my_secret
      TYPE = GENERIC_STRING
      SECRET_STRING = 'my_secret_value';
    
    Copy
  2. シークレットにアクセスする関数を作成します。シークレットアクセスのためのPython API をご参照ください。

    CREATE OR REPLACE FUNCTION get_my_secret()
      RETURNS STRING
      LANGUAGE PYTHON
      RUNTIME_VERSION = 3.12
      HANDLER = 'get_my_secret'
      EXTERNAL_ACCESS_INTEGRATIONS = (my_eai)
      SECRETS = ('my_secret' = my_secret)
      AS
    $$
    import _snowflake
    
    def get_my_secret():
      return _snowflake.get_generic_secret_string('my_secret')
    $$;
    
    Copy
  3. コンテナランタイムでStreamlitアプリを作成します。

    CREATE STREAMLIT my_container_app
      FROM '@my_stage/app_folder'
      MAIN_FILE = 'streamlit_app.py'
      RUNTIME_NAME = 'SYSTEM$ST_CONTAINER_RUNTIME_PY3_11'
      COMPUTE_POOL = my_compute_pool
      QUERY_WAREHOUSE = my_warehouse
      EXTERNAL_ACCESS_INTEGRATIONS = (my_eai);
    
    Copy
  4. Streamlitアプリのコードで、 SQL 関数を呼び出してシークレットを取得します。

    import streamlit as st
    
    # Get the Snowflake connection
    conn = st.connection("snowflake")
    session = conn.session()
    
    # Call the function to retrieve the secret
    secret = session.sql("SELECT get_my_secret()").collect()[0][0]
    
    Copy

非シークレット環境変数に .streamlit/secrets.toml を使用する

技術的には .streamlit/secrets.toml ファイルをアプリのソースディレクトリに追加できますが、 実際のシークレットを保存するためには推奨されていませんsecrets.toml ファイルはステージングされたファイルにプレーンテキストとして保存されますが、これはセキュリティのベストプラクティスではありません。

ただし secrets.toml は、コード内で st.secrets 経由でアクセスする、または依存関係で環境変数として必要な、機密性のない構成値や環境固有の設定を保存するのに役立ちます。

# .streamlit/secrets.toml
# ONLY USE FOR NON-SECRET CONFIGURATION VALUES
app_name = "My Streamlit App"
api_endpoint = "https://api.example.com"
max_results = 100
Copy

その後、st.secrets または環境変数を通じてアプリ内でこれらの値にアクセスできるようになります。

import streamlit as st
import os

app_name = st.secrets["app_name"]
API_ENDPOINT = os.getenv("API_ENDPOINT")
Copy

API キー、パスワード、トークンのような実際のシークレットの場合、前のセクションで説明したように、常にSnowflakeの組み込みシークレット管理システムを使用します。

コンテナランタイム内でのCortex Agentの呼び出し

コンテナランタイムアプリでCortex Agentを呼び出すには、基になる Snowpark Container Services コンテナからセッショントークンを読み取り、 requests ライブラリを使用します。これは、 _snowflake.send_snow_api_request() に推奨される交換です。

import requests
import json
import os

SNOWFLAKE_HOST = os.getenv("SNOWFLAKE_HOST")
SNOWFLAKE_ACCOUNT = os.getenv("SNOWFLAKE_ACCOUNT")
ANALYST_ENDPOINT = "/api/v2/cortex/analyst/message"
URL = "https://" + SNOWFLAKE_HOST + ANALYST_ENDPOINT

def get_token() -> str:
    """Read the oauth token embedded into SPCS container"""
    return open("/snowflake/session/token", "r").read()

def send_request(semantic_model_file, prompt):
    """Sends the prompt using the semantic model file """
    headers = {
        "Content-Type": "application/json",
        "accept": "application/json",
        "Authorization": f"Bearer {get_token()}",
        "X-Snowflake-Authorization-Token-Type": "OAUTH"
    }
    request_body = {
        "messages": [
            {
                "role": "user",
                "content": [{"type": "text", "text": prompt}],
            }
        ],
        "semantic_model_file": semantic_model_file,
    }
    return requests.post(URL, headers=headers, data=json.dumps(request_body))
Copy

ウェアハウスランタイムのシークレット

ウェアハウスのランタイムでは、 _snowflake モジュールを使用して、Streamlitアプリコード内のシークレットに直接アクセスできます。ウェアハウスランタイムは、ストアドプロシージャから _snowflake モジュールへのアクセスを継承し、これによりStreamlitオブジェクトで参照されるシークレットを取得できるようになります。

ウェアハウスランタイムでシークレットを使用するには次のようにします。

  1. Snowflakeでシークレットオブジェクトを作成します。詳細については、 CREATE SECRET をご参照ください。

    CREATE OR REPLACE SECRET my_secret
      TYPE = GENERIC_STRING
      SECRET_STRING = 'my_secret_value';
    
    Copy
  2. 外部アクセス統合を作成し、それにシークレットを割り当てます。

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION my_eai
      ALLOWED_AUTHENTICATION_SECRETS = (my_secret)
      ENABLED = TRUE;
    
    Copy
  3. SECRETS パラメーターを使用して、Streamlitオブジェクト内のシークレットを参照します。

    ALTER STREAMLIT my_warehouse_app
      SET EXTERNAL_ACCESS_INTEGRATIONS = (my_eai)
      SECRETS = ('my_secret_key' = my_secret);
    
    Copy

    外部アクセス統合とシークレットの両方をStreamlitオブジェクトに割り当てる必要があります。Streamlitオブジェクトに単独でシークレットを割り当てることはできません。

  4. Streamlitアプリのコードで、 _snowflake モジュールをインポートしてシークレットを取得します。

    import streamlit as st
    import _snowflake
    
    # Retrieve an API key from a generic string secret
    my_secret = _snowflake.get_generic_secret_string('my_secret_key')
    
    Copy

_snowflake モジュールを使用したシークレットへのアクセスの詳細については、 シークレットアクセスのためのPython API をご参照ください。

Streamlit構成

Streamlitアプリには、構成ファイル(.streamlit/config.toml)を含めることができます。このファイルを使うと、テーマ、レイアウト、動作など、アプリの様々な側面をカスタマイズできます。構成ファイルは TOML 形式で書き込まれます。使用可能な構成オプションの詳細については、Streamlitドキュメントの config.toml をご参照ください。

構成オプションのサポートは、ランタイム環境によって異なります。コンテナランタイムは通常、特に静的サービングのために、ウェアハウスランタイムよりも広範な構成オプションのサポートを提供します。次のテーブルは、ウェアハウスとコンテナランタイムでサポートされている構成セクションを示しています。

構成セクション

ウェアハウスランタイム

コンテナランタイム

[global]

サポート対象外

限定サポート(disableWidgetStateDuplicationWarning

[logger]

サポート対象外

サポート対象外

[client]

サポート対象外

限定サポート(showErrorDetailsshowSidebarNavigation

[runner]

サポート対象外

サポート対象

[server]

サポート対象外

サポート対象外

[browser]

サポート対象外

サポート対象外

[mapbox]

サポート対象外

サポート対象(非推奨、代わりに環境変数を使用)

[theme]

サポート対象

サポート対象

[theme.sidebar]

サポート対象

サポート対象

[secrets]

サポート対象外

サポート対象(ただし、非シークレット環境変数の場合のみ推奨)

[snowflake.sleep]

サポート対象

該当なし

[snowflake.sleep] セクションを使用してウェアハウスランタイムでスリープタイマーを構成する方法については、 Streamlitアプリのカスタムスリープタイマー を参照してください。

次のディレクトリ構造は、構成ファイルを使用したStreamlitアプリの例です。

source_directory/
├── .streamlit/
│   └── config.toml
├── pyproject.toml
├── streamlit_app.py
└── uv.lock
Copy