Snowpark Container Services: サービスのその他の考慮事項

コンテナー内部からのSnowflakeへの接続

サービス(ジョブサービスも含む)を開始すると、Snowflakeは実行中のコンテナに認証情報を提供し、コンテナコードがSnowflakeに接続して SQL を実行するためのドライバーを使用できるようにします(Snowflakeに接続するコンピューター上の他のコードと同様)。提供された認証情報は、所有者ロール(サービスを作成したロール)として認証されます。Snowflakeは、情報の一部をコンテナーの環境変数として提供します。

Snowflakeのすべてのオブジェクトには、所有者ロールがあります。サービスの所有者ロールは、Snowflakeと相互作用する際に、サービスが実行できる機能を決定します。これには SQL の実行、ステージへのアクセス、サービス間のネットワーキングが含まれます。

注釈

サービスの所有者ロールは、サービスを作成したロールになります。サービスが公開するエンドポイントへのアクセスを管理するために、1つ以上のサービスロールを定義できます。詳細については、 サービス関連権限の管理 をご参照ください。

サービスを作成すると、Snowflakeはそのサービス専用の サービスユーザー も作成します。サービスがクエリを実行すると、サービスの所有者ロールを使用して、サービスユーザーとしてクエリを実行します。サービスユーザーが何を実行できるかは、この所有者ロールによって決まります。

サービスの所有者ロールは、 ACCOUNTADMIN、 SECURITYADMIN などのいずれの権限ロールであってはなりません。これは、誤動作を起こしたサービスが実行できることを制限するためです。サービスが管理者業務を実行できるようにするためには、より意図的である必要があります。

特定のサービスユーザーが発行したクエリを表示するには、 ACCOUNTADMIN ロールを使用して、 クエリ履歴 を表示できます。サービス利用者の利用者名は以下の形式で表示されます。

  • 8.35サーバーリリース以前に作成されたサービスの場合、サービスユーザー名は SF$SERVICE$unique-id の形式です。

  • 8.35サーバーリリース以降に作成されたサービスでは、サービスユーザー名はサービス名と同じです。

Snowflakeへの接続

コンテナからSnowflakeに接続するには、2つの方法があります。

  • (推奨)Snowflakeが提供する OAuth トークンを使用します。サービスユーザーとして(または、呼び出し元権限も使用する場合は呼び出しユーザーとして)接続を確立します。このオプションはすべてのサービスで機能し、追加の権限を必要としません。ただし、クライアントコードで使用されるSnowflakeホスト名を構成する必要があります。

  • サービスがSnowflakeのインターネットエンドポイントに接続できるようにする、外部アクセス統合を使用します。これにより、Snowflakeが提供する OAuth トークンだけでなく、任意のSnowflake認証情報を使用できます。ただし、このオプションでは、管理者が外部アクセス統合を作成し、サービス所有者ロールに統合に対する USAGE 権限を付与する必要があります。

注釈

外部アクセス統合を使用してSnowflakeにアクセスすることは、潜在的にセンシティブな情報をインターネット経由で送信することを意味します。可能な限り、サービスは提供された OAuth トークンを使用して、 SNOWFLAKE_HOST ホスト名にアクセスすべきです。これにより、インターネットからSnowflakeにアクセスする必要がなくなります。Snowflakeに接続するためにさまざまなSnowflakeドライバーを使用するコードの例については、 Snowflake接続例 をご参照ください。

Snowflakeが提供する OAuth トークンによる接続

Snowflakeは、 /snowflake/session/token という名前のファイル内のコンテナに OAuth トークンを提供します。Snowflakeは、サービスコードでSnowflakeクライアントを構成するために、次の環境変数を設定します。

  • **SNOWFLAKE_ACCOUNT: ** サービスが現在実行されているSnowflakeアカウントの アカウントロケーター に設定されます。

  • SNOWFLAKE_HOST: Snowflakeへの接続に使用するホスト名を指定します。

コンテナーからSnowflakeへの接続を作成するときには、 SNOWFLAKE_HOST、 SNOWFLAKE_ACCOUNT、および OAuth トークンを使用する必要があります。SNOWFLAKE_HOST を使用せずに OAuth トークンを使用することはできず、 OAuth トークンをSnowpark Container Services外部で使用することはできません。詳細については、 SQL を実行するための OAuth トークンの使用 をご参照ください。

チュートリアル2main.py を参照)で、コードは次の例に示すように環境変数を読み取ります。

SNOWFLAKE_ACCOUNT = os.getenv('SNOWFLAKE_ACCOUNT')
SNOWFLAKE_HOST = os.getenv('SNOWFLAKE_HOST')
Copy

このコードは、これらの変数を選択したSnowflakeクライアントの接続作成コードに渡します。コンテナはこれらの認証情報を使用して、所有者ロールをプライマリロールとする新しいセッションを作成し、クエリを実行します。以下の例は、PythonでSnowflake接続を作成するために最低限必要なコードです。

def get_login_token():
  with open('/snowflake/session/token', 'r') as f:
    return f.read()

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth'
)
Copy

他の認証情報との接続

Snowflakeが提供する OAuth トークンだけでなく、他の形式の認証を使用してSnowflakeに接続できます。そのためには、コンテナがSnowflakeの外部で実行され、インターネットを介して接続しているかのように、コンテナがSnowflakeに接続できるようにする外部アクセス統合(EAI)を作成します。 この方法で接続する場合は、クライアントが使用するホストを構成する必要はありません。

注釈

これらの接続は EAI を通過するため、Snowflake認証もネットワークポリシーを強制します。ビジネスでネットワークポリシーが必要な場合は、他の認証情報との接続はサポートされません。

たとえば、以下の接続では、認証するユーザー名とパスワードを指定します。

conn = snowflake.connector.connect(
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  user = '<user-name>',
  password = '<password>'
)
Copy

デフォルトホストを使用するには、お客様のサービスからアカウントのSnowflakeホスト名へのアクセスを許可するネットワークルールと外部アクセス統合が必要です。例えば、アカウント名が組織 MYORG 内の MYACCOUNT の場合、ホスト名は myorg-myaccount.snowflakecomputing.com です。詳細については、 ネットワークエグレスの構成 をご参照ください。Privatelink ホスト名はサポートされていません

  • アカウントのSnowflake APIホスト名に一致するネットワークルールを作成します。

    CREATE OR REPLACE NETWORK RULE snowflake_egress_access
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('myorg-myaccount.snowflakecomputing.com');
    
    Copy
  • 先行するネットワークルールを使用する統合を作成します。

    CREATE EXTERNAL ACCESS INTEGRATION snowflake_egress_access_integration
      ALLOWED_NETWORK_RULES = (snowflake_egress_access)
      ENABLED = TRUE;
    
    Copy

SQL を実行するためのデータベースとスキーマコンテキストを設定します。

このセクションでは、2つの概念について説明します。

  • サービスを作成するデータベースとスキーマを決定するためにSnowflakeが使用するロジック。

  • Snowflakeがこの情報をコンテナーに伝え、コンテナーコードが同じデータベースとスキーマコンテキストで SQL を実行できるようにするためのメソッド。

Snowflakeはサービス名を使用して、サービスを作成するデータベースとスキーマを決定します。

  • 例1: 以下の CREATE SERVICE および EXECUTE JOB SERVICE コマンドでは、サービス名が明示的にデータベース名とスキーマ名を指定していません。Snowflakeは、現在のデータベースとスキーマでサービスとジョブサービスを作成します。

    -- Create a service.
    CREATE SERVICE test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service ...
    
    Copy
  • 例2: 以下の CREATE SERVICE と EXECUTE JOB SERVICE コマンドでは、サービス名にデータベース名とスキーマ名が含まれています。Snowflakeは、現在のスキーマに関係なく、指定されたデータベース(test_db)とスキーマ(test_schema)にサービスとジョブサービスを作成します。

    -- Create a service.
    CREATE SERVICE test_db.test_schema.test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = test_db.test_schema.example_job_service ...
    
    Copy

Snowflakeがサービスを開始する際は、以下の環境変数を使用して、実行中のコンテナにデータベースとスキーマ情報が提供されます。

  • SNOWFLAKE_DATABASE

  • SNOWFLAKE_SCHEMA

