Snowpark Container Services: Zusätzliche Hinweise zu Diensten

Verbinden mit Snowflake aus einem Container heraus

Wenn Sie einen Dienst (einschließlich Jobdienste) starten, stellt Snowflake den aktiven Containern Anmeldeinformationen zur Verfügung, damit Ihr Containercode Treiber für die Verbindung zu Snowflake und das Ausführen von SQL verwenden kann (ähnlich wie jeder andere Code auf Ihrem Computer, der sich mit Snowflake verbindet). Die bereitgestellten Anmeldeinformationen authentifizieren als Eigentümerrolle (die Rolle, die den Dienst erstellt hat). Snowflake stellt einige der Informationen als Umgebungsvariablen in Ihren Containern bereit.

Jedes Objekt in Snowflake hat eine Eigentümerrolle. Die Eigentümerrolle des Dienstes bestimmt, welche Funktionen Ihr Dienst bei der Interaktion mit Snowflake ausführen darf. Dazu gehören das Ausführen von SQL, der Zugriff auf Stagingbereiche und die Vernetzung zwischen Diensten.

Bemerkung

Die Eigentümerrolle eines Dienstes bezieht sich auf die Rolle, die den Dienst erstellt hat. Sie können auch eine oder mehrere Dienstrollen definieren, um den Zugriff auf die Endpunkte zu verwalten, die der Dienst bereitstellt. Weitere Informationen dazu finden Sie unter Verwalten des Zugriffs auf Dienstendpunkte.

Wenn Sie einen Dienst erstellen, erstellt Snowflake auch einen Dienstbenutzer speziell für diesen Dienst. Wenn der Dienst eine Abfrage ausführt, führt er die Abfrage als der Dienstbenutzer aus und verwendet die Eigentümerrolle des Dienstes. Was der Dienstbenutzer tun kann, wird durch die Eigentümerrolle bestimmt.

Die Eigentümerrolle des Dienstes darf keine der privilegierten Rollen sein, wie ACCOUNTADMIN und SECURITYADMIN. Dies soll die Möglichkeiten eines fehlerhaften Dienstes einschränken und verlangt von den Kunden ein größeres Maß an Aufmerksamkeit, wenn einem Dienst die Ausführung von administrativen Operationen ermöglicht wird.

Um die von einem bestimmten Dienstbenutzer erstellten Abfragen einzusehen, können Sie die Rolle ACCOUNTADMIN verwenden und den Abfrageverlauf anzeigen. Der Benutzername des Dienstbenutzers wird in den folgenden Formen angezeigt:

  • Bei einem Service, der vor dem Release 8.35 des Servers erstellt wurde, hat der Dienstbenutzer das Format SF$SERVICE$unique-id.

  • Bei einem Service, der nach dem Release 8.35 des Servers erstellt wurde, ist der Dienstbenutzer derselbe wie der Name des Services.

Verbinden mit Snowflake

Snowflake stellt die folgenden Umgebungsvariablen zur Verfügung, mit denen Sie einen Snowflake-Client in Ihrem Dienstcode konfigurieren können:

  • SNOWFLAKE_ACCOUNT: Liefert den Konto-Locator für das Snowflake-Konto, unter dem der Service derzeit läuft.

  • SNOWFLAKE_HOST: Gibt den Hostnamen an, der für die Verbindung zu Snowflake verwendet wird.

Snowflake stellt auch ein OAuth-Token im Container in einer Datei namens /snowflake/session/token bereit. Wenn Sie eine Verbindung herstellen, geben Sie dieses Token an den Konnektor weiter.

Wenn Sie eine Verbindung zu Snowflake von einem Container aus erstellen, müssen Sie SNOWFLAKE_HOST, SNOWFLAKE_ACCOUNT und das OAuth-Token verwenden. Sie können das OAuth-Token nur verwenden, wenn Sie auch SNOWFLAKE_HOST verwenden, und Sie können das OAuth-Token nicht außerhalb von Snowpark Container Services verwenden. Weitere Informationen dazu finden Sie unter Verwenden eines OAuth-Tokens zum Ausführen von SQL.

Bemerkung

Die Verwendung externer Integrationen für den Zugriff auf Snowflake kann bedeuten, dass potenziell sensible Informationen über das Internet gesendet werden. Wann immer möglich, sollten Services das bereitgestellte OAuth-Token verwenden, um auf den SNOWFLAKE_HOST-Hostnamen zuzugreifen. Dadurch müssen Sie nicht mehr über das Internet auf Snowflake zugreifen.

Beispielcode für die Verwendung verschiedener Snowflake-Treiber finden Sie unter Snowflake Connection Samples.

Beispiele

  • In Tutorial 2 (siehe main.py) liest der Code die Umgebungsvariablen wie folgt:

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

    Der Code übergibt diese Variablen an einen Verbindungserstellungscode für den Snowflake-Client Ihrer Wahl. Der Container verwendet diese Anmeldeinformationen, um eine neue Sitzung mit der Eigentümerrolle als Primärrolle zu erstellen, um Abfragen auszuführen. Der folgende Beispielcode zeigt, was mindestens zum Erstellen einer Snowflake-Verbindung in Python erforderlich ist:

    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
  • Wenn Sie den Standard-Host verwenden (d. h. Sie geben das Argument host beim Erstellen einer Verbindung nicht an), wird die Verbindung zu Snowflake mit anderen Formen der Authentifizierung (z. B. Benutzername und Kennwort) unterstützt. Bei der folgenden Verbindung werden zur Authentifizierung beispielsweise Benutzername und Kennwort angegeben:

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

    Die Verwendung eines Standard-Hosts erfordert eine Integration für den externen Zugriff mit einer Netzwerkregel, die den Zugriff von Ihrem Dienst auf den Snowflake-Hostnamen Ihres Kontos erlaubt. Wenn Ihr Kontoname beispielsweise MyAccount ist, lautet der Hostname myaccount.snowflakecomputing.com. Weitere Informationen dazu finden Sie unter Konfigurieren des Netzwerkausgangs.

    • Erstellen Sie eine Netzwerkregel, die einen Abgleich mit Snowflake-API-Hostnamen Ihres Kontos vornimmt:

      CREATE OR REPLACE NETWORK RULE snowflake_egress_access
        MODE = EGRESS
        TYPE = HOST_PORT
        VALUE_LIST = ('myaccount.snowflakecomputing.com');
      
      Copy
    • Erstellen Sie eine Integration unter Verwendung der obigen Netzwerkregel:

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

Konfigurieren des Datenbank- und Schemakontextes für das Ausführen von SQL

In diesem Abschnitt werden zwei Konzepte erläutert:

  • Die Logik, mit der Snowflake Datenbank und Schema bestimmt, in dem Ihr Dienst erstellt werden soll.

  • Die Methode, mit der Snowflake diese Informationen an Ihre Container weitergibt, sodass der Containercode SQL im gleichen Datenbank- und Schemakontext ausführen kann.

Snowflake verwendet den Dienstnamen, um die Datenbank und das Schema zu bestimmen, in denen ein Dienst erstellt werden soll:

  • Beispiel 1: In den folgenden Befehlen CREATE SERVICE und EXECUTE JOB SERVICE gibt der Dienstname nicht explizit einen Datenbank- und Schemanamen an. Snowflake erstellt den Dienst und den Jobdienst in der aktuellen Datenbank und dem aktuellen Schema.

    -- 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
  • Beispiel 2: In den folgenden Befehlen CREATE SERVICE und EXECUTE JOB SERVICE enthält der Dienstname einen Datenbank- und einen Schemanamen. Snowflake erstellt den Dienst und den Jobdienst in der angegebenen Datenbank (test_db) und dem angegebenen Schema (test_schema), unabhängig vom aktuellen 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

