外部ネットワークアクセスの例

このトピックでは、ユーザー定義関数とプロシージャから外部ネットワークロケーションにアクセスする例を示します。

Google翻訳 API へのアクセス

以下のステップでは、Google翻訳 API にアクセスするための外部アクセス統合を作成するコードを示します。ステップでは、セキュリティの統合と、ステートメントの実行に必要な許可を追加します。

  1. 外部ロケーションを表すネットワークルールを作成します。

    必要な権限など、外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。

    CREATE OR REPLACE NETWORK RULE google_apis_network_rule
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('translation.googleapis.com');
    
    Copy
  2. google_apis_network_rule ネットワークルールで指定された外部ネットワークロケーションとの認証に必要な OAuth 認証情報を保持するセキュリティ統合を作成します。

    必要な権限など、コマンドに関する参考情報については、 CREATE SECURITY INTEGRATION (外部 API 認証) をご参照ください。

    CREATE OR REPLACE SECURITY INTEGRATION google_translate_oauth
      TYPE = API_AUTHENTICATION
      AUTH_TYPE = OAUTH2
      OAUTH_CLIENT_ID = 'my-client-id'
      OAUTH_CLIENT_SECRET = 'my-client-secret'
      OAUTH_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token'
      OAUTH_AUTHORIZATION_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
      OAUTH_ALLOWED_SCOPES = ('https://www.googleapis.com/auth/cloud-platform')
      ENABLED = TRUE;
    
    Copy
  3. google_translate_oauth セキュリティ統合に含まれる認証情報を表すシークレットを作成します。

    必要な権限など、外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。

    シークレットは、 OAUTH_REFRESH_TOKEN パラメーターでリフレッシュトークンを指定する必要があります。サービスプロバイダー(この場合はGoogle Cloud Translation API サービス)からリフレッシュトークンを取得するには、プロバイダーが提供する方法を使用するか、Snowflakeのシステム関数を使用します。

    リフレッシュトークンでシークレットを作成するには、以下のようにGoogle OAuth PlaygroundまたはSnowflakeシステム関数の いずれか を使用します。

    • Snowflakeシステム関数

      1. CREATE SECRET を実行してシークレットを作成します。後のステップで、これをリフレッシュトークンで更新します。

        USE DATABASE my_db;
        USE SCHEMA secret_schema;
        
        CREATE OR REPLACE SECRET oauth_token
          TYPE = oauth2
          API_AUTHENTICATION = google_translate_oauth;
        
        Copy
      2. SYSTEM$START_OAUTH_FLOW 関数を実行して URL を取得し、その引数に以前に作成したシークレットの名前を指定してリフレッシュトークンを取得することができます。

        CALL SYSTEM$START_OAUTH_FLOW( 'my_db.secret_schema.oauth_token' );
        
        Copy

        この関数は URL を生成し、 OAuth 同意プロセスを完了するために使用できます。

      3. ブラウザーで、生成された URL にアクセスし、 OAuth2 同意プロセスを完了します。終了したら、ブラウザーをプロセスの最終ページで開いたままにしておきます。

      4. ブラウザーのアドレスバーから、同意プロセスの最終ページの URL にあるクエスチョンマーク以降のテキストをすべてコピーします。

      5. ブラウザーのアドレスバーからコピーしたパラメーターを引数に指定して、 SYSTEM$FINISH_OAUTH_FLOW 関数を実行します。

        これによってリフレッシュトークンでシークレットが更新されます。

        必ず SYSTEM$FINISH_OAUTH_FLOW を SYSTEM$START_OAUTH_FLOW と同じセッションで実行してください。SYSTEMFINISH_OAUTH_FLOW は SYSTEM$START_OAUTH_FLOW で指定したシークレットを OAuth サーバーから取得したアクセストークンとリフレッシュトークンで更新します。

        CALL SYSTEM$FINISH_OAUTH_FLOW( 'state=<remaining_url_text>' );
        
        Copy
    • Google OAuth Playground

      1. GoogleOAuth Playground で、ステップ1で指定したようにCloud Translation API を選択して認証します。

      2. ステップ2で exchange authorization code for tokens をクリックし、 refresh token トークン値をコピーします。

      3. CREATE SECRET を実行して、コピーしたリフレッシュトークン値を指定するシークレットを作成します。

        必要な権限など、外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。

        CREATE OR REPLACE SECRET oauth_token
          TYPE = oauth2
          API_AUTHENTICATION = google_translate_oauth
          OAUTH_REFRESH_TOKEN = 'my-refresh-token';
        
        Copy
  4. ネットワークルールとシークレットを使用して外部アクセス統合を作成します。

    必要な権限など、外部アクセス統合のロールについては、 外部アクセス統合の作成 をご参照ください。

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION google_apis_access_integration
      ALLOWED_NETWORK_RULES = (google_apis_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS = (oauth_token)
      ENABLED = TRUE;
    
    Copy
  5. 統合を使用する UDF またはプロシージャを作成する必要があるユーザーに割り当てる developer ロールを作成します。

    CREATE OR REPLACE ROLE developer;
    CREATE OR REPLACE ROLE user;
    
    Copy
  6. 外部アクセス用のオブジェクトを使用する UDF を作成するために必要な権限を developer ロールに付与します。これには、次が含まれます。

    • シークレットに対する READ 権限。

    • シークレットを含むスキーマに対する USAGE 権限。

    • 統合に対する USAGE 権限。

      GRANT READ ON SECRET oauth_token TO ROLE developer;
      GRANT USAGE ON SCHEMA secret_schema TO ROLE developer;
      GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE developer;
      
      Copy
  7. 指定されたテキストを指定された言語のフレーズに翻訳する UDF google_translate_python を作成します。詳細については、 関数またはプロシージャでの外部アクセス統合の使用 をご参照ください。

    USE ROLE developer;
    
    CREATE OR REPLACE FUNCTION google_translate_python(sentence STRING, language STRING)
    RETURNS STRING
    LANGUAGE PYTHON
    RUNTIME_VERSION = 3.8
    HANDLER = 'get_translation'
    EXTERNAL_ACCESS_INTEGRATIONS = (google_apis_access_integration)
    PACKAGES = ('snowflake-snowpark-python','requests')
    SECRETS = ('cred' = oauth_token )
    AS
    $$
    import _snowflake
    import requests
    import json
    session = requests.Session()
    def get_translation(sentence, language):
      token = _snowflake.get_oauth_access_token('cred')
      url = "https://translation.googleapis.com/language/translate/v2"
      data = {'q': sentence,'target': language}
      response = session.post(url, json = data, headers = {"Authorization": "Bearer " + token})
      return response.json()['data']['translations'][0]['translatedText']
    $$;
    
    Copy
  8. USAGE 権限を google_translate_python 関数に付与して、 user ロールを持つ人がその関数を呼び出せるようにします。

    GRANT USAGE ON FUNCTION google_translate_python(string, string) TO ROLE user;
    
    Copy
  9. フレーズを翻訳するには google_translate_python 関数を実行します。

    USE ROLE user;
    
    SELECT google_translate_python('Happy Thursday!', 'zh-CN');
    
    Copy

    これは以下のような出力を生成します。

    -------------------------------------------------------
    | GOOGLE_TRANSLATE_PYTHON('HAPPY THURSDAY!', 'ZH-CN') |
    -------------------------------------------------------
    | 快乐星期四!                                          |
    -------------------------------------------------------
    

外部ラムダ関数へのアクセス

以下のステップでは、Snowflakeの外部ラムダ関数にアクセスするための外部アクセス統合を作成するサンプルコードを示します。この例では外部エンドポイント自体のプレースホルダーを使用していますが、例えば REST サービスエンドポイントで利用可能な関数でも構いません。

外部アクセスは ベクトル化されたPython UDF で使用され、データを含むPandas DataFrame を受け取ります。

  1. 外部ロケーション my_external_service を表すネットワークルール lambda_network_rule を作成します(ここでは、外部エンドポイントのロケーションのプレースホルダー値です)。

    外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。

    CREATE OR REPLACE NETWORK RULE lambda_network_rule
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('my_external_service');
    
    Copy
  2. 外部サービスが必要とする認証情報を表すシークレットを作成します。

    この例の後のハンドラーコードは、Python用のSnowflake API を使用してシークレットから認証情報を取得します。

    外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。

    CREATE OR REPLACE SECRET secret_password
      TYPE = PASSWORD
      USERNAME = 'my_user_name'
      PASSWORD = 'my_password';
    
    Copy
  3. developer ロールを作成し、そのロールにシークレットの READ 権限を付与します。このロールは、シークレットを使用する UDF またはプロシージャを作成する必要があるユーザに割り当てられます。

    また、ユーザが関数を呼び出すために使用するロールを作成します。

    CREATE OR REPLACE ROLE developer;
    CREATE OR REPLACE ROLE user;
    
    Copy
  4. 外部アクセス用のオブジェクトを使用する UDF を作成するために必要な権限を developer ロールに付与します。これには、次が含まれます。

    • シークレットに対する READ 権限。

    • シークレットを含むスキーマに対する USAGE 権限。

    GRANT READ ON SECRET secret_password TO ROLE developer;
    GRANT USAGE ON SCHEMA secret_schema TO ROLE developer;
    
    Copy
  5. 外部アクセス統合を作成し、作成したネットワークルールとシークレットを使用して外部エンドポイントと認証情報を指定します。

    必要な権限など、外部アクセス統合のロールについては、 外部アクセス統合の作成 をご参照ください。

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION lambda_external_access_integration
      ALLOWED_NETWORK_RULES = (lambda_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS = (secret_password)
      ENABLED = TRUE;
    
    Copy
  6. Pandas DataFrame として受信したデータを処理するために、外部ネットワークロケーションにアクセスする ベクトル化された Python UDF return_double_column を作成します。

    UDF での外部アクセスの使用の詳細については、 関数またはプロシージャでの外部アクセス統合の使用 をご参照ください。

    CREATE OR REPLACE FUNCTION return_double_column(x int)
    RETURNS INT
    LANGUAGE PYTHON
    EXTERNAL_ACCESS_INTEGRATIONS = (lambda_external_access_integration)
    SECRETS = ('cred' = secret_password)
    RUNTIME_VERSION = 3.8
    HANDLER = 'return_first_column'
    PACKAGES = ('pandas', 'requests')
    AS $$
    import pandas
    import numpy as np
    import json
    import requests
    import base64
    import _snowflake
    from _snowflake import vectorized
    from requests.auth import HTTPBasicAuth
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3.util.retry import Retry
    
    session = requests.Session()
    retries = Retry(total=10, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504], allowed_methods = None)
    
    session.mount('https://', HTTPAdapter(max_retries=retries))
    
    @vectorized(input=pandas.DataFrame)
    def return_first_column(df):
      request_rows = []
    
      df.iloc[:,0] = df.iloc[:,0].astype(int)
      request_rows = np.column_stack([df.index, df.iloc[:,0]]).tolist()
    
      request_payload = {"data" : request_rows}
    
      username_password_object = _snowflake.get_username_password('cred');
      basic = HTTPBasicAuth(username_password_object.username, username_password_object.password)
    
      url = 'my_external_service'
    
      response = session.post(url, json=request_payload, auth=basic)
    
      response.raise_for_status()
      response_payload = json.loads(response.text)
    
      response_rows = response_payload["data"]
    
      return pandas.DataFrame(response_rows)[1]
    $$;
    
    Copy
  7. USAGE 権限を return_double_column 関数に付与して、 user ロールを持つ人がその関数を呼び出せるようにします。

    GRANT USAGE ON FUNCTION return_double_column(int) TO ROLE user;
    
    Copy
  8. return_double_column 関数を実行し、外部エンドポイントにリクエストを行います。

    以下の例のコードは、2列のテーブルを作成し、4バイト整数を含む100,000,000行を挿入します。次にコードは return_double_column 関数を実行し、外部エンドポイントによる処理のために a 列から値を渡します。

    CREATE OR REPLACE TABLE t1 (a INT, b INT);
    INSERT INTO t1 SELECT SEQ4(), SEQ4() FROM TABLE(GENERATOR(ROWCOUNT => 100000000));
    
    SELECT return_double_column(a) AS retval FROM t1 ORDER BY retval;
    
    Copy