コンテナーコードでは、この例に示すように、接続コードで環境変数を使用して、使用するデータベースとスキーマを決定することができます。

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth',
  database = os.getenv('SNOWFLAKE_DATABASE'),
  schema = os.getenv('SNOWFLAKE_SCHEMA')
)
Copy

チュートリアル2 では、Snowflakeに接続して SQL ステートメントを実行するSnowflakeジョブサービスを作成します。以下のステップは、チュートリアルのコードがどのように環境変数を使用するかをまとめたものです。

  1. 共通セットアップ(共通セットアップ セクションを参照)では、データベースとスキーマを含む、リソースを作成します。また、セッションの現在のデータベースとスキーマも設定します。

    USE DATABASE tutorial_db;
    ...
    USE SCHEMA data_schema;
    
    Copy
  2. (EXECUTE JOB SERVICE を実行して)ジョブサービスを作成すると、Snowflakeはコンテナを起動し、コンテナ内の以下の環境変数をセッションの現在のデータベースとスキーマに設定します。

    • SNOWFLAKE_DATABASE は「TUTORIAL_DB」に設定

    • SNOWFLAKE_SCHEMA は「DATA_SCHEMA」に設定

  3. ジョブコード(チュートリアル2の main.py を参照)はこれらの環境変数を読み取ります。

    SNOWFLAKE_DATABASE = os.getenv('SNOWFLAKE_DATABASE')
    SNOWFLAKE_SCHEMA = os.getenv('SNOWFLAKE_SCHEMA')
    
    Copy
  4. ジョブコードは SQL ステートメント(main.pyrun_job() 関数)を実行するコンテキストとしてデータベースとスキーマを設定します。

    {
       "account": SNOWFLAKE_ACCOUNT,
       "host": SNOWFLAKE_HOST,
       "authenticator": "oauth",
       "token": get_login_token(),
       "warehouse": SNOWFLAKE_WAREHOUSE,
       "database": SNOWFLAKE_DATABASE,
       "schema": SNOWFLAKE_SCHEMA
    }
    ...
    
    Copy

    注釈

    SNOWFLAKE_ACCOUNT、SNOWFLAKE_HOST、 SNOWFLAKE_DATABASE、 SNOWFLAKE_SCHEMA はSnowflakeがアプリケーションコンテナー用に生成する環境変数ですが、 SNOWFLAKE_WAREHOUSE はそうではありません(Snowflakeはウェアハウス名をコンテナーに渡さないため、チュートリアル2のアプリケーションコードがこの変数を作成しました)。

コンテナー用ウェアハウスの指定

サービスがSnowflakeに接続してSnowflakeウェアハウスでクエリを実行する場合は、ウェアハウスを指定する以下のオプションがあります。

  • アプリケーションコードでウェアハウスを指定します。 コードでクエリを実行するためにSnowflakeセッションを開始する際に、接続構成の一部としてウェアハウスを指定します。例については、 チュートリアル2 をご参照ください。

  • Specify a default warehouse when creating a service. Specify the optional QUERY_WAREHOUSE parameter in the CREATE SERVICE or EXECUTE JOB SERVICE command to provide a default warehouse. If your application code doesn't provide a warehouse as part of connection configuration, Snowflake uses the default warehouse. Use the ALTER SERVICE command to change the default warehouse.

    注釈

    The warehouse specified using the QUERY_WAREHOUSE parameter is the default only for the service user. When the service connects to Snowflake on behalf of another user --- in the context of caller's rights scenario, Snowflake uses the user's default warehouse.

If you specify a warehouse by using both methods, the warehouse that is specified in the application code is used.

SQL を実行するための OAuth トークンの使用

Snowflakeが提供するすべてのクライアントは、認証方法として OAuth をサポートしています。サービスコンテナも OAuth メカニズムを使用してSnowflakeで認証を行います。たとえば、コンテナーが SQL を実行する場合、コンテナーは他のSnowflakeクライアントと同様にSnowflakeへの接続を作成します。

def get_login_token():
  with open('/snowflake/session/token', 'r') as f:
    return f.read()

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth'
)
Copy

サービスを作成すると、Snowflakeはコンテナを実行し、コンテナ内の /snowflake/session/token にコンテナが使用するOauthトークンを提供します。

この OAuth トークンについては、次の点に注意してください。

  • Snowflakeは、 /snowflake/session/token ファイルの内容を数分ごとに更新します。トークンの有効期限は1時間です。コンテナーがSnowflakeに正常に接続した後には、有効期限は接続に適用されません(ユーザーが直接作成するセッションと同様)。

  • この OAuth トークンは、特定のSnowflakeサービス内でのみ有効です。OAuth トークンをコピーしてサービス外部で使用することはできません。

  • コンテナは、 OAuth トークンを使ってサービスユーザーとしてSnowflakeに接続し、サービスの所有者ロールを使用します。

  • OAuth トークンを使用して接続すると、新しいセッションが作成されます。OAuth トークンはいずれの既存の SQL セッションとも関連付けられていません。

    注釈

    ストアドプロシージャの実行とサービスの実行の大きな違いは、ストアドプロシージャはそれを実行する SQL と同じセッションで実行されることです。しかし、コンテナーが新しい接続を確立するたびに、新しいセッションが作成されます。

Connections to Snowflake from inside a container by using caller's rights

Containers execute queries by connecting to Snowflake as the service user and using the service's owner role that grants privileges to the service. In certain application scenarios, you might need to execute queries by using the context of the end user rather than the service user. The caller's right feature is used in this context.

For example, suppose you create a service that exposes a public endpoint to provide a web application that displays a dashboard that uses data stored in Snowflake. You grant other users in your Snowflake account access to the dashboard by granting the service role to those users. When any one of these users signs in to the dashboard, you want the dashboard to display only the data the user has access to.

However, because containers by default execute queries by using the service user and the service's owner role, the dashboard shows the data that the service's owner role has access to, regardless of which end user connected to the endpoint. As a result, the data in the user's dashboard isn't limited to what the end user has access to. This allows the user to access data that they shouldn't be allowed to access.

To limit the dashboard to show only data accessible to the signed in user, the application containers must execute SQL by using privileges granted to the end user. You can enable this by using caller's rights in the application.

注釈

  • 呼び出し元権限機能は、ネットワーク・イングレスを使用して サービス  にアクセスする場合にのみサポートされます。サービス関数を使用してアクセスする場合は、この機能は使用できません。

  • 呼び出し元権限の機能は現在、 Snowflake Native App (コンテナー付きアプリ)ではサポートされていません。

サービスの呼び出し元権限の構成

アプリケーションの呼び出し元権限を構成するには、2つのステップがあります。

  1. サービス仕様executeAsCallertrue にセットします。

    spec:
      containers:
      ...
    capabilities:
      securityContext:
        executeAsCaller: true
    
    Copy

    これによりSnowflakeは、アプリケーションが呼び出し元権限を使用する意図があることを明示的に伝え、リクエストをアプリケーションコンテナーに送信する前に、すべての受信リクエストに Sf-Context-Current-User-Token ヘッダを挿入します。このユーザートークンは、呼び出しユーザーとしてのクエリ実行を容易にします。指定がない場合、 executeAsCaller のデフォルトは false です。

    executeAsCaller オプションを指定しても、サービスユーザーおよびサービスのオーナーロールとしてクエリを実行するサービスの能力には影響しません。executeAsCaller を有効にすると、サービスには、通話ユーザーとしてもサービスユーザーとしてもSnowflakeに接続するオプションがあります。

  2. アプリケーションコードを更新します。呼び出しユーザーの代わりにSnowflake接続を確立するには、コードを更新して、Snowflakeがサービス に提供した OAuth トークンと、 Sf-Context-Current-User-Token ヘッダーのユーザー トークンの両方を含むログイントークンを作成します。ログイントークンは以下の形式に従う必要があります。<service-oauth-token>.<Sf-Context-Current-User-Token>

    これは以下のPythonコードで示されています。

    # Environment variables below will be automatically populated by Snowflake.
    SNOWFLAKE_ACCOUNT = os.getenv("SNOWFLAKE_ACCOUNT")
    SNOWFLAKE_HOST = os.getenv("SNOWFLAKE_HOST")
    
    def get_login_token():
        with open("/snowflake/session/token", "r") as f:
            return f.read()
    
    def get_connection_params(ingress_user_token = None):
        # start a Snowflake session as ingress user
        # (if user token header provided)
        if ingress_user_token:
            logger.info("Creating a session on behalf of the current user.")
            token = get_login_token() + "." + ingress_user_token
        else:
            logger.info("Creating a session as the service user.")
            token = get_login_token()
    
        return {
            "account": SNOWFLAKE_ACCOUNT,
            "host": SNOWFLAKE_HOST,
            "authenticator": "oauth",
            "token": token
        }
    
    def run_query(request, query):
        ingress_user_token = request.headers.get('Sf-Context-Current-User-Token')
        # ingress_user_token is None if header not present
        connection_params = get_connection_params(ingress_user_token)
        with Session.builder.configs(connection_params).create() as session:
          # use the session to execute a query.
    
    Copy