Wenn Snowflake einen Dienst startet, werden den ausgeführten Containern die Datenbank- und Schemainformationen über die folgenden Umgebungsvariablen zur Verfügung gestellt:

  • SNOWFLAKE_DATABASE

  • SNOWFLAKE_SCHEMA

Ihr Containercode kann Umgebungsvariablen im Verbindungscode verwenden, um die zu verwendende Datenbank und das Schema zu bestimmen, wie im folgenden Beispiel gezeigt:

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

Beispiel

In Tutorial 2 erstellen Sie einen Snowflake-Jobdienst, der sich mit Snowflake verbindet und SQL-Anweisungen ausführt. Die folgenden Schritte fassen zusammen, wie der Tutorial-Code die Umgebungsvariablen verwendet:

  1. Bei der grundlegenden Einrichtung (siehe Abschnitt Grundlegende Einrichtung) erstellen Sie Ressourcen, einschließlich einer Datenbank und eines Schemas. Sie legen auch die aktuelle Datenbank und das aktuelle Schema für die Sitzung fest:

    USE DATABASE tutorial_db;
    ...
    USE SCHEMA data_schema;
    
    Copy
  2. Nachdem Sie einen Jobdienst erstellt haben (durch Ausführen von EXECUTE JOB SERVICE), startet Snowflake den Container und setzt die folgenden Umgebungsvariablen im Container auf die aktuelle Datenbank und das aktuelle Schema der Sitzung:

    • SNOWFLAKE_DATABASE ist auf „TUTORIAL_DB“ gesetzt.

    • SNOWFLAKE_SCHEMA ist auf „DATA_SCHEMA“ gesetzt.

  3. Der Jobcode (siehe main.py in Tutorial 2) liest diese Umgebungsvariablen aus:

    SNOWFLAKE_DATABASE = os.getenv('SNOWFLAKE_DATABASE')
    SNOWFLAKE_SCHEMA = os.getenv('SNOWFLAKE_SCHEMA')
    
    Copy
  4. Der Jobcode legt die Datenbank und das Schema als Kontext fest, in dem die SQL-Anweisungen ausgeführt werden (Funktion run_job() in main.py):

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

    Bemerkung

    SNOWFLAKE_ACCOUNT SNOWFLAKE_HOST, SNOWFLAKE_DATABASE, SNOWFLAKE_SCHEMA sind Umgebungsvariablen, die Snowflake für den Anwendungscontainer generiert, allerdings nicht SNOWFLAKE_WAREHOUSE (der Anwendungscode von Tutorial 2 erstellt diese Variable, da Snowflake keinen Warehouse-Namen an einen Container übergibt).

Angeben des Warehouses für Ihren Container

Wenn Ihr Dienst eine Verbindung zu Snowflake herstellt, um eine Abfrage in einem Snowflake-Warehouse auszuführen, haben Sie die folgenden Optionen für die Angabe des Warehouses:

  • Warehouse in Ihrem Anwendungscode angeben. Geben Sie ein Warehouse als Teil der Verbindungskonfiguration an, wenn Sie eine Snowflake-Sitzung zum Ausführen von Abfragen in Ihrem Code starten. Ein Beispiel dazu finden Sie unter Tutorial 2.

  • Standard-Warehouse beim Erstellen eines Dienstes angeben. Geben Sie den optionalen Parameter QUERY_WAREHOUSE im Befehl CREATE SERVICE (oder EXECUTE JOB SERVICE) an, um ein Standard-Warehouse bereitzustellen. Wenn Ihr Anwendungscode kein Warehouse als Teil der Verbindungskonfiguration bereitstellt, verwendet Snowflake das Standard-Warehouse. Verwenden Sie den Befehl ALTER SERVICE, um das Standard-Warehouse zu ändern.

Wenn Sie ein Warehouse mit beiden Methoden angeben, wird das im Anwendungscode angegebene Warehouse verwendet.

Verwenden eines OAuth-Tokens zum Ausführen von SQL

Alle von Snowflake bereitgestellten Clients unterstützen OAuth als Authentifizierungsoption. Auch Dienstcontainer verwenden den OAuth-Mechanismus zur Authentifizierung bei Snowflake. Wenn ein Container zum Beispiel SQL ausführen möchte, stellt er eine Verbindung zu Snowflake her, ähnlich wie jeder andere Snowflake-Client:

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

Wenn Sie einen Dienst erstellen, führt Snowflake die Container aus und stellt den Containern ein OAuth-Token zur Verfügung, das an der folgendem Speicherort innerhalb des Containers verwendet wird: /snowflake/session/token.

Beachten Sie die folgenden Details zu diesem OAuth-Token:

  • Sie müssen den Inhalt der Datei /snowflake/session/token unmittelbar vor der Verwendung lesen, da der Inhalt innerhalb von 10 Minuten abläuft, und Snowflake diese Datei alle paar Minuten aktualisiert. Nachdem sich ein Container erfolgreich mit Snowflake verbunden hat, gilt die Ablaufzeit nicht mehr für die Verbindung (wie bei allen Sitzungen, die Benutzer direkt erstellen).

  • Dieses OAuth-Token ist nur innerhalb des jeweiligen Snowflake-Dienstes gültig. Sie können das OAuth-Token nicht kopieren und außerhalb des Dienstes verwenden.

  • Unter Verwendung des OAuth-Tokens verbinden sich die Container mit Snowflake als Dienstbenutzer und verwenden die Eigentümerrolle des Dienstes.

  • Die Verwendung des OAuth-Tokens zum Herstellen einer Verbindung führt zu einer neuen Sitzung. Das OAuth-Token ist mit keiner bestehenden SQL-Sitzung verbunden.

    Bemerkung

    Ein wesentlicher Unterschied zwischen dem Ausführen von gespeicherten Prozeduren und dem Ausführen eines Dienstes besteht darin, dass gespeicherte Prozeduren in der gleichen Sitzung ausgeführt werden wie der SQL-Code, der sie ausführt. Aber jedes Mal, wenn ein Container eine neue Verbindung aufbaut, wird eine neue Sitzung erstellt.

Konnektivität mit Snowflake aus einem Container heraus unter Verwendung Aufruferrechte

Container führen Abfragen aus, indem sie sich als Dienstbenutzer mit Snowflake verbinden und die Eigentümerrolle des Dienstes verwenden, die dem Dienst Berechtigungen gewährt. In bestimmten Anwendungsszenarien kann es erforderlich sein, dass Sie Abfragen im Kontext des Endbenutzers und nicht des Dienstbenutzers ausführen müssen. In diesem Kontext wird das Aufruferrechte-Feature verwendet.

Nehmen wir zum Beispiel an, Sie erstellen einen Dienst, der einen öffentlichen Endpunkt für eine Webanwendung bereitstellt, die ein Dashboard mit in Snowflake gespeicherten Daten anzeigt. Sie gewähren anderen Benutzern in Ihrem Snowflake-Konto Zugriff auf das Dashboard (indem Sie diesen Benutzern die Dienstrolle zuweisen). Wenn sich einer dieser Endbenutzer beim Dashboard anmeldet, soll das Dashboard nur die Daten anzeigen, auf die der Benutzer Zugriff hat.

