Accès au réseau externe et connectivité privée sur AWS

Cette rubrique fournit des détails de configuration pour configurer la connectivité privée sortante vers un service externe AWS via l’accès au réseau externe. Les principales différences entre les configurations de connectivité publique sortante et de connectivité privée sortante sont que, avec la connectivité privée, vous devez effectuer les opérations suivantes :

  • Créez un point de terminaison de connectivité privé. Cette étape nécessite le rôle ACCOUNTADMIN.

  • Créez la règle de réseau de manière afin que la propriété TYPE soit définie sur PRIVATE_HOST_PORT.

Coûts de la connectivité privée sortante

Vous payez pour le point de terminaison de la connectivité privée et pour toutes les données traitées. Pour connaître les prix de ces éléments, consultez le tableau de consommation des services de Snowflake.

Vous pouvez connaître le coût de ces éléments en filtrant sur les types de services suivants lors de la requête des vues de facturation dans les schémas ACCOUNT_USAGE et ORGANIZATION_USAGE :

  • OUTBOUND_PRIVATELINK_ENDPOINT

  • OUTBOUND_PRIVATELINK_DATA_PROCESSED

Par exemple, vous pouvez interroger la vue USAGE_IN_CURRENCY_DAILY et filtrer sur ces types de services.

Définir la connectivité privée sur un service Amazon S3 externe

  1. Appelez la fonction système SYSTEM$PROVISION_PRIVATELINK_ENDPOINT pour spécifier que Snowflake se connecte à un service S3 AWS et le nom d’hôte à utiliser lors de la connexion au service :

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

    Note

    L’astérisque dans *.s3.us-west-2.amazonaws.com indique que vous pouvez utiliser le point de terminaison pour accéder à plusieurs compartiments S3.

  2. Exécutez l’instruction SQL suivante pour créer une règle de réseau permettant à Snowflake d’envoyer des requêtes à une destination externe, en veillant à définir la propriété TYPE sur 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. Exécutez l’instruction SQL suivante pour créer une intégration de sécurité pour l’authentification de l’API externe :

    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. Exécutez l’instruction SQL suivante pour obtenir les valeurs STORAGE_AWS_IAM_USER_ARN et STORAGE_AWS_EXTERNAL_ID pour l’utilisateur IAM :

    DESC SECURITY INTEGRATION aws_s3_security_integration;
    
    Copy
  5. À l’aide des valeurs STORAGE_AWS_IAM_USER_ARN et STORAGE_AWS_EXTERNAL_ID, suivez l”étape 5 dans Option 1 : Configuration d’une intégration de stockage Snowflake pour accéder à Amazon S3 pour accorder l’accès à l’utilisateur IAM au service Amazon S3.

  6. Exécutez l’instruction SQL suivante pour créer un jeton à utiliser pour l’authentification avec le service S3 AWS :

    CREATE OR REPLACE SECRET aws_s3_access_token
      TYPE = CLOUD_PROVIDER_TOKEN
      API_AUTHENTICATION = aws_s3_security_integration;
    
    Copy
  7. Exécutez l’instruction SQL suivante pour créer une intégration d’accès externe qui utilise la règle de réseau et le jeton créés dans les étapes précédentes :

    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. Exécutez l’une des instructions SQL suivantes pour créer une fonction qui peut utiliser l’intégration de l’accès externe et le jeton qui ont été créés précédemment :

    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. Exécutez l’une des instructions SQL suivantes pour exécuter la fonction que vous avez créée :

    SELECT aws_s3_python_function();
    
    Copy

Définir la connectivité privée vers un service Amazon Bedrock externe

  1. Appelez la fonction système SYSTEM$PROVISION_PRIVATELINK_ENDPOINT pour spécifier que Snowflake se connecte aux services AWS S3 et Amazon Bedrock, ainsi que les noms d’hôte à utiliser lors de la connexion aux services :

    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. Exécutez l’instruction SQL suivante pour créer une règle de réseau permettant à Snowflake d’envoyer des requêtes à une destination externe, en veillant à définir la propriété TYPE sur 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. Exécutez l’instruction SQL suivante pour créer une intégration de sécurité pour l’authentification de l’API externe :

    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. Exécutez l’instruction SQL suivante pour obtenir les valeurs STORAGE_AWS_IAM_USER_ARN et STORAGE_AWS_EXTERNAL_ID pour l’utilisateur IAM :

    DESC  SECURITY INTEGRATION bedrock_security_integration;
    
    Copy
  5. À l’aide des valeurs STORAGE_AWS_IAM_USER_ARN et STORAGE_AWS_EXTERNAL_ID, suivez l”étape 5 dans Option 1 : Configuration d’une intégration de stockage Snowflake pour accéder à Amazon S3 pour accorder l’accès à l’utilisateur IAM au service Amazon Bedrock.

  6. Exécutez l’instruction SQL suivante pour créer un jeton à utiliser pour l’authentification avec le service Bedrock AWS :

    CREATE OR REPLACE SECRET aws_bedrock_access_token
      TYPE = CLOUD_PROVIDER_TOKEN
      API_AUTHENTICATION = bedrock_security_integration;
    
    Copy
  7. Exécutez l’instruction SQL suivante pour créer une intégration d’accès externe qui utilise la règle de réseau et le jeton créés dans les étapes précédentes :

    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. Exécutez l’instruction SQL suivante pour créer une fonction qui peut utiliser l’intégration de l’accès externe et le jeton qui ont été créés précédemment :

    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. Exécutez l’instruction SQL suivante pour exécuter la fonction que vous avez créée :

    SELECT bedrock_private_connectivity_tests();
    
    Copy