上記の例では、

  • get_login_token 関数は、コンテナーが使用する OAuth トークンを Snowflake がコピーしたファイルを読み込みます。

  • get_connection_params 関数は、 OAuth トークンと Sf-Context-Current-User-Token ヘッダーのユーザートークンを連結してトークンを構築します。関数は、アプリケーションがSnowflakeに接続するために使用するパラメーターの辞書にこのトークンを含めます。

注釈

サービスが発信者権限を使用する場合、複数のユーザーとしてSnowflakeに接続できます。Snowflakeが管理していないリソースへのアクセス管理は、お客様の責任で行ってください。

例えばStreamlitアプリでは、 st.connection オブジェクトが st.cache_resource を使用して接続を自動的にグローバル状態にキャッシュし、異なるユーザーが開始したStreamlitセッション間でアクセスできるようにします。発信者権限を使用する場合、ユーザー間で接続を共有しないように、 st.session_state を使用してセッションごとに接続を保存することを検討してください。

For an example with step-by-step instructions, see Create a service with caller's rights enabled.

呼び出し元権限が構成されたサービスへのアクセス

呼び出し元権限の構成とは、発信者に代わってお客様のサービスがSnowflake接続を確立することです。サービスのイングレス・エンドポイントへのログイン方法(プログラムまたはブラウザを使用)は変わりません。ログイン後は以下のようになります。

  • ブラウザを使用してパブリックエンドポイントにアクセスします。エンドポイントにログインすると、サービスはユーザーの既定のロールを使用して、呼び出しユーザーの代わりにSnowflakeへの接続を確立します。ユーザーに既定のロールが構成されていない場合、 PUBLIC ロールが使用されます。

  • プログラムによるパブリックエンドポイントへのアクセス: JWT トークンを使って プログラムでエンドポイントにログインする場合、オプションで scope パラメーターをセットして、有効化するロールを指定することができます。

現在、サービスが呼び出し元に代わってSnowflakeへの正しい接続を確立した後、ロールの切り替えはサポートされていません。アプリケーションで異なるオブジェクトへのアクセスに異なるロールを使用する必要がある場合は、デフォルトですべてのセカンダリロールがアクティブになるようにユーザーをセットしてください。これを行うには、 ALTER USER コマンドを使用して、ユーザーの DEFAULT_SECONDARY_ROLES プロパティを ('ALL') にセットします。

ALTER USER my_user SET DEFAULT_SECONDARY_ROLES = ( 'ALL' );
Copy

サービスへの呼び出し元グラントの管理

サービスが呼び出し元権限セッションを作成する場合、セッションは呼び出し元のユーザーとして操作されます(サービスユーザーとしてではありません)。このセッションを使用して演算子が実行されると、Snowflakeは2つの権限チェックを適用します。

  1. 最初の権限のチェックは、ユーザーが直接セッションを作成したかのように行われます。これらはSnowflakeがユーザーに対して行う通常の権限チェックです。

  2. 2つ目の権限チェックは、サービスがユーザーに代わって操作を実行することを許可されているかどうかを確認します。Snowflakeは、サービス所有者ロールに必要な呼び出し元グラントが付与されていることを確認することで、これを検証します。

呼び出し元権限セッションにおいて、通常の権限チェックとサービス所有者ロールの 呼び出し元権限 チェックの両方が、その操作を許可しなければなりません。これは、 制限された呼び出し元権限 と呼ばれます。デフォルトでは、サービスはユーザーに代わって何かをする権限を持っていません。サービスが呼び出し元権限で実行できるように、呼び出し元権限を明示的に付与する必要があります。

例えば、ユーザー U1 が、テーブル T1 の SELECT 権限を持つロール R1 を使用しているとします。U1 が、呼び出し元権限を使用するように構成されたあなたのサービス (example_service) のパブリックエンドポイントにログインすると、サービスは U1 に代わって Snowflake との接続を確立します。

サービスが U1 に代わってテーブル T1 をクエリできるようにするには、サービスの所有者ロールに以下の権限を付与する必要があります。

  1. そのテーブルのデータベースとスキーマに対して、 USAGE 権限でサービスを実行することを許可する呼び出し元グラントを付与することで、テーブル名を解決する権限です。

  2. サービスをウェアハウス上で USAGE 権限で実行できるようにする呼び出し元グラントを付与することで、クエリを実行するためにウェアハウスを使用する権限です。

  3. テーブル T1 の SELECT 権限でサービスを実行できる呼び出し元グラントを付与することで、テーブルにクエリを実行できる権限です。

-- Permissions to resolve the table's name.
GRANT CALLER USAGE ON DATABASE <db_name> TO ROLE <service_owner_role>;
GRANT CALLER USAGE ON SCHEMA <schema_name> TO ROLE <service_owner_role>;
-- Permissions to use a warehouse
GRANT CALLER USAGE ON WAREHOUSE <warehouse_name> TO ROLE <service_owner_role>;
-- Permissions to query the table.
GRANT CALLER SELECT ON TABLE T1 TO ROLE <service_owner_role>;
Copy

あなたのアカウントでグローバル権限(MANAGE CALLER GRANT)を持つロールであれば、呼び出し元グラントを付与することができます。呼び出し元権限の詳細については、 GRANT CALLER および 制限された呼び出し元権限 をご参照ください。

An example of a service that uses the caller's rights feature when executing SQL queries on behalf of the users is provided. For more information, see Create a service with caller's rights enabled.

サービスクエリ履歴へのアクセス

user_type が SNOWFLAKE_SERVICE である場合、 QUERY_HISTORY ビュー または QUERY_HISTORY 関数をフィルターすることで、サービスによって実行されたクエリを見つけることができます。

例1: サービスによって実行されるフェッチクエリ。

SELECT *
FROM snowflake.account_usage.query_history
WHERE user_type = 'SNOWFLAKE_SERVICE'
AND user_name = '<service_name>'
AND user_database_name = '<service_db_name>'
AND user_schema_name = '<service_schema_name>'
order by start_time;
Copy

WHERE 句で、

  • user_name = '<service_name>': サービスは サービスユーザー としてクエリを実行し、サービスユーザーの名前はサービス名と同じであるため、ユーザー名としてサービス名を指定します。

  • user_type = 'SNOWFLAKE_SERVICE' および user_name = '<service_name>': これはクエリ結果を、あるサービスによって実行されたクエリのみを取得するように制限します。

  • user_database_name および user_schema_name: サービスユーザーにとって、これらはサービスのデータベースとスキーマです。

QUERY_HISTORY 関数を呼び出しても同じ結果が得られます。

SELECT *
FROM TABLE(<service_db_name>.information_schema.query_history())
WHERE user_database_name = '<service_db_name>'
AND user_schema_name = '<service_schema_name>'
AND user_type = 'SNOWFLAKE_SERVICE'
AND user_name = '<service_name>'
order by start_time;
Copy

WHERE 句で、

  • user_type = 'SNOWFLAKE_SERVICE' および user_name = '<service_name>' は、あるサービスによって実行されたクエリのみを取得するようにクエリ結果を制限します。

  • user_database_nameuser_schema_name の名前は、サービスユーザーの場合、サービスのデータベースとスキーマです。

例2: サービスによって実行されたクエリと対応するサービス情報を取得します。

SELECT query_history.*, services.*
FROM snowflake.account_usage.query_history
JOIN snowflake.account_usage.services
ON query_history.user_name = services.service_name
AND query_history.user_schema_id = services.service_schema_id
AND query_history.user_type = 'SNOWFLAKE_SERVICE'
Copy