Da Container jedoch standardmäßig Abfragen unter Verwendung des Dienstbenutzers und der Eigentümerrolle des Dienstes ausführen, zeigt das Dashboard die Daten an, auf die die Eigentümerrolle des Dienstes Zugriff hat, unabhängig davon, welcher Endbenutzer mit dem Endpunkt verbunden ist. Daher sind die Daten im Dashboard des Benutzers nicht auf die Daten beschränkt, auf die der Benutzer Zugriff hat, so dass der Benutzer auf Daten zugreifen kann, auf die er keinen Zugriff hat.

Um das Dashboard so einzuschränken, dass nur Daten angezeigt werden, auf die der angemeldete Benutzer Zugriff hat, müssen die Anwendungscontainer SQL mit den Berechtigungen des Endbenutzers ausführen. Sie können dies aktivieren, indem Sie die Aufruferrechte in der Anwendung verwenden.

Bemerkung

  • Das Aufruferrechte-Feature wird nur unterstützt, wenn der Zugriff auf einen Dienst über den Netzwerkeingang erfolgt. Das Feature ist nicht verfügbar, wenn Sie eine Dienstfunktion für den Zugriff auf den Dienst verwenden.

  • Das Aufruferrechte-Feature wird derzeit in Snowflake Native App (Apps mit Containern nicht) unterstützt.

Konfigurieren der Aufruferrechte für Ihren Dienst

Die Konfiguration der Aufruferrechte für Ihre Anwendung ist ein zweistufiger Prozess.

  1. Setzen Sie executeAsCaller in der Dienstspezifikation auf true, wie im folgenden Spezifikationsfragment gezeigt:

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

    Dies teilt Snowflake ausdrücklich mit, dass die Anwendung beabsichtigt, die Aufruferrechte zu verwenden und veranlasst Snowflake, den Sf-Context-Current-User-Token-Header in jede eingehende Anfrage einzufügen, bevor die Anfrage an den Anwendungscontainer gesendet wird. Dieses Benutzer-Token erleichtert die Ausführung der Abfrage als aufrufender Benutzer. Wenn nichts angegeben wird, ist executeAsCaller standardmäßig auf false eingestellt.

    Die Angabe der Option executeAsCaller wirkt sich nicht auf die Möglichkeit des Dienstes aus, Abfragen in der Dienstbenutzerrolle und der Eigentümerrolle des Dienstes auszuführen. Wenn executeAsCaller aktiviert ist, hat der Dienst die Möglichkeit, sich sowohl als aufrufender Benutzer als auch als Dienstbenutzer mit Snowflake zu verbinden.

  2. Aktualisieren Sie Ihren Anwendungscode. Um eine Snowflake-Verbindung im Namen des aufrufenden Benutzers herzustellen, aktualisieren Sie Ihren Code, um ein Anmeldetoken zu erstellen, das sowohl das OAuth-Token, das Snowflake dem Dienst bereitgestellt hat, als auch das Benutzer-Token aus dem Sf-Context-Current-User-Token-Header enthält. Das Anmeldetoken sollte diesem Format entsprechen: <service-oauth-token>.<Sf-Context-Current-User-Token>.

    Dies wird in dem folgenden Python-Codefragment veranschaulicht:

    # 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

Im obigen Beispiel:

  • Die Funktion get_login_token liest die Datei, in die Snowflake das OAuth-Token für den zu verwendenden Container kopiert hat.

  • Die Funktion get_connection_params konstruiert ein Token durch Verkettung des OAuth-Tokens und des Benutzertokens aus dem Sf-Context-Current-User-Token-Header. Die Funktion nimmt dieses Token in ein Verzeichnis von Parametern auf, die die Anwendung für die Verbindung mit Snowflake verwendet.

Ein Beispiel mit einer Schritt-für-Schritt-Anleitung finden Sie unter Erstellen eines Dienstes mit aktivierten Aufruferrechten.

Zugriff auf einen Dienst mit konfigurierten Aufruferrechten

Bei der Konfiguration der Aufruferrechte geht es darum, dass Ihr Dienst im Namen des Aufrufers eine Snowflake-Verbindung aufbaut. Die Art und Weise, wie Sie sich bei den Eingangsendpunkten des Dienstes anmelden (programmgesteuert oder über einen Browser), bleibt unverändert. Nach der Anmeldung gilt Folgendes:

  • Zugriff auf einen öffentlichen Endpunkt über einen Browser: Nachdem Sie sich bei einem Endpunkt angemeldet haben, stellt der Dienst im Namen des anrufenden Benutzers mit der Standardrolle des Benutzers eine Verbindung zu Snowflake her. Wenn keine Standardrolle für den Benutzer konfiguriert ist, wird die Rolle PUBLIC verwendet.

  • Programmgesteuerter Zugriff auf einen öffentlichen Endpunkt: Bei der programmgesteuerten Anmeldung bei einem Endpunkt mit dem JWT-Token können Sie optional den Parameter scope setzen, um die zu aktivierende Rolle anzugeben

Nachdem ein Dienst die Verbindung zu Snowflake mit Aufruferrechten im Namen des Aufrufers hergestellt hat, wird ein Umschalten zwischen den Rollen derzeit nicht unterstützt. Wenn Ihre Anwendung verschiedene Rollen für den Zugriff auf verschiedene Objekte benötigt, richten Sie den Benutzer so ein, dass alle sekundären Rollen standardmäßig aktiv sind. Verwenden Sie dazu den Befehl ALTER USER, um die Eigenschaft DEFAULT_SECONDARY_ROLES des Benutzers auf (‚ALL‘) einzustellen:

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

Verwalten von Aufruferberechtigungen für einen Dienst

Wenn ein Dienst eine Sitzung mit Aufruferrechten erstellt, arbeitet die Sitzung als aufrufender Benutzer (nicht als Dienstbenutzer). Wenn eine Operation über diese Sitzung durchgeführt wird, wendet Snowflake zwei Berechtigungsprüfungen an:

  1. Die erste Berechtigungsprüfung erfolgt so, als hätte der Benutzer die Sitzung direkt erstellt. Dies sind die normalen Berechtigungsprüfungen, die Snowflake für den Benutzer durchführt.

  2. Die zweite Berechtigungsprüfung verifiziert, dass der Dienst die Operation im Namen eines Benutzers durchführen darf. Snowflake überprüft dies, indem sichergestellt wird, dass der Rolle des Diensteigentümers die erforderlichen Aufruferberechtigungen gewährt wurden.

In einer Sitzung mit Aufruferrechten müssen sowohl die normale Berechtigungsprüfung als auch die Prüfung der Aufruferrechte der Rolle des Diensteigentümers die Operation erlauben. Dies wird als eingeschränkte Aufruferrechte bezeichnet. Standardmäßig hat der Dienst keine Berechtigung, etwas im Namen eines Benutzers zu tun. Sie müssen dem Dienst explizit Aufruferrechte gewähren, damit er mit den Berechtigungen des Aufrufers ausgeführt werden kann.

Nehmen wir zum Beispiel an, dass ein Benutzer U1 eine Rolle R1 verwendet, die die Berechtigung SELECT für die Tabelle T1 hat. Wenn sich U1 bei dem öffentlichen Endpunkt Ihres Dienstes (example_service) anmeldet, der so konfiguriert ist, dass er die Aufruferrechte verwendet, stellt der Dienst dann im Namen von U1 eine Verbindung zu Snowflake her.

