AWS 上での外部ネットワークアクセスとプライベート接続

このトピックでは、 外部ネットワークアクセス を使用して、AWS 外部サービスへのアウトバウンド プライベート接続を設定するための構成の詳細を説明します。アウトバウンド・パブリック接続とアウトバウンド・プライベート接続の設定の主な違いは、プライベート接続の場合、以下の操作を行う必要があることです。

  • プライベート接続エンドポイントを作成します。このステップでは、 ACCOUNTADMIN ロールが必要です。

  • ネットワーク・ルールを作成し、 TYPE プロパティを PRIVATE_HOST_PORT にセットします。

アウトバウンド プライベート接続コスト

各プライベート・コネクティビティ・エンドポイントの料金は、処理されるデータ総量に応じて支払われます。これらのアイテムの価格については、 Snowflake Service Consumption Table をご参照ください。

ACCOUNT_USAGE および ORGANIZATION_USAGE スキーマで請求ビューをクエリする際、以下のサービスタイプでフィルターをかけることで、これらの項目のコストを調べることができます。

  • OUTBOUND_PRIVATELINK_ENDPOINT

  • OUTBOUND_PRIVATELINK_DATA_PROCESSED

例えば、 USAGE_IN_CURRENCY_DAILY 表示をクエリし、これらのサービスタイプでフィルターをかけることができます。

外部Amazon S3サービスへのプライベート接続のセットアップ

  1. SYSTEM$PROVISION_PRIVATELINK_ENDPOINT システム関数を呼び出して、Snowflake が AWS S3 サービスに接続することを指定し、サービスに接続するときに使用するホスト名を指定します:

    USE ROLE ACCOUNTADMIN;
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.s3',
      '*.s3.us-west-2.amazonaws.com'
    );
    
    Copy

    注釈

    *.s3.us-west-2.amazonaws.com のアスタリスクは、エンドポイントを使用して複数のS3バケットにアクセスできることを示します。

  2. 次の SQL ステートメントを実行して、Snowflake が外部宛先にリクエストを送信できるようにするネットワークルールを作成します。 TYPE プロパティを PRIVATE_HOST_PORT にセットしてください:

    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
  3. 以下の SQL ステートメントを実行して、外部 API 認証用のセキュリティ統合を作成します:

    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
  4. 次の SQL ステートメントを実行して、 IAM ユーザーの STORAGE_AWS_IAM_USER_ARNSTORAGE_AWS_EXTERNAL_ID の値を取得します:

    DESC SECURITY INTEGRATION aws_s3_security_integration;
    
    Copy
  5. STORAGE_AWS_IAM_USER_ARNSTORAGE_AWS_EXTERNAL_ID の値を使用して、 オプション1: Amazon S3にアクセスするためのSnowflakeストレージ統合の構成ステップ 5 に従って、 IAM ユーザーに Amazon S3 サービスへのアクセスを付与します。

  6. 以下の SQL ステートメントを実行して、 AWS S3サービスで認証に使用するトークンを作成します:

    CREATE OR REPLACE SECRET aws_s3_access_token
      TYPE = CLOUD_PROVIDER_TOKEN
      API_AUTHENTICATION = aws_s3_security_integration;
    
    Copy
  7. 次の SQL ステートメントを実行して、前の手順で作成したネットワークルールとトークンを使用する外部アクセス統合を作成します:

    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
  8. 次の SQL ステートメントのいずれかを実行して、以前に作成した外部アクセス統合とトークンを使用できる関数を作成します:

    CREATE OR REPLACE FUNCTION aws_s3_python_function()
      RETURNS VARCHAR
      LANGUAGE PYTHON
      EXTERNAL_ACCESS_INTEGRATIONS = (aws_s3_external_access_integration)
      RUNTIME_VERSION = '3.8'
      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 the previously created token as an object
          cloud_provider_object = _snowflake.get_cloud_provider_token('cred')
    
          # Configure boto3 connection settings
          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 the s3 object upload/download resources
          # ...
    
          return 'Successfully connected to AWS S3'
    $$;
    
    Copy
  9. 以下の SQL ステートメントのいずれかを実行して、作成した関数を実行します:

    SELECT aws_s3_python_function();
    
    Copy