このクエリは、 QUERY_HISTORY と SERVICES ビューを結合し、クエリとクエリを実行したサービスに関する情報を取得します。次の点に注意してください。

  • サービスによって実行されるクエリの場合、 query_history.user_name は、サービスユーザー名です。これは、サービス名と同じです。

  • クエリは、スキーマ IDs (スキーマ名ではない)を使用してビューを結合し、同じスキーマを参照していることを確認します。スキーマをドロップして再作成すると、スキーマ ID は変更されますが、名前は同じままだからです。

クエリにオプションのフィルターを追加することができます。例:

  • 特定のクエリを実行したサービスのみを取得するためのフィルター query_history

  • 特定のサービスによって実行されたクエリのみを取得するためのフィルター services

例3: すべてのサービスについて、サービスユーザー情報をフェッチします。

SELECT services.*, users.*
FROM snowflake.account_usage.users
JOIN snowflake.account_usage.services
ON users.name = services.service_name
AND users.schema_id = services.service_schema_id
AND users.type = 'SNOWFLAKE_SERVICE'
Copy

このクエリは、 ACCOUNT_USAGE スキーマの SERVICES と USERS ビューを結合し、サービスとサービスユーザー情報を取得します。次の点に注意してください。

  • サービスがクエリを実行すると、サービスユーザーとしてクエリを実行します。サービスユーザーの名前はサービス名と同じです。したがって、結合条件 users.name = services.service_name を指定します。

  • サービス名はスキーマ内でのみ一意です。したがって、クエリは、各サービスユーザーが所属する固有のサービス(そして、異なるスキーマで実行されている他の同じ名前のサービスではない)に対して一致することを確実にするために、結合条件(users.schema_id = services.service_schema_id)を指定します。

Google Cloudでのファイルステージングコマンドのサポート

Google CloudでSnowflakeクライアントライブラリを使用して PUT、 GET、 LIST、または REMOVE コマンドを使用するには、クライアントを少なくとも次のバージョンに更新します。

クライアント

バージョン

Go Snowflakeドライバー

1.14.1

Python用Snowflake Connector

3.16.0

.NET ドライバー

4.6.0

Node.jsドライバー

2.1.3

JDBCドライバー

3.25.1

ODBCドライバー

3.10.0

ネットワークイングレスの構成

インターネットからサービスとのやり取りできるようにするには、サービスがリッスンしているネットワークポートを、サービス仕様ファイルのエンドポイントとして宣言します。これらのエンドポイントはイングレスを制御します。

デフォルトでは、サービスエンドポイントはプライベートです。サービス関数サービス間通信 のみがプライベートエンドポイントにリクエストできます。エンドポイントをパブリックと宣言すると、インターネットからエンドポイントへのリクエストを許可することができます。パブリックエンドポイントの作成は権限操作であり、サービスの所有者ロールはアカウントで BIND SERVICE ENDPOINT 権限を持っている必要があります。

endpoints:
- name: <endpoint name>
  port: <port number>
  protocol : < TCP / HTTP >
  public: true
  corsSettings:                  # optional CORS configuration
    Access-Control-Allow-Origin: # required list of allowed origins
      - <origin>                 # for example, "http://example.com"
      - <origin>
        ...
    Access-Control-Allow-Methods: # optional list of HTTP methods
      - <method>
      - <method>
        ...
    Access-Control-Allow-Headers: # optional list of HTTP headers
      - <header-name>
      - <header-name>
        ...
    Access-Control-Expose-Headers: # optional list of HTTP headers
      - <header-name>
      - <header-name>
        ...
Copy

例については、 チュートリアル1 をご参照ください。

イングレス接続のタイムアウト

イングレスエンドポイントのタイムアウトは90秒です。イングレスエンドポイントへの接続に90秒間アクティビティがない場合、Snowflakeは接続を終了します。アプリケーションでもっと長く接続する必要がある場合は、ポーリングまたは WebSockets を使用します。

イングレスウェブブラウザー認証ログアウト

サービスとして動作するウェブアプリを構築している場合、ユーザーを /sfc-endpoint/logout に誘導してアプリからログアウトできるようにするオプションがあります。

ログアウト後、ユーザーはサービスのパブリックエンドポイントにアクセスするためにSnowflakeへの再認証が必要となります。

イングレスとウェブアプリのセキュリティ

パブリックエンドポイントサポート(ネットワークイングレス)を使用して、ウェブホスティング用のSnowpark Container Servicesサービスを作成できます。セキュリティを強化するために、Snowflakeはプロキシサービスを採用して、クライアントからサービスへの受信リクエストと、サービスからクライアントへの送信応答をモニターします。このセクションでは、プロキシが何を行い、Snowpark Container Servicesに展開されたサービスにどのような影響を与えるかを説明します。

注釈

ローカルでサービスをテストする場合はSnowflakeプロキシを使用しないため、Snowpark Container Servicesに展開した場合とローカルでサービスを実行した場合のエクスペリエンスに違いが生じます。このセクションを確認し、より良いテストのためにローカル設定を更新してください。

例:

  • 禁止されている HTTP メソッドをリクエストが使用する場合、プロキシは受信 HTTP リクエストを転送しません。

  • プロキシは、応答のContent-Typeヘッダーが実行可能ファイルを含むことを示す場合は、403応答をクライアントに送信します。

さらに、プロキシはリクエストと応答に新しいヘッダーを注入したり、既存のヘッダーを変更したりすることもできます。

たとえば、リクエストを受信すると、サービスは応答で HTML、 JavaScript、 CSS などのウェブページのコンテンツをクライアントのブラウザーに送信する可能性があります。ブラウザー上のウェブページはサービスの一部であり、ユーザーインターフェイスとして機能します。セキュリティ上の理由から、サービスに制限がある場合(他サイトへのネットワーク接続の制限など)に、サービスのウェブページにも同じ制限を設けたい場合があります。

デフォルトでは、サービスはインターネットにアクセスする権限が制限されている。ブラウザーでも、クライアントアプリがインターネットにアクセスし、データを共有する可能性を制限する必要があります。外部アクセス統合(EAI)を設定してサービスが example.comネットワークエグレスの構成 を参照)にアクセスできるようにすると、サービスのウェブページもブラウザーを通して example.com にアクセスできるようになります。

Snowflakeプロキシは、応答に Content-Security-Policy (CSP)ヘッダーを追加して、サービスとウェブページに同じネットワーク制限を適用します。デフォルトでは、プロキシは一般的なセキュリティの脅威から守るために、応答にベースライン CSP を追加します。ブラウザーのセキュリティは、機能性とセキュリティのバランスをとるためのベストエフォートであり、このベースラインがあなたのユースケースに適切であることを確認することは、共有された責任です。さらに、サービスが EAI を使用するように設定されている場合、プロキシはウェブページに対して EAI から CSP まで同じネットワークルールを適用します。この CSP により、ブラウザーのウェブページは、サービスがアクセスできるのと同じサイトにアクセスできるようになります。

Snowflakeは、サービス仕様で構成する CORS サポートを提供します。

Snowflakeプロキシは、サービス仕様で定義されている CORS 設定を返します。プロキシはサービスによって返された CORS ヘッダーをすべて削除することに注意してください。

以下の CORS ヘッダーはデフォルトでセットされています。

  • Access-Control-Expose-Headers ヘッダーは、エンドポイントのサービス仕様で構成されたヘッダーに加えて、常に以下のヘッダー名を報告します。

    • X-Frame-Options

    • Cross-Origin-Opener-Policy

    • Cross-Origin-Resource-Policy

    • X-Content-Type-Options

    • Cross-Origin-Embedder-Policy

    • Content-Security-Policy-Report-Only

    • Content-Security-Policy

  • Access-Control-Max-Age は2時間にセットされます。

  • Access-Control-Allow-Credentials はtrueにセットされます。

さらに、Snowflakeは、 Origin の値に基づいて、 Access-Control-Allow-Origin の値が異なる可能性があることをブラウザーに示すために、 Origin の値で Vary ヘッダーをセットします。

CORS リクエストを実行するには、 Authorization ヘッダーが必要です。このヘッダー(Authorization: "Snowflake Token=\"${patToken}\"")にプログラムによるアクセストークン(PAT)を指定できます。プログラムのアクセストークンを生成する方法については、 認証のためのプログラム アクセス トークンの使用 をご参照ください。