Damit der Dienst die Tabelle T1 im Namen von U1 abfragen kann, müssen Sie der Rolle des Diensteigentümers die folgenden Berechtigungen erteilen:

  1. Berechtigungen zur Auflösung des Tabellennamens, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der USAGE-Berechtigung auf der Datenbank und dem Schema für diese Tabelle zu arbeiten.

  2. Berechtigung zur Verwendung eines Warehouse, um Abfragen auszuführen, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der entsprechende USAGE-Berechtigung auf dem Warehouse zu arbeiten.

  3. Berechtigungen zur Abfrage der Tabelle, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der SELECT-Berechtigung auf der Tabelle T1 ausgeführt zu werden.

-- 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

Jede Rolle in Ihrem Konto, die über die globale Berechtigung MANAGE CALLER GRANT verfügt, kann Aufruferberechtigungen gewähren. Weitere Informationen über Aufruferrechte finden Sie unter GRANT CALLER und Eingeschränkte Aufruferrechte.

Beispiel

Hier finden Sie ein Beispiel für einen Dienst, der bei der Ausführung von SQL-Abfragen im Namen der Benutzer das Aufruferrechte-Feature verwendet. Weitere Informationen finden Sie unter Erstellen eines Dienstes mit aktivierten Aufruferrechten.

Konfigurieren des Netzwerkeingangs

Um eine Interaktion mit Ihrem Dienst vom Internet aus zu ermöglichen, deklarieren Sie die Netzwerkports, die von Ihrem Dienst überwacht werden, als Endpunkte in der Dienstspezifikationsdatei. Diese Endpunkte kontrollieren den eingehenden Datenverkehr.

Standardmäßig sind die Dienstendpunkte privat. Nur Dienstfunktionen und die Dienst-zu-Dienst-Kommunikation können Anforderungen an die privaten Endpunkte senden. Sie können einen Endpunkt als öffentlich deklarieren, um Anforderungen an einen Endpunkt aus dem Internet zuzulassen. Die Eigentümerrolle des Dienstes muss über die Berechtigung BIND SERVICE ENDPOINT für das Konto verfügen.

endpoints:
- name: <endpoint name>
  port: <port number>
  protocol : < TCP / HTTP / HTTPS >
  public: true
Copy

Ein Beispiel dazu finden Sie unter Tutorial 1.

Bemerkung

Derzeit unterstützen nur Dienste, nicht aber Jobdienste, den Netzwerkzugang (eingehende Daten).

Sicherheit von Eingangsdatenverkehr und Webanwendungen

Sie können einen Snowpark Container Services-Dienst für das Webhosting erstellen, indem Sie die Unterstützung für öffentliche Endpunkte (Netzwerkeingang) nutzen. Für zusätzliche Sicherheit setzt Snowflake einen Proxydienst ein, um eingehende Anforderungen von Clients an Ihren Dienst und ausgehende Antworten von Ihrem Dienst an die Clients zu überwachen. In diesem Abschnitt wird erklärt, was der Proxy tut und wie er sich auf einen Dienst auswirkt, der in Snowpark Container Services bereitgestellt wird.

Bemerkung

Wenn Sie einen Dienst lokal testen, verwenden Sie nicht den Snowflake-Proxy. Daher wird es Unterschiede zwischen der lokalen Ausführung eines Dienstes und der Bereitstellung in Snowpark Container Services geben. Lesen Sie diesen Abschnitt, und aktualisieren Sie Ihre lokalen Einstellungen, um das Testen zu optimieren.

Beispiel:

  • Der Proxy leitet eine eingehende HTTP-Anforderung nicht weiter, wenn die Anforderung eine nicht zulässige HTTP-Methode verwendet.

  • Der Proxy sendet eine 403-Antwort an den Client, wenn der Content-Type-Header in der Antwort angibt, dass die Antwort eine ausführbare Datei enthält.

Darüber hinaus kann der Proxy auch neue Kopfzeilen einfügen und bestehende Kopfzeilen in der Anforderung und der Antwort ändern, wobei Ihr Container und Ihre Datensicherheit berücksichtigt werden.

Beispielsweise könnte Ihr Dienst nach Erhalt einer Anforderung in der Antwort HTML-, JavaScript-, CSS- und andere Inhalte für eine Webseite an den Client-Browser senden. Die Webseite im Browser ist Teil Ihres Dienstes und dient als Benutzerschnittstelle. Wenn Ihr Dienst aus Sicherheitsgründen Einschränkungen unterliegt (z. B. bezüglich des Herstellens von Netzwerkverbindungen zu anderen Standorten), möchten Sie vielleicht auch, dass die Webseite Ihres Dienstes denselben Einschränkungen unterliegt.

Standardmäßig haben Dienste nur begeschränkte Berechtigungen für den Zugriff auf das Internet. Der Browser sollte auch verhindern, dass die Clientanwendung auf das Internet zugreift und möglicherweise in den meisten Fällen Daten freigibt. Wenn Sie eine Integration des externen Zugriffs (EAI) eingerichtet haben, um Ihrem Dienst den Zugriff auf example.com zu ermöglichen (siehe Konfigurieren des Netzwerkausgangs), sollte die Webseite für Ihren Dienst auch über Ihren Browser auf example.com zugreifen können.

Der Snowflake-Proxy wendet dieselben Netzwerkbeschränkungen auf den Dienst und die Webseite an, indem er einen CSP-Header (Content-Security-Policy) in die Antwort einfügt. Standardmäßig fügt der Proxy eine Baseline-CSP in die Antwort ein, um Schutz vor allgemeinen Sicherheitsbedrohungen zu bieten. Bei der Browser-Sicherheit geht es darum, ein Gleichgewicht zwischen Funktionalität und Sicherheit zu finden. Es liegt in der gemeinsamen Verantwortung sicherzustellen, dass diese Basis für Ihren Anwendungsfall geeignet ist. Wenn Ihr Dienst so konfiguriert ist, dass eine EAI verwendet wird, wendet der Proxy außerdem dieselben Netzwerkregeln von der EAI auf die CSP der Webseite an. Diese CSP ermöglicht der Webseite im Browser auf dieselben Standorte zuzugreifen, auf die auch der Dienst zugreifen kann.

In den folgenden Abschnitten wird erläutert, wie der Snowflake-Proxy eingehende Anforderungen für Ihren Dienst verarbeitet und die ausgehenden Antworten Ihres Dienstes an die Clients modifiziert.

Beim Dienst eingehende Anforderungen

Wenn eine Anforderung eintrifft, führt der Proxy folgende Schritte aus, bevor er die Anforderung an den Dienst weiterleitet:

  • Eingehende Anforderungen mit nicht zulässigen HTTP-Methoden: Wenn eine eingehende HTTP-Anforderung eine der folgenden nicht zulässigen HTTP-Methoden verwendet, leitet der Proxy die Anforderung nicht an Ihren Dienst weiter:

    • TRACE

    • OPTIONS

    • CONNECT

An die Clients ausgehende Antworten