外部のAmazon Bedrockサービスへのプライベート接続のセットアップ

  1. SYSTEM$PROVISION_PRIVATELINK_ENDPOINT システム関数を呼び出して、Snowflake が AWS S3 と Amazon Bedrock サービスに接続することと、サービスに接続するときに使用するホスト名を指定します:

    USE ROLE ACCOUNTADMIN;
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.s3',
      '*.s3.us-west-2.amazonaws.com'
    );
    
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.bedrock-runtime',
      'bedrock-runtime.us-west-2.amazonaws.com'
    );
    
    Copy
  2. 次の SQL ステートメントを実行して、Snowflake が外部宛先にリクエストを送信できるようにするネットワークルールを作成します。 TYPE プロパティを PRIVATE_HOST_PORT にセットしてください:

    CREATE OR REPLACE NETWORK RULE bedrock_network_rule
      MODE = EGRESS
      TYPE = PRIVATE_HOST_PORT
      VALUE_LIST = ('bedrock-runtime.us-west-2.amazonaws.com');
    
    Copy
  3. 以下の SQL ステートメントを実行して、外部 API 認証用のセキュリティ統合を作成します:

    CREATE OR REPLACE SECURITY INTEGRATION bedrock_security_integration
      TYPE = API_AUTHENTICATION
      AUTH_TYPE = AWS_IAM
      ENABLED = TRUE
      AWS_ROLE_ARN = 'arn:aws:iam::736112632310:role/external-access-iam-bucket';
    
    Copy
  4. 次の SQL ステートメントを実行して、 IAM ユーザーの STORAGE_AWS_IAM_USER_ARNSTORAGE_AWS_EXTERNAL_ID の値を取得します:

    DESC  SECURITY INTEGRATION bedrock_security_integration;
    
    Copy
  5. STORAGE_AWS_IAM_USER_ARNSTORAGE_AWS_EXTERNAL_ID の値を使用して、 オプション1: Amazon S3にアクセスするためのSnowflakeストレージ統合の構成ステップ 5 に従って、 IAM ユーザーに Amazon Bedrock サービスへのアクセスを付与します。

  6. 以下の SQL ステートメントを実行して、 AWS Bedrock サービスで認証に使用するトークンを作成します:

    CREATE OR REPLACE SECRET aws_bedrock_access_token
      TYPE = CLOUD_PROVIDER_TOKEN
      API_AUTHENTICATION = bedrock_security_integration;
    
    Copy
  7. 次の SQL ステートメントを実行して、前の手順で作成したネットワークルールとトークンを使用する外部アクセス統合を作成します:

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION bedrock_external_access_integration
      ALLOWED_NETWORK_RULES = (bedrock_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS=(aws_bedrock_access_token)
      ENABLED=true ;
    
    Copy
  8. 次の SQL ステートメントを実行して、以前に作成した外部アクセス統合とトークンを使用できる関数を作成します:

    CREATE OR REPLACE FUNCTION bedrock_private_connectivity_tests(
      id INT,
      instructions VARCHAR,
      user_context VARCHAR,
      model_id VARCHAR
    )
      RETURNS VARCHAR
      LANGUAGE PYTHON
      EXTERNAL_ACCESS_INTEGRATIONS = (bedrock_external_access_integration)
      RUNTIME_VERSION = '3.8'
      SECRETS = ('cred' = aws_bedrock_access_token)
      PACKAGES = ('boto3')
      HANDLER = 'bedrock_py'
    AS
    $$
      import boto3
      import json
      import _snowflake
      def bedrock_py(id, instructions, user_context, model_id):
          # Get the previously created token as an object
          cloud_provider_object = _snowflake.get_cloud_provider_token('cred')
          cloud_provider_dictionary = {
              "ACCESS_KEY_ID": cloud_provider_object.access_key_id,
              "SECRET_ACCESS_KEY": cloud_provider_object.secret_access_key,
              "TOKEN": cloud_provider_object.token
          }
          # Assign AWS credentials and choose a region
          boto3_session_args = {
              'aws_access_key_id': cloud_provider_dictionary["ACCESS_KEY_ID"],
              'aws_secret_access_key': cloud_provider_dictionary["SECRET_ACCESS_KEY"],
              'aws_session_token': cloud_provider_dictionary["TOKEN"],
              'region_name': 'us-west-2'
          }
          session = boto3.Session(**boto3_session_args)
          client = session.client('bedrock-runtime')
          # Prepare the request body for the specified model
          def prepare_request_body(model_id, instructions, user_context):
              default_max_tokens = 512
              default_temperature = 0.7
              default_top_p = 1.0
              if model_id == 'amazon.titan-text-express-v1':
                  body = {
                      "inputText": f"<SYSTEM>Follow these:{instructions}<END_SYSTEM>\n<USER_CONTEXT>Use this user context in your response:{user_context}<END_USER_CONTEXT>",
                      "textGenerationConfig": {
                          "maxTokenCount": default_max_tokens,
                          "stopSequences": [],
                          "temperature": default_temperature,
                          "topP": default_top_p
                      }
                  }
              elif model_id == 'ai21.j2-ultra-v1':
                  body = {
                      "prompt": f"<SYSTEM>Follow these:{instructions}<END_SYSTEM>\n<USER_CONTEXT>Use this user context in your response:{user_context}<END_USER_CONTEXT>",
                      "temperature": default_temperature,
                      "topP": default_top_p,
                      "maxTokens": default_max_tokens
                  }
              elif model_id == 'anthropic.claude-3-sonnet-20240229-v1:0':
                  body = {
                      "max_tokens": default_max_tokens,
                      "messages": [{"role": "user", "content": f"<SYSTEM>Follow these:{instructions}<END_SYSTEM>\n<USER_CONTEXT>Use this user context in your response:{user_context}<END_USER_CONTEXT>"}],
                      "anthropic_version": "bedrock-2023-05-31"
                  }
              else:
                  raise ValueError("Unsupported model ID")
              return json.dumps(body)
          # Call Bedrock to get a completion
          body = prepare_request_body(model_id, instructions, user_context)
          response = client.invoke_model(modelId=model_id, body=body)
          response_body = json.loads(response.get('body').read())
          # Parse the API response based on the model
          def get_completion_from_response(response_body, model_id):
              if model_id == 'amazon.titan-text-express-v1':
                  output_text = response_body.get('results')[0].get('outputText')
              elif model_id == 'ai21.j2-ultra-v1':
                  output_text = response_body.get('completions')[0].get('data').get('text')
              elif model_id == 'anthropic.claude-3-sonnet-20240229-v1:0':
                  output_text = response_body.get('content')[0].get('text')
              else:
                  raise ValueError("Unsupported model ID")
              return output_text
          # Get the generated text from Bedrock
          output_text = get_completion_from_response(response_body, model_id)
          return output_text
      $$;
    
    Copy
  9. 以下の SQL ステートメントを実行して、作成した関数を実行します:

    SELECT bedrock_private_connectivity_tests();
    
    Copy