以下のセクションでは、Snowflakeプロキシがサービスに対する受信リクエストをどのように処理し、サービスからクライアントへの送信応答をどのように変更するかを説明します。

サービスへの受信リクエスト

リクエストを受信すると、プロキシはリクエストをサービスに転送する前に以下を実行します。

  • 禁止された HTTP メソッドを持つ受信リクエスト: 受信 HTTP リクエストが以下の禁止された HTTP メソッドのいずれかを使用する場合、プロキシはそのリクエストをサービスに転送しません。

    • TRACE

    • CONNECT

  • 受信リクエストヘッダーのスクラブ: Snowflakeプロキシは、以下のリクエストヘッダーが存在する場合は削除します。

    • X-SF-SPCS-Authorization

    • Authorization:Snowflakeトークンが含まれている場合のみ削除され、含まれていない場合はサービスに渡されます。

クライアントへの応答送信

Snowflakeプロキシは、クライアントに応答を転送する前に、サービスから送信された応答にこれらの修正を適用します。

  • ヘッダースクラビング: Snowflakeプロキシは、これらの応答ヘッダーを削除します(存在する場合)。

    • X-XSS-Protection

    • Server

    • X-Powered-By

    • Public-Key-Pins

  • CORS ヘッダー操作: 進入と CORS への配慮 を参照してください。

  • Content-Type応答ヘッダー: サービス応答でContent-Typeヘッダーに次の MIME 型の値(実行可能ファイルを示す)が含まれる場合、Snowflakeプロキシはその応答をクライアントに転送しません。代わりに、プロキシは 403 Forbidden 応答を送信します。

    • application/x-msdownload:Microsoftの実行可能ファイル。

    • application/exe: 汎用実行可能ファイル。

    • application/x-exe: 別の汎用実行可能ファイル。

    • application/dos-exe: DOS の実行可能ファイル。

    • application/x-winexe:Windowsの実行可能ファイル。

    • application/msdos-windows: MS-DOS Windows実行可能ファイル。

    • application/x-msdos-program: MS-DOS 実行可能ファイル。

    • application/x-sh:Unixシェルスクリプト。

    • application/x-bsh:Bourneシェルスクリプト。

    • application/x-csh:Cシェルスクリプト。

    • application/x-tcsh:Tcshシェルスクリプト。

    • application/batch:Windowsバッチファイル。

  • X-Frame-Options応答ヘッダー: クリックジャッキング攻撃を防ぐために、Snowflakeプロキシはこの応答ヘッダーを DENY に設定し、他のウェブページがサービスのウェブページにiframeを使用できないようにします。

  • Cross-Origin-Opener-Policy(COOP)応答ヘッダー: Snowflakeは COOP 応答ヘッダーを same-origin に設定し、参照元のクロスオリジンウィンドウがサービスタブにアクセスできないようにします。

  • Cross-Origin-Resource-Policy(CORP)応答ヘッダー: Snowflakeは CORP ヘッダーを same-origin に設定し、外部サイトが(iframeなどで)イングレスエンドポイントによって公開されたリソースをロードできないようにします。

  • X-Content-Type-Options応答ヘッダー: Snowflakeプロキシはこのヘッダーを nosniff に設定し、クライアントがサービスによって応答に記載された MIME 型を変更できないようにします。

  • Cross-Origin-Embedder-Policy(COEP)応答ヘッダー: Snowflakeプロキシは COEP 応答ヘッダーを credentialless に設定します。これは、画像やスクリプトなどのクロスオリジンオブジェクトをロードするときに、リモートオブジェクトがCross-Origin Resource Sharing(CORS)プロトコルをサポートしていない場合、Snowflakeはそれをロードするときに認証情報を送信しないことを意味します。

  • Content-Security-Policy-Report-Only応答ヘッダー: Snowflakeプロキシは、クライアントに CSP レポートをSnowflakeに送信するよう指示する新しい値で、この応答ヘッダーを置き換えます。

  • Content-Security-Policy(CSP)応答ヘッダー: デフォルトでは、Snowflakeプロキシは、一般的なウェブ攻撃から保護するために、以下のベースライン CSP を追加します。

    default-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data:; object-src 'none'; connect-src 'self'; frame-ancestors 'self';
    
    Copy

    コンテンツセキュリティポリシーの考慮点は2つあります。

    • プロキシが追加するベースラインコンテンツセキュリティポリシーに加えて、サービス自身が応答に明示的に CSP を追加することができます。サービスは、より厳格な CSP を追加して、セキュリティを強化することを選択する場合があります。たとえば、サービスは CSP を追加して、 self からのスクリプトのみを許可する場合があります。

      script-src 'self'
      
      Copy

      結果としてクライアントに送られる応答には、2つの CSP ヘッダーがあります。応答を受信すると、クライアントブラウザーは、各ポリシーによって指定された追加制限を含む、最も厳格なコンテンツセキュリティポリシーを適用します。

    • サービスが外部サイト(ネットワークエグレスの構成)にアクセスできるように外部アクセス統合(EAI)を構成すると、Snowflakeプロキシは、ウェブページがそのサイトにアクセスできるようにする CSP を作成します。たとえば、 EAI に関連付けられているネットワークルールが、サービスに example.com へのエグレスアクセスを許可しているとします。次に、Snowflakeプロキシは以下の CSP 応答ヘッダーを追加します。

      default-src 'self' 'unsafe-inline' 'unsafe-eval' http://example.com https://example.com blob: data:; object-src 'none'; connect-src 'self' http://example.com https://example.com wss://example.com; frame-ancestors 'self';
      
      Copy

      ブラウザーは、応答で受け取ったコンテンツアクセスポリシーを尊重します。この例では、ブラウザーはアプリに example.com へのアクセスを許可しますが、他のサイトへのアクセスは許可しません。

進入と CORS への配慮

デフォルトでは、ブラウザーは、あるサーバーでホストされているウェブアプリが、ホスト名の異なる別のサーバーにリクエストを送信するのをブロックします。例えば、Snowpark Container Services内にデプロイされたバックエンドサービスとやり取りする必要があるウェブアプリをSnowpark Container Servicesの外でホストする場合、この制限が適用されます。

CORS (Cross-Origin Resource Sharing)により、Snowpark Container Servicesサービスは、その環境外でホストされているウェブアプリからのリクエストを許可するよう、ブラウザーに指示することができます。各パブリックエンドポイントを構成して、 CORS プリフライトリクエストと標準リクエストの両方への応答方法を指定できます。

Snowflakeプロキシは常に以下のレスポンスヘッダーを上書きします。

  • Access-Control-Allow-Origin

  • Access-Control-Allow-Methods

  • Access-Control-Allow-Headers

  • Access-Control-Expose-Headers

  • Access-Control-Max-Age

  • Access-Control-Allow-Credentials

Snowflakeプロキシは、以下のいずれかが真である場合、レスポンスにこれらの CORS ヘッダーを含めません。

  • CORS はサービスエンドポイントに構成されていません。つまり、サービス仕様に corsSettings はありません

  • CORS がサービスエンドポイントに構成されていますが、リクエストの Origin ヘッダーがサービス仕様の指定された Access-Control-Allow-Origin フィールドと一致しません

サービス仕様では、各パブリックエンドポイントに対して CORS の設定を行うことができます。リクエストの origin ヘッダーが、仕様でエンドポイントに指定されている Access-Control-Allow-Origin フィールドにマッチするとき、プロキシは以下の調整を加えて、仕様で定義されている CORS ヘッダーをレスポンスに含めます。

  • Access-Control-Allow-Origin: リクエストから Origin ヘッダーを返します。

  • Access-Control-Expose-Headers: 構成した許可ヘッダーのリストを、これらの常時公開ヘッダーとマージします: X-Frame-OptionsCross-Origin-Opener-PolicyCross-Origin-Resource-PolicyX-Content-Type-OptionsCross-Origin-Embedder-PolicyContent-Security-Policy-Report-OnlyContent-Security-Policy

  • Access-Control-Max-Age:2時間にセットされます。

  • Access-Control-Allow-Credentials: trueにセットされます。

進入と SSO への配慮