Der Snowflake-Proxy wendet diese Änderungen auf die von Ihrem Dienst gesendete Antwort an, bevor er die Antwort an den Client weiterleitet.

  • Header Scrubbing: Der Snowflake-Proxy entfernt diese Antwort-Header, falls vorhanden:

    • X-XSS-Protection

    • Server

    • X-Powered-By

    • Public-Key-Pins

  • Antwort-Header „Content-Type“: Wenn die Antwort Ihres Dienstes den „Content-Type“-Header mit einem der folgenden Werte des MIME-Typs (der auf eine ausführbare Datei hinweist) enthält, leitet der Snowflake-Proxy diese Antwort nicht an den Client weiter. Stattdessen sendet der Proxy eine 403 Forbidden-Antwort.

    • application/x-msdownload: ausführbare Microsoft-Datei.

    • application/exe: allgemeine ausführbare Datei.

    • application/x-exe: eine weitere allgemeine ausführbare Datei.

    • application/dos-exe: ausführbare DOS-Datei.

    • application/x-winexe: ausführbare Windows-Datei.

    • application/msdos-windows: ausführbare MS-DOS-Windows-Datei.

    • application/x-msdos-program: ausführbare MS-DOS-Datei.

    • application/x-sh: Unix-Shell-Skript.

    • application/x-bsh: Bourne-Shell-Skript.

    • application/x-csh: C-Shell-Skript.

    • application/x-tcsh: Tcsh-Shell-Skript.

    • application/batch: Windows-Batch-Datei.

  • Antwort-Header „X-Frame-Options“: Um Clickjacking-Angriffe zu verhindern, setzt der Snowflake-Proxy diesen Antwort-Header auf DENY und verhindert so, dass andere Webseiten einen iFrame zur Webseite für Ihren Dienst verwenden.

  • Antwort-Header „Cross-Origin-Opener-Policy“ (COOP): Snowflake setzt den COOP-Antwort-Header auf same-origin, um zu verhindern, dass verweisende Cross-Origin-Fenster auf Ihre Dienst-Registerkarte zugreifen.

  • Antwort-Header „Cross-Origin-Resource-Policy“ (CORP): Snowflake setzt den CORP-Header auf same-origin, um zu verhindern, dass externe Websites Ressourcen laden, die vom Eingangsendpunkt bereitgestellt werden (z. B. in einem iFrame).

  • Antwort-Header „X-Content-Type-Options“: Snowflake-Proxy setzt diesen Header auf nosniff, um sicherzustellen, dass die Clients den von Ihrem Dienst in der Antwort angegebenen MIME-Typ nicht ändern.

  • Antwort-Header „Cross-Origin-Embedder-Policy“ (COEP): Snowflake-Proxy setzt den COEP-Antwort-Header auf credentialless, was bedeutet, dass Snowflake beim Laden eines Cross-Origin-Objekts, z. B. eines Images oder eines Skripts, die Anmeldeinformationen nicht sendet, wenn das Remoteobjekt das „Cross-Origin Resource Sharing“ (CORS)-Protokoll nicht unterstützt.

  • Antwort-Header „Content-Security-Policy-Report-Only“: Snowflake-Proxy ersetzt diesen Antwort-Header durch einen neuen Wert, der den Client anweist, die CSP-Berichte an Snowflake zu senden.

  • Antwort-Header „Content-Security-Policy“ (CSP): Standardmäßig fügt der Snowflake-Proxy die folgende Baseline-CSP hinzu, um sich gegen gängige Webangriffe zu schützen.

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

    Es gibt zwei Überlegungen zur Inhaltssicherheitsrichtlinie:

    • Zusätzlich zur Baseline-Sicherheitsrichtlinie für Inhalte, die der Proxy hinzufügt, kann der Dienst selbst explizit eine CSP in der Antwort hinzufügen. Ein Dienst könnte sich dafür entscheiden, die Sicherheit durch Hinzufügen einer strengeren CSP zu erhöhen. Ein Dienst könnte zum Beispiel folgendes CSP hinzufügen, um nur Skripte von self zuzulassen.

      script-src 'self'
      
      Copy

      In der Antwort, die an den Client gesendet wird, sind zwei CSP-Header enthalten. Nach Erhalt der Antwort wenden die Client-Browser dann die strengste Inhaltssicherheitsrichtlinie an, die die in den einzelnen Richtlinien angegebenen zusätzlichen Einschränkungen enthält.

    • Wenn Sie eine Integration für den externen Zugriff (EAI) konfigurieren, um Ihrem Dienst den Zugriff auf eine externe Website (Konfigurieren des Netzwerkausgangs) zu ermöglichen, erstellt der Snowflake-Proxy eine CSP, die Ihrer Webseite den Zugriff auf diese Site ermöglicht. Angenommen, eine mit einer EAI verknüpfte Netzwerkregel erlaubt Ihrem Dienst den Ausgangsdatenzugriff auf example.com. Dann fügt der Snowflake-Proxy diesen CSP-Antwort-Header hinzu:

      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

      Die Browser halten sich an die in der Antwort enthaltene Inhaltszugriffsrichtlinie. In diesem Beispiel erlauben die Browser der App den Zugriff auf example.com, aber nicht auf andere Websites.

Überlegungen zum Zugriff und SSO

Wenn Sie vom Internet aus auf den öffentlichen Endpunkt zugreifen, kann es sein, dass die Authentifizierung mit Benutzername und Kennwort funktioniert, aber SSO zu einer leeren Seite oder dem Fehler führt: „OAuth Clientintegration mit der angegebenen Client-ID wurde nicht gefunden.“

Dies passiert, wenn Sie die alte Methode der föderierten Authentifizierung (SSO) mit Snowflake anstelle der neueren Version der Sicherheitsintegration verwenden, wie unter Konfigurieren von Snowflake für die Verwendung der Verbundauthentifizierung beschrieben. Gehen Sie wie folgt vor, um dies zu überprüfen:

  1. Führen Sie die folgende Abfrage aus:

    SHOW PARAMETERS LIKE 'SAML_IDENTITY_PROVIDER' IN ACCOUNT;
    
    Copy

    Wenn Sie diesen Parameter gesetzt haben, haben Sie zu irgendeinem Zeitpunkt die alte föderierte Authentifizierung verwendet.

  2. Wenn der obige Parameter gesetzt wurde, führen Sie die folgenden Abfragen aus, um festzustellen, ob Sie über eine SAML-Sicherheitsintegration verfügen:

    SHOW INTEGRATIONS;
    SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE "type" = 'SAML2';
    
    Copy

    Wenn Sie keine Integrationen des Typs SAML2 haben, dann verwenden Sie die alte Methode der föderierten Authentifizierung.

In diesem Fall besteht die Lösung darin, von der alten Methode der föderierten Authentifizierung auf die neue, integrative Methode der föderierten Authentifizierung umzusteigen. Weitere Informationen dazu finden Sie unter Migration zu einer SAML2-Sicherheitsintegration.

Konfigurieren des Netzwerkausgangs

Der Code Ihrer Anwendung erfordert möglicherweise einen Zugang zum Internet. Standardmäßig haben Anwendungscontainer keine Berechtigung für den Zugriff auf das Internet. Sie müssen daher den Internetzugang über Integrationen für den externen Zugriff (External Access Integrations, EAIs) aktivieren.

In der Regel werden EAIs von einem Kontoadministrator erstellt, um den von Diensten (einschließlich Jobdiensten) erlaubten externen Zugriff zu verwalten. Kontoadministratoren können dann die Berechtigung zur EAI-Nutzung bestimmten Rollen zuweisen, die Entwickler zum Ausführen von Diensten verwenden.

Im folgenden Beispiel werden die Schritte zum Erstellen einer EAI beschrieben, die ausgehenden Datenverkehr zu bestimmten Zielen zulässt, die mithilfe von Netzwerkregeln spezifiziert werden. Sie können sich dann auf diese EAI beziehen, wenn Sie einen Dienst erstellen, um Anforderungen an bestimmte Internetziele zuzulassen.

Beispiel

Angenommen, Sie möchten, dass Ihr Anwendungscode Anforderungen an die folgenden Ziele sendet:

  • HTTPS-Anforderung an translation.googleapis.com

  • HTTP- und HTTPS-Anforderung an google.com

