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

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

OAuth で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 と同じセッションで実行してください。SYSTEM$FINISH_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.9
    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.9
    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

AWS IAM でAmazon S3にアクセスする

IAM を使って AWS S3 バケットに接続するサンプルコードを以下に示します。

AWS IAM の詳細については、 AWS ドキュメント IAM. をご参照ください。

  1. VALUE_LIST パラメーターで指定された場所に、 AWS S3 バケットを表すネットワー クルール、 aws_s3_network_rule を作成します。

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

    CREATE OR REPLACE NETWORK RULE aws_s3_network_rule
      MODE = EGRESS
      TYPE = PRIVATE_HOST_PORT
      VALUE_LIST = ('external-access-iam-bucket.s3.us-west-2.amazonaws.com');
    
    Copy
  2. aws_s3_network_rule ネットワークルールで指定された外部ネットワークロケーションとの認証に必要な AWSIAM Amazon Resource Name (ARN) 認証情報を保持するセキュリティ統合を作成します。

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

    CREATE OR REPLACE SECURITY INTEGRATION aws_s3_security_integration
      TYPE = API_AUTHENTICATION
      AUTH_TYPE = AWS_IAM
      ENABLED = TRUE
      AWS_ROLE_ARN = 'arn:aws:iam::736112632310:role/external-access-iam-bucket';
    
    Copy
  3. IAM USER のために ARN と ID を入手します。

    1. 作成したセキュリティ統合で DESC コマンドを実行します。

      DESC SECURITY INTEGRATION aws_s3_security_integration;
      
      Copy
    2. 表示された出力から、次のステップで使用するために以下のプロパティの値をコピーします。

      • API_AWS_IAM_USER_ARN

      • API_AWS_EXTERNAL_ID

  4. IAM ユーザーにバケットへのアクセスに必要なパーミッションを付与します。

    オプション1: Amazon S3にアクセスするためのSnowflakeストレージ統合の構成 のステップ 5 で説明されているようにトラスト・ポリシーを設定する際には、 ARN と ID の値を使用します。

  5. CLOUD_PROVIDER_TOKEN 型の外部サービスが必要とする認証情報を表す シークレット を作成します。

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

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

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

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

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

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

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

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

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

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION aws_s3_external_access_integration
      ALLOWED_NETWORK_RULES = (aws_s3_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS = (aws_s3_access_token)
      ENABLED = TRUE
      COMMENT = 'Testing S3 connectivity';
    
    Copy
  9. 外部アクセス統合を使用して、作成したネットワークルールで指定したAmazon S3バケットに接続する UDF を作成します。

    ハンドラのコードでは、 Snowflake APIs を使用して、作成したシークレットからトークンを取得します。このトークンから、Snowflake APIs を使用して、アクセスキー ID 、シークレットアクセスキー、セッショントークンなど、Amazon S3 に接続するためのセッションを作成するために必要な値を取得できます。

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

    CREATE OR REPLACE FUNCTION aws_s3_python_function()
      RETURNS VARCHAR
      LANGUAGE PYTHON
      EXTERNAL_ACCESS_INTEGRATIONS = (aws_s3_external_access_integration)
      RUNTIME_VERSION = '3.9'
      SECRETS = ('cred' = aws_s3_access_token)
      PACKAGES = ('boto3')
      HANDLER = 'main_handler'
    AS
    $$
    import boto3
    import _snowflake
    from botocore.config import Config
    
    def main_handler():
      # Get token object
      cloud_provider_object = _snowflake.get_cloud_provider_token('cred')
    
      # Boto3 configuration
      config = Config(
        retries=dict(total_max_attempts=9),
        connect_timeout=30,
        read_timeout=30,
        max_pool_connections=50
      )
    
      # Connect to S3 using boto3
      s3 = boto3.client(
        's3',
        region_name='us-west-2',
        aws_access_key_id=cloud_provider_object.access_key_id,
        aws_secret_access_key=cloud_provider_object.secret_access_key,
        aws_session_token=cloud_provider_object.token,
        config=config
      )
    
      # Use S3 object to upload/download
      return 'Successfully connected with S3'
    $$;
    
    Copy
  10. USAGE 権限を UDF 関数に付与して、 user ロールを持つ人がその関数を呼び出せるようにします。

    GRANT USAGE ON FUNCTION return_double_column(int) TO ROLE user;
    
    Copy
  11. 外部エンドポイントに接続するための関数を実行します。

    SELECT aws_s3_python_function();
    
    Copy