インターネットからパブリックエンドポイントにアクセスすると、ユーザー名/パスワード認証コードは機能しますが、 SSO では、空白のページが表示されるか、以下のエラーが表示されることがあります。「指定されたOAuth クライアントとの統合 ID が見つかりません。」

この現象は、 フェデレーション認証を使用するためのSnowflakeの構成 で説明されている新しいセキュリティ統合バージョンではなく、Snowflake で古いスタイルの統合認証 (SSO) を使用している場合に発生します。次のことを確認してください。

  1. 以下のクエリを実行します。

    SHOW PARAMETERS LIKE 'SAML_IDENTITY_PROVIDER' IN ACCOUNT;
    
    Copy

    このパラメーターがセットされている場合は、ある時点で旧式の認証コードを使用していたことになります。

  2. 前述のパラメーターがセットされている場合、以下のクエリを実行して、 SAML セキュリティ統合があるかどうかを確認します。

    SHOW INTEGRATIONS
      ->> SELECT * FROM $1 WHERE "type" = 'SAML2';
    
    Copy

    SAML2 タイプの統合がない場合は、旧式の認証コードを使用していることになります。

この大文字と小文字の場合、解決策は、旧式の統合認証から新しい統合形式の統合認証に移行することです。詳細については、 SAML2 セキュリティ統合への移行 をご参照ください。

ネットワークエグレスの構成

アプリケーションコードは、インターネットへのアクセスを必要とする場合があります。デフォルトでは、アプリケーションコンテナーはインターネットにアクセスする権限を持っていません。外部アクセス統合(EAIs) を使用してインターネットアクセスを有効にする必要があります。

通常、サービス(ジョブサービスを含む)から許可される外部アクセスを管理するために、アカウント管理者は EAIs を作成します。アカウント管理者は、開発者がサービスを実行するために使用する特定ロールに EAI の使用権限を付与できます。

次の例は、ネットワークルールを使用して指定された特定の宛先へのエグレストラフィックを許可する EAI を作成するステップの概要を示しています。その後、特定のインターネット宛先へのリクエストを許可するサービスを作成するときに、 EAI を参照します。

アプリケーションコードが、以下の宛先にリクエストを送信するとします。

  • HTTPS が、translation.googleapis.comにリクエストする

  • HTTP と HTTPS が、google.comにリクエストする

以下のステップに従って、サービスがインターネット上のこれらのドメインにアクセスできるようにします。

  1. 外部アクセス統合(EAI)を作成するこれには適切な権限が必要です。たとえば、 ACCOUNTADMIN ロールを使用して EAI を作成することができます。これは2段階のプロセスです。

    1. CREATE NETWORK RULE コマンドを使用して、アクセスを許可する外部宛先をリストした1つ以上のエグレスネットワークルールを作成します。この例は1つのネットワークルールで実現できますが、説明のために2つのネットワークルールを作成します。

      1. translate_network_rule という名前のネットワークルールを作成します。

        CREATE OR REPLACE NETWORK RULE translate_network_rule
          MODE = EGRESS
          TYPE = HOST_PORT
          VALUE_LIST = ('translation.googleapis.com');
        
        Copy

        このルールは、 translation.googleapis.com の宛先への TCP 接続を許可します。VALUE_LIST プロパティのドメインは、オプションのポート番号を指定しないため、デフォルトのポート443(HTTPS)が想定されます。これにより、アプリケーションは https://translation.googleapis.com/ で始まる任意の URL に接続できます。

      2. google_network_rule という名前のネットワークルールを作成します。

        CREATE OR REPLACE NETWORK RULE google_network_rule
          MODE = EGRESS
          TYPE = HOST_PORT
          VALUE_LIST = ('google.com:80', 'google.com:443');
        
        Copy

        これにより、アプリケーションは http://google.com/ または https://google.com/ で始まる任意の URL に接続できます。

      注釈

      VALUE_LIST パラメーターには、完全なホスト名を指定する必要があります。ワイルドカード(例: *.googleapis.com)はサポートされていません。

      Snowpark Container Servicesは、ポート22、80、443、1024+を許可するネットワークルールのみをサポートします。参照されているネットワークルールが他のポートへのアクセスを許可している場合、サービスの作成は失敗します。追加のポートが必要な場合は、担当者にお問い合わせください。

      注釈

      サービスが HTTP または HTTPS リクエストをインターネット上の任意の宛先に送信できるようにするには、 VALUE_LIST プロパティでドメインとして「0.0.0.0」を指定します。以下のネットワークルールは、インターネット上の任意の宛先に「HTTP」と「HTTPS」の両方のリクエストを送信することを許可します。「0.0.0.0」をサポートしているのは、ポート80または443のみです。

      CREATE NETWORK RULE allow_all_rule
        TYPE = 'HOST_PORT'
        MODE= 'EGRESS'
        VALUE_LIST = ('0.0.0.0:443','0.0.0.0:80');
      
      Copy
    2. 外部アクセス統合(EAI) を作成し、先行する2つのエグレスネットワークルールが許可されることを指定します。

      CREATE EXTERNAL ACCESS INTEGRATION google_apis_access_integration
        ALLOWED_NETWORK_RULES = (translate_network_rule, google_network_rule)
        ENABLED = true;
      
      Copy

      これで、アカウント管理者は、開発者に統合の使用権限を付与して、インターネット上の特定の宛先にアクセスできるサービスを実行できるようにすることができます。

      GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE test_role;
      
      Copy
  2. 以下の例に示すように、 EAI を指定してサービスを作成します。サービスを作成する所有者ロールは、 EAI の USAGE 権限と、参照されるシークレットの READ 権限が必要です。ACCOUNTADMIN ロールを使用してサービスを作成することはできません。

    • サービスを作成します。

      USE ROLE test_role;
      
      CREATE SERVICE eai_service
        IN COMPUTE POOL MYPOOL
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION)
        FROM SPECIFICATION
        $$
        spec:
          containers:
            - name: main
              image: /db/data_schema/tutorial_repository/my_echo_service_image:tutorial
              env:
                TEST_FILE_STAGE: source_stage/test_file
              args:
                - read_secret.py
          endpoints:
            - name: read
              port: 8080
        $$;
      
      Copy

      この例の CREATE SERVICE リクエストは、インラインサービス仕様を使用し、 EAI を含むようにオプションの EXTERNAL_ACCESS_INTEGRATIONS プロパティを指定します。EAI は、サービスから特定の宛先へのエグレストラフィックを許可するネットワークルールを指定します。

    • ジョブサービスを実行します。

      EXECUTE JOB SERVICE
        IN COMPUTE POOL tt_cp
        NAME = example_job_service
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION)
        FROM SPECIFICATION $$
        spec:
          container:
          - name: curl
            image: /tutorial_db/data_schema/tutorial_repo/alpine-curl:latest
            command:
            - "curl"
            - "http://google.com/"
        $$;
      
      Copy

      この例の EXECUTE JOB SERVICE コマンドは、インライン仕様と、 EAI を含めるためのオプション EXTERNAL_ACCESS_INTEGRATIONS プロパティを指定します。これは、ジョブから EAI が許可するネットワークルールで指定された宛先への、エグレストラフィックを許可します。

プライベート接続を使用したネットワークエグレス

公衆インターネット経由でネットワークのイグレスをルーティングする代わりに、 プライベート接続エンドポイント を介してサービスのイグレス・トラフィックを誘導することを選択することもできます。

まず、Snowflakeアカウントでプライベート接続エンドポイントを作成する必要があります。次に、 プライベート接続 を使用する発信トラフィックを許可するネットワークルールを構成します。外部アクセス統合(EAI)のセットアップ手順は、前のセクションと同じです。

注釈

プライベート通信では、Snowflakeとお客様のクラウドアカウントの両方が同じクラウドプロバイダーと同じリージョンを使用する必要があります。