Führen Sie die folgenden Schritte aus, damit Ihr Dienst auf diese Domänen im Internet zugreifen kann:

  1. Erstellen Sie eine Integration für den externen Zugriff (EAI). Dafür sind die entsprechenden Berechtigungen erforderlich. Sie können zum Beispiel die Rolle ACCOUNTADMIN verwenden, um eine EAI zu erstellen. Dies ist ein zweistufiger Prozess:

    1. Verwenden Sie den Befehl CREATE NETWORK RULE, um eine oder mehrere Netzwerkregeln für den ausgehenden Datenverkehr zu erstellen, wobei in den Regeln die externen Ziele aufgeführt sind, für die Sie den Zugriff erlauben möchten. Sie können benötigen für dieses Beispiel normalerweise nur eine Netzwerkregel, aber zur Veranschaulichung erstellen wir hier zwei Netzwerkregeln:

      1. Erstellen Sie eine Netzwerkregel namens translate_network_rule.

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

        Diese Regel erlaubt TCP-Verbindungen zum Ziel translation.googleapis.com. Die Domäne in der Eigenschaft VALUE_LIST gibt keine optionale Portnummer an, sodass der Standardport 443 (HTTPS) angenommen wird. Dadurch kann Ihre Anwendung eine Verbindung zu jeder URL herstellen, die mit https://translation.googleapis.com/ beginnt.

      2. Erstellen Sie eine Netzwerkregel namens 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

        Dadurch kann Ihre Anwendung eine Verbindung zu jeder URL herstellen, die mit http://google.com/ oder https://google.com/ beginnt.

      Bemerkung

      Für den Parameter VALUE_LIST müssen Sie einen vollständigen Hostnamen angeben. Platzhalter (z. B. *.googleapis.com) werden nicht unterstützt.

      Snowpark Container Services unterstützt nur die Netzwerkregeln, die die Ports 22, 80, 443 und 1024+ erlauben. Wenn eine referenzierte Netzwerkregel den Zugriff auf andere Ports zulässt, schlägt das Erstellen des Dienstes fehl. Wenden Sie sich an Ihren Kundenbetreuer, wenn Sie zusätzliche Ports benötigen.

      Bemerkung

      Damit Ihr Dienst HTTP- oder HTTPS-Anforderungen an ein beliebiges Ziel im Internet senden kann, geben Sie in der VALUE_LIST-Eigenschaft „0.0.0.0“ als Domäne an. Die folgende Netzwerkregel erlaubt es, sowohl „HTTP“- als auch „HTTPS“-Anforderungen an beliebige Ziele im Internet zu senden. Mit „0.0.0.0“ werden nur die Ports 80 oder 443 unterstützt.

      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. Erstellen Sie eine Integration für den externe Zugriff (EAI), die festlegt, dass die beiden obigen Netzwerkregeln für ausgehenden Datenverkehr zulässig sind:

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

      Nun kann der Kontoadministrator Entwicklern die Nutzung (USAGE) der Integration gestatten, damit diese einen Dienst ausführen können, der auf bestimmte Ziele im Internet zugreifen kann.

      GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE test_role;
      
      Copy
  2. Erstellen Sie den Dienst durch Angabe der EAI wie in den folgenden Beispielen gezeigt. Die Eigentümerrolle, die den Dienst erstellt, benötigt die Berechtigung USAGE für die EAI und die Berechtigung READ für die referenzierten Geheimnisse. Beachten Sie, dass Sie mit der Rolle ACCOUNTADMIN keine Dienste erstellen können.

    • Erstellen Sie einen Dienst:

      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

      Diese CREATE SERVICE-Beispielanforderung verwendet eine Inline-Dienstspezifikation und gibt die optionale Eigenschaft EXTERNAL_ACCESS_INTEGRATIONS an, um die EAI einzuschließen. Die EAI gibt die Netzwerkregeln an, die den ausgehenden Datenverkehr vom Dienst zu den spezifischen Zielen erlauben.

    • Führen Sie einen Jobdienst aus:

      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

      Dieser EXECUTE JOB SERVICE-Beispielbefehl gibt die Inline-Spezifikation und die optionale Eigenschaft EXTERNAL_ACCESS_INTEGRATIONS an, um die EAI einzuschließen. Dadurch wird der ausgehende Datenverkehr vom Job zu den in den Netzwerkregeln angegebenen Zielen zugelassen, die die EAI zulässt.

Netzwerkausgang über private Konnektivität

Anstatt den Netzwerkausgag über das öffentliche Internet zu routen, können Sie sich dafür entscheiden, den Ausgangverkehr Ihres Dienstes über einen privaten Konnektivitätsendpunkt zu leiten.

Zunächst müssen Sie den privaten Konnektivitätsendpunkt in Ihrem Snowflake-Konto erstellen. Konfigurieren Sie dann eine Netzwerkregel, um den ausgehenden Datenverkehr über die private Konnektivität zuzulassen. Der Prozess zur Einrichtung einer External Access Integration (EAI) bleibt derselbe wie im vorangegangenen Abschnitt beschrieben.

Bemerkung

Private Kommunikation erfordert, dass sowohl Snowflake als auch das Cloud-Konto des Kunden denselben Cloudanbieter und dieselbe Region verwenden.

Wenn Sie zum Beispiel den ausgehenden Internetzugang Ihres Dienstes zu einem Amazon S3-Bucket über private Konnektivität aktivieren möchten, gehen Sie wie folgt vor:

  1. Aktivieren Sie die private Link-Konnektivität für den selbstverwalteten Endpunktdienst (Amazon S3). Eine Schritt-für-Schritt-Anleitung finden Sie unter AWS Private Link for Amazon S3.

  2. Rufen Sie die Systemfunktion SYSTEM$PROVISION_PRIVATELINK_ENDPOINT auf, um einen privaten Konnektivitätsendpunkt in Ihrem Snowflake-VNet bereitzustellen. Dadurch kann Snowflake über private Konnektivität eine Verbindung zum externen Dienst (in diesem Beispiel Amazon S3) herstellen.

    USE ROLE ACCOUNTADMIN;
    
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.s3',
      '*.s3.us-west-2.amazonaws.com'
    );
    
    Copy
  3. Genehmigen Sie den Endpunkt im Konto des Cloudanbieters. In diesem Beispiel für Amazon AWS, siehe Verbindungsanfragen annehmen oder ablehnen in der AWS-Dokumentation. Um den Endpunkt in Azure zu genehmigen, lesen Sie auch die Azure-Dokumentation.

  4. Verwenden Sie den Befehl CREATE NETWORK RULE, um eine Netzwerkegel für den ausgehenden Datenverkehr zu erstellen, in der Sie die externen Ziele angeben, für die Sie den Zugriff erlauben möchten.

    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

    Der Parameters TYPE ist auf PRIVATE_HOST_PORT eingestellt. Er zeigt an, dass die Netzwerkregel den ausgehenden Datenverkehr über die private Konnektivität zulässt.

  5. Die übrigen Schritte zur Erstellung eines EAI und dessen Verwendung zur Erstellung eines Dienstes sind die gleichen wie im vorangegangenen Abschnitt (siehe Konfigurieren des Netzwerkausgangs) erklärt.

Weitere Informationen zur Arbeit mit privaten Konnektivitätsendpunkten finden Sie unter:

Konfigurieren der Netzwerkkommunikation zwischen Containern