例えば、プライベート接続を介してAmazon S3バケットへのサービスのアウトバウンドインターネットアクセスを有効にしたい場合、次のようにします。

  1. 自営エンドポイントサービス(Amazon S3)のプライベートリンク接続を有効にします。ステップバイステップの手順については、 AWS Private Link for Amazon S3 をご参照ください。

  2. SYSTEM$PROVISION_PRIVATELINK_ENDPOINT システム関数を呼び出して、Snowflake VNet にプライベート接続エンドポイントをプロビジョニングします。これにより、Snowflakeはプライベート接続を使用して外部サービス(この例ではAmazon S3)に接続できるようになります。

    USE ROLE ACCOUNTADMIN;
    
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.s3',
      '*.s3.us-west-2.amazonaws.com'
    );
    
    Copy
  3. クラウドプロバイダーのアカウントで、エンドポイントを承認します。この例では、Amazon AWS の場合、 接続リクエストを受け入れるか拒否するか AWS ドキュメントの  を参照してください。 また、Azure でエンドポイントを承認するには、 Azure ドキュメント をご参照ください。

  4. CREATE NETWORK RULE コマンドを使用して、アクセスを許可する外部宛先を指定するエグレスネットワークルールを作成します。

    CREATE OR REPLACE NETWORK RULE private_link_network_rule
      MODE = EGRESS
      TYPE = PRIVATE_HOST_PORT
      VALUE_LIST = ('<bucket-name>.s3.us-west-2.amazonaws.com');
    
    Copy

    TYPE パラメーターの値は PRIVATE_HOST_PORT にセットされます。このネットワークルールは、発信ネットワークトラフィックが プライベート接続 を使用することを許可することを示します。

  5. EAI を作成し、それを使用してサービスを作成する残りの手順は、前のセクションで説明したのと同様です(ネットワークエグレスの構成 を参照)。

プライベート接続エンドポイントの操作については、以下を参照してください。

コンテナー間のネットワーク通信構成

次の2つを考慮します。

  • **サービスインスタンスのコンテナー間の通信

  • 複数のサービスまたは複数のサービスインスタンスにまたがるコンテナ間の通信: 異なるサービス(または同じサービスの異なるインスタンス)に属するコンテナは、仕様ファイルで定義されたエンドポイントを使用して通信できます。詳細については、 サービス間通信 をご参照ください。

Snowflakeシークレットを使用してコンテナーに認証情報を引き渡す

Snowflake が管理する認証情報をコンテナーに渡したい理由は多数あります。サービスが外部エンドポイント(Snowflakeの外部)と通信する場合は、アプリケーションコードが使用できるように、コンテナー内に認証情報を提供する必要があります。

認証情報を提供するには、まず認証情報を Snowflake secret オブジェクトに格納します。次に、サービス仕様の中で、 containers.secrets 、どのシークレットオブジェクトを使用し、コンテナー内のどこに配置するかを指定します。これらの認証情報をコンテナー内の環境変数に渡すか、コンテナー内のローカルファイルで利用できるようにします。

Snowflakeのシークレットを指定する

Snowflakeのシークレットを名前または参照で指定します(参照はNative Applicationシナリオでのみ適用可能です)。

  • Snowflake のシークレットを名前で渡す: snowflakeSecret フィールドの値としてシークレット名を渡すことができます。

    ...
    secrets:
    - snowflakeSecret:
        objectName: '<secret-name>'
      <other info about where in the container to copy the secret>
      ...
    
    Copy

    なお、 snowflakeSecret の値として、 <secret-name> を直接指定することもできます。

  • Snowflakeシークレットをリファレンスで渡す: Snowpark Container Services を使用してNative App(コンテナー付きアプリ)を作成する場合、アプリのプロデューサーとコンシューマーは異なる Snowflake アカウントを使用します。場合によっては、インストールされた Snowflake Native Appは、 APPLICATION オブジェクトの外部に存在するコンシューマーカウントの既存のオブジェクトにアクセスする必要があります。この場合、開発者は「secrets by reference(参照によるシークレット)」指定構文を使用して、図のように認証情報を扱うことができます。

    containers:
    - name: main
      image: <url>
      secrets:
      - snowflakeSecret:
          objectReference: '<reference-name>'
        <other info about where in the container to copy the secret>
    
    Copy

    この仕様では、シークレットの参照名を提供するために、 objectName の代わりに objectReference を使用していることに注意してください。

コンテナー内のシークレットの配置を指定する

Snowflakeには、シークレットを環境変数としてコンテナーに配置するか、ローカルコンテナーファイルに書き込むように指示することができます。

シークレットを環境変数として引き渡し

Snowflakeのシークレットを環境変数としてコンテナーに渡すには、 containers.secrets フィールドに envVarName を含めます。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: <secret-name>
    secretKeyRef: username | password | secret_string |  'access_token'
    envVarName: '<env-variable-name>'
Copy

secretKeyRef: この値はSnowflakeシークレットの型によって異なります。設定可能な値は以下の通りです。

  • username、またはSnowflakeシークレットが password 型の場合は password

  • Snowflakeシークレットが generic_string 型の場合は secret_string

サービスが作成された後、Snowflakeは環境変数として渡されたシークレットを更新しないことに注意してください。

例1: パスワード 型のシークレットを環境変数として引き渡し

この例では、 password 型の以下のSnowflakeシークレットオブジェクトを作成します。

CREATE SECRET testdb.testschema.my_secret_object
  TYPE = password
  USERNAME = 'snowman'
  PASSWORD = '1234abc';
Copy

このSnowflakeシークレットオブジェクトをコンテナー内の環境変数(例: LOGIN_USERLOGIN_PASSWORD)に提供するには、仕様ファイルに以下の containers.secrets フィールドを追加します。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret_object
    secretKeyRef: username
    envVarName: LOGIN_USER
  - snowflakeSecret: testdb.testschema.my_secret_object
    secretKeyRef: password
    envVarName: LOGIN_PASSWORD
Copy

この例では、 snowflakeSecret の値は完全修飾オブジェクト名です。これは、シークレットは作成されるサービスとは異なるスキーマに格納できるためです。

この例の containers.secrets フィールドは、2つの snowflakeSecret オブジェクトのリストです。

  • 最初のオブジェクトは、Snowflakeシークレットオブジェクトの username をコンテナーの環境変数 LOGIN_USER にマップします。

  • 2番目のオブジェクトは、Snowflakeシークレットオブジェクトの password をコンテナーの環境変数 LOGIN_PASSWORD にマップします。

この例では、 generic_string 型の以下のSnowflakeシークレットオブジェクトを作成します。

CREATE SECRET testdb.testschema.my_secret
  TYPE=generic_string
  SECRET_STRING='
       some_magic: config
  ';
Copy

このSnowflakeシークレットオブジェクトをコンテナー内の環境変数(例: GENERIC_SECRET)に提供するには、仕様ファイルに以下の containers.secrets フィールドを追加します。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret
    secretKeyRef: secret_string
    envVarName: GENERIC_SECRET
Copy

ローカルコンテナーファイルでのシークレットを記述する

ローカルコンテナーファイル内のアプリケーションコンテナーで Snowflake シークレットを利用できるようにするには、 containers.secrets フィールドを含めます。ローカルコンテナーファイル内のアプリケーションコンテナーでSnowflake のシークレットを利用できるようにするには、 containers.secretsdirectoryPath を含めます。

containers:
- name: <name>
  image: <url>
  ...
  secrets:
  - snowflakeSecret: <snowflake-secret-name>
    directoryPath: '<local directory path in the container>'
Copy

Snowflakeは、この指定された directoryPath; secretKeyRef を指定する必要はありません。シークレットタイプに応じて、Snowflakeは指定したディレクトリパスの下のコンテナー内に以下のファイルを作成します。

  • Snowflakeシークレットが password 型の場合、 usernamepassword です。

  • Snowflakeシークレットが generic_string 型の場合は secret_string

  • Snowflakeシークレットが oauth2 型の場合は access_token

注釈

サービスが作成された後、Snowflakeのシークレットオブジェクトが更新されると、Snowflakeは実行中のコンテナ内の対応するシークレットファイルを更新します。

例1: ローカルコンテナーファイルにおける password 型のシークレットの引き渡し

この例では、 password 型の以下のSnowflakeシークレットオブジェクトを作成します。

CREATE SECRET testdb.testschema.my_secret_object
  TYPE = password
  USERNAME = 'snowman'
  PASSWORD = '1234abc';
Copy

これらの認証情報をローカルコンテナーファイルで利用できるようにするには、仕様ファイルに以下の containers.secrets フィールドを追加します。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret_object
    directoryPath: '/usr/local/creds'
Copy

サービスを開始すると、Snowflakeはコンテナー内に /usr/local/creds/username/usr/local/creds/password の2つのファイルを作成します。そうすると、アプリケーションコードはこれらのファイルを読み取ることができます。