Es gibt zwei Konzepte:

  • Kommunikation zwischen Containern einer Dienstinstanz: Wenn eine Dienstinstanz mehrere Container ausführt, können diese Container über „localhost“ miteinander kommunizieren (es ist nicht erforderlich, in der Dienstspezifikation Endpunkte zu definieren).

  • Kommunikation zwischen Containern verschiedener Dienste oder mehrerer Dienstinstanzen: Container, die zu verschiedenen Diensten (oder verschiedenen Instanzen desselben Dienstes) gehören, können über Endpunkte kommunizieren, die in Spezifikationsdateien definiert sind. Weitere Informationen dazu finden Sie unter Dienst-zu-Dienst-Kommunikation.

Übergabe von Anmeldeinformationen an einen Container mit Snowflake-Geheimnissen

Es gibt viele Gründe, warum Sie von Snowflake verwaltete Anmeldeinformationen an Ihren Container weitergeben möchten. Ihr Dienst könnte zum Beispiel mit externen Endpunkten (außerhalb von Snowflake) kommunizieren. In diesem Fall müssen Sie in Ihrem Container Anmeldeinformationen bereitstellen, die Ihr Anwendungscode verwenden kann.

Um Anmeldeinformationen bereitzustellen, speichern Sie diese zunächst in Snowflake-Geheimnis-Objekten. In der Service-Spezifikation geben Sie dann unter containers.secrets an, welche Geheimnisobjekte verwendet werden sollen und wo sie im Container platziert werden sollen. Sie können diese Anmeldeinformationen entweder an Umgebungsvariablen in den Containern übergeben oder sie in lokalen Dateien in den Containern verfügbar machen.

Snowflake-Geheimnisse angeben

Geben Sie ein Snowflake-Geheimnis durch Name oder Referenz an (die Referenz ist nur im Native Application-Szenario anwendbar):

  • Snowflake-Geheimnis per Name übergeben: Sie können einen Geheimnamen als snowflakeSecret-Feldwert übergeben.

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

    Beachten Sie, dass Sie optional <secret-name> direkt als Wert snowflakeSecret angeben können.

  • Snowflake-Geheimnis per Referenz weitergeben: Wenn Sie Snowpark Container Services verwenden, um eine Native App (eine App mit Containern) zu erstellen, verwenden der App-Produzent und die Verbraucher unterschiedliche Snowflake-Konten. In bestimmten Kontexten muss eine installierte Snowflake Native App auf bestehende Geheimnisobjekte im Verbraucherkonto zugreifen, die außerhalb des APPLICATION-Objekts existieren. In diesem Fall können Entwickler die Syntax der Spezifikation „secrets by reference“ (Geheimnisse per Referenz) verwenden, um Anmeldeinformationen wie gezeigt zu behandeln:

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

    Beachten Sie, dass die Spezifikation objectReference anstelle von objectName verwendet, um einen geheimen Referenznamen anzugeben.

Festlegen der Platzierung von Geheimnissen innerhalb des Containers

Sie können Snowflake anweisen, die Geheimnisse entweder als Umgebungsvariablen in den Containern zu platzieren oder sie in lokale Dateien der Container zu schreiben.

Übergeben Sie Geheimnisse als Variablen der Umgebung

Um Snowflake-Geheimnisse als Umgebungsvariablen an Container zu übergeben, fügen Sie envVarName in das containers.secrets-Feld ein.

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

Der secretKeyRef-Wert hängt von der Art des Snowflake-Geheimnisses ab. Mögliche Werte sind die folgenden:

  • username oder password, wenn das Snowflake-Geheimnis vom Typ password ist.

  • secret_string, wenn das Snowflake-Geheimnis vom Typ generic_string ist.

Beachten Sie, dass Snowflake die als Umgebungsvariablen übergebenen Geheimnisse nicht aktualisiert, nachdem ein Dienst erstellt wurde.

Beispiel 1: Übergeben von Geheimnissen des Typs password als Umgebungsvariable

In diesem Beispiel erstellen Sie das folgende Snowflake-Geheimnisobjekt vom Typ password:

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

Um dieses Snowflake-Geheimnisobjekt den Umgebungsvariablen (z. B. LOGIN_USER und LOGIN_PASSWORD) in Ihrem Container zur Verfügung zu stellen, fügen Sie das folgende Feld containers.secrets in die Spezifikationsdatei ein:

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

In diesem Beispiel ist der Wert snowflakeSecret ein vollständig qualifizierter Objektname, da Geheimnisse in einem anderen Schema als der zu erstellende Dienst gespeichert sein können.

Das Feld containers.secrets in diesem Beispiel ist eine Liste mit zwei snowflakeSecret-Objekten:

  • Mit dem ersten Objekt wird username im Snowflake-Geheimnisobjekt der Umgebungsvariablen LOGIN_USER in Ihrem Container zugeordnet.

  • Mit dem zweiten Objekt wird password im Snowflake-Geheimnisobjekt der Umgebungsvariablen LOGIN_PASSWORD in Ihrem Container zugeordnet.

Beispiel 2: Übergeben von Geheimnissen vom Typ generic_string als Umgebungsvariable

In diesem Beispiel erstellen Sie das folgende Snowflake-Geheimnisobjekt vom Typ generic_string:

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

Um dieses Snowflake-Geheimnisobjekt den Umgebungsvariablen (z. B. GENERIC_SECRET) in Ihrem Container zur Verfügung zu stellen, fügen Sie das folgende Feld containers.secrets in die Spezifikationsdatei ein:

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

Geheimnisse in lokale Containerdateien schreiben

Um Snowflake-Geheimnisse für Ihren Anwendungscontainer in lokalen Containerdateien verfügbar zu machen, fügen Sie ein containers.secrets-Feld ein: Um Snowflake-Geheimnisse für Ihren Anwendungscontainer in lokalen Containerdateien verfügbar zu machen, fügen Sie directoryPath in die Datei containers.secrets ein:

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

Snowflake füllt die notwendigen Dateien für das Geheimnis in diesem angegebenen directoryPath auf; die Angabe von secretKeyRef ist nicht erforderlich. Je nach Geheimnistyp erstellt Snowflake die folgenden Dateien im Container unter dem von Ihnen angegebenen Verzeichnispfad:

  • username und password, wenn das Snowflake-Geheimnis vom Typ password ist.

  • secret_string, wenn das Snowflake-Geheimnis vom Typ generic_string ist.

  • access_token, wenn das Snowflake-Geheimnis vom Typ oauth2 ist.

Bemerkung

Wenn nach dem Erstellen eines Dienstes das Snowflake-Geheimnisobjekt aktualisiert wird, aktualisiert Snowflake die entsprechenden Geheimnisdateien in den aktiven Containern.

Beispiel 1: Übergeben von Geheimnissen des Typs password mithilfe von lokalen Containerdateien

In diesem Beispiel erstellen Sie das folgende Snowflake-Geheimnisobjekt vom Typ password:

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

Um diese Anmeldeinformationen in lokalen Containerdateien zur Verfügung zu stellen, fügen Sie das folgende containers.secrets-Feld in die Spezifikationsdatei ein:

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

Wenn Sie Ihren Dienst starten, erstellt Snowflake zwei Dateien innerhalb des Containers: /usr/local/creds/username und /usr/local/creds/password. Ihr Anwendungscode kann dann diese Dateien lesen.

Beispiel 2: Übergabe von Geheimnissen vom Typ generic_string in lokalen Containerdateien

In diesem Beispiel erstellen Sie das folgende Snowflake-Geheimnisobjekt vom Typ generic_string:

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

Um dieses geheime Snowflake-Objekt in lokalen Containerdateien bereitzustellen, fügen Sie das folgende containers.secrets-Feld in die Datei mit den Spezifikationen ein:

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

Wenn Sie Ihren Dienst starten, erstellt Snowflake diese Datei in den Containern: /usr/local/creds/secret_string.

Beispiel 3: Übergeben von Geheimnissen des Typs oauth2 mithilfe von lokalen Containerdateien

In diesem Beispiel erstellen Sie das folgende Snowflake-Geheimnisobjekt vom Typ oauth2:

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

Um diese Anmeldeinformationen in lokalen Containerdateien zur Verfügung zu stellen, fügen Sie das folgende containers.secrets-Feld in die Spezifikationsdatei ein:

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

Snowflake ruft das Zugriffstoken aus dem OAuth-Geheimnisobjekt ab und erstellt /usr/local/creds/access_token in den Containern.

Wenn ein Dienst Geheimnisse des „oauth2“-Typs verwendet, wird erwartet, dass der Dienst dieses Geheimnis für den Zugriff auf ein Internetziel verwendet. Ein OAuth-Geheimnis muss von einer Integration für den externen Zugriff (EAI) erlaubt werden, da sonst CREATE SERVICE und EXECUTE JOB SERVICE fehlschlagen. Diese zusätzliche EAI-Anforderung gilt nur für Geheimnisse des „oauth2“-Typs und nicht für andere Typen von Geheimnissen.

Zusammenfassend sind folgende allgemeine Schritte zum Erstellen eines solchen Dienstes erforderlich:

  1. Erstellen Sie ein Geheimnis vom Typ „oauth2“ (siehe oben).

  2. Erstellen Sie eine EAI, um die Verwendung des Geheimnisses durch einen Dienst zu erlauben. Beispiel:

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION example_eai
      ALLOWED_NETWORK_RULES = (<name>)
      ALLOWED_AUTHENTICATION_SECRETS = (testdb.testschema.oauth_secret)
      ENABLED = true;
    
    Copy
  3. Erstellen Sie einen Dienst, der ein containers.secrets-Feld in der Spezifikation enthält. Darin wird auch die optionale Eigenschaft EXTERNAL_ACCESS_INTEGRATIONS mit einer EAI angegeben, um die Verwendung des OAuth2-Geheimnisses zuzulassen.

    Beispiel für einen CREATE SERVICE-Befehl (mit Inline-Spezifikation):

    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

Weitere Informationen zu ausgehendem Datenverkehr finden Sie unter Konfigurieren des Netzwerkausgangs.

Richtlinien und Einschränkungen

  • Allgemeine Beschränkungen: Sollten Sie Probleme mit diesen Beschränkungen haben, wenden Sie sich bitte an Ihren Kontobeauftragten.

    • Sie können bis zu 200 Dienste in Ihrem Snowflake-Konto erstellen.

    • Jeder Service kann bis zu 100 Endpunkte bereitstellen.

    • Die folgenden Beschränkungen gelten, wenn Sie den Internetzugang (siehe Konfigurieren des Netzwerkausgangs) unter Verwendung von Integrationen für den externen Zugang (EAIs) aktivieren.

    • Snowpark Container Services unterstützt ausgehende private Konnektivität sowohl auf AWS als auch auf Azure. Eingehende private Konnektivität ist in der Vorschau für AWS. Wenden Sie sich an Ihren Kundenbetreuer, wenn Sie eine eingehende private Konnektivität zu Azure benötigen.

    • Wenn Sie vom Internet aus auf den öffentlichen Endpunkt zugreifen, kann es sein, dass die Authentifizierung mit Benutzername und Kennwort funktioniert, aber SSO zu einer leeren Seite oder dem Fehler führt: „OAuth Clientintegration mit der angegebenen Client-ID wurde nicht gefunden.“ Informationen zum Umgang mit diesem Problem finden Sie unter Überlegungen zum Zugriff und SSO.

  • Anforderungen an Plattformimages: Snowpark Container Services benötigt derzeit Images der linux/amd64-Plattform.

  • Dienstcontainer haben keine Berechtigungen: Dienstcontainer werden derzeit ohne weitreichende Berechtigungen ausgeführt, d. h. sie können die Konfiguration der Hardware auf dem Host nicht ändern und können BS-Konfigurationen nur begrenzt ändern. Dienstcontainer können nur Betriebssystemkonfigurationen ausführen, die auch ein normaler Benutzer (d. h. ein Benutzer, der keine Root-Berechtigung benötigt) ausführen kann.

  • Umbenennen von Datenbank und Schema:

    • Benennen Sie keine Datenbanken und Schemas um, für die Sie bereits einen Dienst erstellt haben. Das Umbenennen bedeutet im Grunde, dass ein Dienst in eine andere Datenbank und ein anderes Schema verschoben wird, was nicht unterstützt wird. Beispiel:

      • Der DNS-Name des Dienstes wird weiterhin den alten Datenbank- und Schemanamen verwenden.

      • Datenbank- und Schemainformationen, die Snowflake den aktiven Dienstcontainern zur Verfügung stellt, beziehen sich weiterhin auf die alten Namen.

      • Neue Protokolleinträge, die von Diensten in die Ereignistabelle aufgenommen werden, beziehen sich weiterhin auf die alten Datenbank- und Schemanamen.

      • Die Dienstfunktion wird weiterhin auf den Dienst in der alten Datenbank und dem alten Schema verweisen, und wenn Sie die Dienstfunktion aufrufen, wird sie fehlschlagen.

    • Eine Dienstspezifikation kann auf Objekte wie Snowflake-Stagingbereiche und Image-Repositorys verweisen. Wenn Sie den Namen von Datenbank oder Schema umbenennen, in denen sich diese Objekte befinden, müssen Sie die Datenbank- und Schemanamen der referenzierten Objekte in der Dienstspezifikation manuell aktualisieren.

  • Löschen und Wiederherstellen von Datenbank und Schema:

    • Wenn Sie die übergeordnete Datenbank oder das übergeordnete Schema löschen, werden die Dienste asynchron gelöscht. Das bedeutet, dass ein Dienst noch einige Zeit weiter ausgeführt wird, bevor er durch interne Prozesse entfernt wird.

    • Wenn Sie versuchen, eine zuvor gelöschte Datenbank oder ein Schema wiederherzustellen, gibt es keine Garantie, dass die Dienste wiederhergestellt werden.

  • Übertragen der Eigentümerschaft: Das Übertragen der Eigentümerschaft von Diensten (einschließlich Jobdiensten) wird nicht unterstützt.

  • Replikation: Bei der Replikation in Snowflake ist Folgendes zu beachten:

    • Snowpark Container Services-Objekte wie Dienste, Computepools und Repositorys können nicht repliziert werden.

    • Wenn Sie ein Repository innerhalb einer Datenbank erstellen, kann nicht die gesamte Datenbank repliziert werden. In Fällen, in denen die Datenbank andere Ressourcen enthält, wie z. B. Dienste oder Computepools, wird der Replikationsprozess der Datenbank erfolgreich sein, aber diese einzelnen Objekte innerhalb der Datenbank werden nicht repliziert.

  • Timeout von Jobdiensten: Snowpark Container Services-Jobdienste werden synchron ausgeführt. Wenn eine Anweisung ein Zeitlimit überschreitet, wird der Jobdienst abgebrochen. Das Standard-Timeout für Anweisungen beträgt zwei Tage. Kunden können den Timeout-Wert ändern, indem sie den Parameter STATEMENT_TIMEOUT_IN_SECONDS mit ALTER SESSION einstellen.

    ALTER SESSION SET statement_timeout_in_seconds=<time>
    
    Copy

    Stellen Sie ihn ein, bevor Sie den Befehl EXECUTE JOB SERVICE ausführen.