例2: ローカルコンテナーファイルにおける oauth2 型のシークレットを引き渡す

この例では、 generic_string 型の以下のSnowflakeシークレットオブジェクトを作成します。

CREATE SECRET testdb.testschema.my_secret
  TYPE=generic_string
  SECRET_STRING='
       some_magic: config
  ';
Copy

このSnowflakeシークレットオブジェクトをローカルコンテナーファイルで提供するには、仕様ファイルに以下の containers.secrets フィールドを追加します。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.my_secret
    directoryPath: '/usr/local/creds'
Copy

サービスを開始すると、Snowflakeはコンテナー内に /usr/local/creds/secret_string のファイルを作成します。

例3: ローカルコンテナーファイルにおける oauth2 型のシークレットを引き渡す

この例では、 oauth2 型の以下のSnowflakeシークレットオブジェクトを作成します。

CREATE SECRET testdb.testschema.oauth_secret
  TYPE = OAUTH2
  OAUTH_REFRESH_TOKEN = '34n;vods4nQsdg09wee4qnfvadH'
  OAUTH_REFRESH_TOKEN_EXPIRY_TIME = '2023-12-31 20:00:00'
  API_AUTHENTICATION = my_integration;
Copy

これらの認証情報をローカルコンテナーファイルで利用できるようにするには、仕様ファイルに以下の containers.secrets フィールドを追加します。

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: testdb.testschema.oauth_secret
    directoryPath: '/usr/local/creds'
Copy

Snowflakeは OAuth シークレットオブジェクトからアクセストークンをフェッチし、コンテナーに /usr/local/creds/access_token を作成します。

サービスがoauth2型のシークレットを使用する場合、サービスはインターネット宛先にアクセスするためにそのシークレットを使用することが求められます。oauthシークレットは 外部アクセス統合(EAI) によって許可される必要があります。それ以外の場合、 CREATE SERVICE または EXECUTE JOB SERVICE は失敗します。この追加の EAI 要件は、oauth2型のシークレットにのみ適用され、他の型のシークレットには適用されません。

要約すると、このようなサービスを作る際の典型的なステップは以下のとおりです。

  1. oauth2型のシークレットを作成します(前述のとおり)。

  2. サービスによるシークレットの使用を許可する EAI を作成します。例:

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION example_eai
      ALLOWED_NETWORK_RULES = (<name>)
      ALLOWED_AUTHENTICATION_SECRETS = (testdb.testschema.oauth_secret)
      ENABLED = true;
    
    Copy
  3. 仕様に containers.secrets フィールドを含むサービスを作成します。また、oauth2シークレットの使用を許可するために、 EXTERNAL_ACCESS_INTEGRATIONS プロパティに EAI を含めるようにオプションで指定します。

    CREATE SERVICE (インライン仕様を使用)コマンドの例:

    CREATE SERVICE eai_service
      IN COMPUTE POOL MYPOOL
      EXTERNAL_ACCESS_INTEGRATIONS = (example_eai)
      FROM SPECIFICATION
      $$
      spec:
        containers:
          - name: main
            image: <url>
            secrets:
            - snowflakeSecret: testdb.testschema.oauth_secret
              directoryPath: '/usr/local/creds'
        endpoints:
          - name: api
            port: 8080
      $$;
    
    Copy

エグレスの詳細については、 ネットワークエグレスの構成 をご参照ください。

ガイドラインと制約

  • 一般的な制限: これらの制限に関する問題が発生した場合は、アカウント担当者にお問い合わせください。

    • Snowflakeアカウントには最大200のサービスを作成できます。

    • 各サービスは最大100のエンドポイントを持つことができます(spec.endpoints を参照)。

    • 各サービスは最大20のコンテナーを持つことができます(spec.containers を参照)。

    • 各サービスは最大50のシークレットを持つことができます(containers.secrets を参照)。

    • 各サービスは最大20のボリュームを持つことができます(spec.volumes を参照)。

    • 外部アクセス統合(EAIs)を使用してインターネットアクセス(ネットワークエグレスの構成)を有効にすると、以下の制限が適用されます。

      • 各サービスは最大10個の EAIs (CREATE SERVICE および ALTER SERVICE を参照)をサポートすることができます。

      • 各 EAI は最大100のホスト名を持つことができます。

    • インターネットからパブリックエンドポイントにアクセスすると、ユーザー名/パスワード認証コードは機能しますが、 SSO では、空白のページが表示されるか、以下のエラーが表示されることがあります。" 指定された OAuth クライアントとの統合 ID が見つかりません。"この問題への対処情報については、 進入と SSO への配慮 をご覧ください。

  • 画像プラットフォームの要件: 現在、Snowpark Container Servicesにはlinux/amd64プラットフォーム画像が必要です。

  • サービスコンテナの権限なし: サービスコンテナは権限として実行されないため、ホスト上のハードウェアの構成を変更できず、限られた OS 構成のみを変更できます。サービスコンテナは、通常のユーザー(つまり、ルートを必要としないユーザー)ができるオペレーティングシステム構成のみを実行できます。

  • データベースおよびスキーマの名前変更:

    • すでにサービスを作成したデータベースやスキーマの名前は変更しないでください。名前変更は事実上、サービスを別のデータベースとスキーマに移動することになりますが、これはサポートされていません。例:

      • Snowflakeが実行中のサービスコンテナーに提供したデータベースとスキーマの情報は、引き続き従来の名前を参照します。

      • サービスがイベントテーブルにインジェストする新しいログは、従来のデータベース名とスキーマ名を参照し続けます。

      • サービス関数は従来のデータベースとスキーマのサービスを参照し続け、サービス関数を呼び出すと失敗します。

    • サービス仕様は、Snowflakeステージやイメージリポジトリなどのオブジェクトを参照することができます。これらのオブジェクトが存在するデータベース名やスキーマ名を変更した場合は、サービス仕様の参照オブジェクトのデータベース名やスキーマ名を手動で更新する必要があります。

  • 親スキーマまたはデータベースの所有権の移転:

    親データベース/スキーマの所有権を別のロールに移すことができます。しかし、データベース/スキーマ内のサービスの所有権は新しいロールに移転されません。なぜなら、サービスはサービス所有者のロールとして実行され、それは変更されないからです。その結果、同じスキーマ内のイメージリポジトリやSnowflakeステージなど、スキーマ内のオブジェクトに対する許可が失われる可能性があります。

    親スキーマ/データベースの所有権移転が必要な場合は、サービスの再作成を検討してください。

  • データベースおよびスキーマのドロップおよびドロップ解除:

    • 親データベースまたはスキーマをドロップすると、サービスは非同期に削除されます。つまり、内部プロセスでサービスが削除されるまで、しばらくの間サービスが実行され続ける可能性があります。

    • 以前に削除されたデータベースやスキーマのドロップ解除を試行しても、サービスが復元される保証はありません。

  • Ownership transfer of services: Ownership transfer or future ownership transfer for services, including job services, isn't supported.

  • サービス関数の所有権移転:

    サービス関数の所有権は、異なるロールに移転することができます。新しい所有者ロールがサービスの USAGE 権限を持っていない場合、関数の呼び出しは失敗します。新しい関数所有者ロールに USAGE 権限を与える必要があります。

  • 複製: Snowflakeで複製を扱う場合、以下の点に注意してください。

    • サービス、コンピューティングプール、リポジトリなどのSnowpark Container Servicesオブジェクトを複製することはできません。

    • データベース内にリポジトリを作成した場合は、データベース全体を複製することはできません。データベースにサービス、コンピューティングプールなどの他のリソースが含まれている場合、データベースの複製プロセスは成功しますが、データベース内の個々のオブジェクトは複製されません。

  • Job services timeout: Snowpark Container Services job services runs synchronously by default. If a statement times out, the job service is canceled. The default statement timeout is two days. Customers can change the timeout by setting the parameter STATEMENT_TIMEOUT_IN_SECONDS using ALTER SESSION.

    ALTER SESSION SET statement_timeout_in_seconds=<time>
    
    Copy

    EXECUTE JOB SERVICE コマンドを実行する前に設定します。ASYNC=true を指定してジョブサービスを非同期的に実行し、ステートメントのタイムアウトによってジョブサービスが中断されるのを回避できます。