Snowpark Container Services: Zusätzliche Hinweise zu Diensten und Jobs

Wichtig

Das Job-Feature von Snowpark Container Services befindet sich derzeit in der privaten Vorschau und unterliegt den Nutzungsbedingungen für Vorschau-Features unter https://snowflake.com/legal. Weitere Informationen dazu erhalten Sie bei Ihrem Snowflake-Ansprechpartner.

Verbinden mit Snowflake aus einem Container heraus

Wenn Sie einen Dienst oder Job 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 angegebenen Anmeldeinformationen authentifizieren sich als Dienstrolle. Snowflake stellt einige der Informationen als Umgebungsvariablen in Ihren Containern bereit.

Jedes Objekt in Snowflake hat eine Eigentümerrolle. Im Falle eines Dienstes oder Jobs hat Snowflake ein Konzept, das als Dienstrolle bezeichnet wird (dieser Begriff gilt sowohl für Dienste als auch für Jobs). Die Dienstrolle 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

In der derzeitigen Implementierung ist die Dienstrolle mit der Eigentümerrolle identisch.

So erstellen Sie beispielsweise die Rolle test_role als Teil der grundlegenden Einrichtung für die Tutorials. Sie erteilen der Rolle die erforderlichen Berechtigungen und verwenden die Rolle dann beim Erstellen eines Dienstes und Jobs. Diese Rolle ist sowohl die Eigentümerrolle des Dienstes oder Jobs als auch die Dienstrolle, die die Berechtigungen des Dienstes oder Jobs bestimmt.

Bemerkung

Dienstrollen können keine der Rollen mit weitreichenden Berechtigungen wie ACCOUNTADMIN, SECURITYADMIN und ORGADMIN sein.

Wenn Sie einen Dienst erstellen, erstellt Snowflake auch einen „Dienstbenutzer“ für diesen Dienst. Wenn der Dienst eine Abfrage ausführt, führt er die Abfrage als der Dienstbenutzer aus. Was der Dienstbenutzer tun kann, wird durch die Dienstrolle bestimmt.

Verbinden mit Snowflake

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

  • SNOWFLAKE_ACCOUNT: Gibt den Namen des Snowflake-Kontos an, unter dem der Dienst derzeit ausgeführt wird.

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

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 Dienstrolle 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 Ausgehender Netzwerk-Datenverkehr.

    • 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/Job 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 die folgende Logik, um die Datenbank und das Schema zu bestimmen, in denen ein Dienst/Job erstellt werden soll:

  • Bei einem Dienst verwendet Snowflake den im Befehl CREATE SERVICE angegebenen Dienstnamen, um den Datenbank- und Schemakontext für den Dienst zu ermitteln:

    • Beispiel 1: Der folgende Befehl CREATE SERVICE spezifiziert test_service als den Dienstnamen:

      CREATE SERVICE test_service IN COMPUTE POOL ...
      
      Copy

      Snowflake platziert diesen Dienst in der aktuellen Datenbank und im aktuellen Schema.

    • Beispiel 2: Der folgende Befehl CREATE SERVICE spezifiziert einen vollqualifizierten Dienstnamen:

      CREATE SERVICE test_db.test_schema.test_service IN COMPUTE POOL ...
      
      Copy

      Snowflake platziert den Dienst in der angegebenen Datenbank (test_db) und dem angegebenen Schema (test_schema), unabhängig vom aktuellen Schema.

  • Bei einem Job geben Sie beim Erstellen des Jobs mit dem Befehl EXECUTE SERVICE keinen Jobnamen an:

    EXECUTE SERVICE IN COMPUTE POOL ..
    
    Copy

    In diesem Fall haben Sie keine Möglichkeit, den Job irgendwo zu platzieren. Daher platziert Snowflake den Job in der aktuellen Datenbank und im aktuellen Schema. Wenn Sie möchten, dass ein Job SQL-Anweisungen in verschiedenen Schemas ausführt, können Sie den Job in verschiedenen Schemakontexten ausführen. Beispiel:

    USE ROLE test_role;
    USE DATABASE tutorial_db;
    
    USE SCHEMA schema1;
    -- Execute using tutorial_db and schema1
    EXECUTE SERVICE IN COMPUTE POOL ...
    
    USE SCHEMA schema2;
    -- execute service again, using schema2
    EXECUTE SERVICE IN COMPUTE POOL ...
    
    Copy

Wenn Snowflake einen Dienst/Job 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-Job, 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 Job erstellt haben (durch Ausführen von EXECUTE 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

    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 (oder Job) 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 Standardwarehouses angeben. Geben Sie den optionalen Parameter QUERY_WAREHOUSE im Befehl CREATE SERVICE an, um ein Standard-Warehouse anzugeben. 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 Dienst-/Jobcontainer 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/Job 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/Jobs gültig. Sie können das OAuth-Token nicht kopieren und außerhalb des Dienstes/Jobs verwenden.

  • Unter Verwendung des OAuth-Tokens verbinden sich die Container mit Snowflake als Benutzer und Dienst-/Jobrolle wie folgt:

    • Der Benutzer ist die Person, die den Dienst/Job erstellt hat.

    • Die Rolle ist die Dienstrolle für den Dienst/Job, und dies ist die einzige unterstützte Rolle. Sie können die Rolle nicht ändern.

  • 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/Jobs 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.

Konfigurieren der Netzwerkeigenschaften

In den folgenden Abschnitten wird erläutert, wie Sie die Netzwerkeigenschaften (eingehender/ausgehender Datenverkehr) für Ihren Dienst und Job konfigurieren.

Eingehender Netzwerk-Datenverkehr

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 Rolle, die den Dienst (mit einem öffentlichen Endpunkt) erstellt, 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 Jobs, 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.

Dienste haben standardmäßig keine Berechtigung für den Zugriff auf das Internet. Der Browser sollte auch verhindern, dass die Clientanwendung auf das Internet zugreift und möglicherweise Daten freigibt. Wenn Sie eine Integration des externen Zugriffs (EAI) eingerichtet haben, um Ihrem Dienst den Zugriff auf example.com zu ermöglichen (siehe Ausgehender Netzwerk-Datenverkehr), 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. 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' http: https: blob: data:; object-src 'none'; connect-src 'self' http: https: wss:; 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 (Ausgehender Netzwerk-Datenverkehr) 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.

Ausgehender Netzwerk-Datenverkehr

Der Code Ihrer Anwendung (Job oder Dienst) 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 Jobs und Diensten erlaubten externen Zugriff zu verwalten. Kontoadministratoren können dann die EAI-Nutzung bestimmten Rollen erlauben, mit denen Entwickler dann Jobs oder Diensten ausführen können.

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 Job oder Dienst erstellen, um Anforderungen an bestimmte Internetziele zuzulassen.

Beispiel

Angenommen, Sie möchten, dass Ihr Anwendungscode (Job oder Dienst) 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 Job oder 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 Job oder 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 Job/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 oder einen Job durch Angabe der EAI wie in den folgenden Beispielen gezeigt. Die Rolle, die den Dienst oder Job erstellt, benötigt die Nutzungsberechtigung (USAGE) für die EAI und die Leseberechtigung (READ) für die referenzierten Geheimnisse. Beachten Sie, dass Sie mit der Rolle ACCOUNTADMIN keine Dienste oder Jobs erstellen können.

    • Erstellen Sie einen Dienst:

      USE ROLE test_role;
      
      CREATE SERVICE eai_service
        IN COMPUTE POOL MYPOOL
        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
        $$
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION);
      
      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.

    • Erstellen Sie einen Job:

      EXECUTE SERVICE
        IN COMPUTE POOL tt_cp
        FROM SPECIFICATION $$
        spec:
          container:
          - name: curl
            image: /tutorial_db/data_schema/tutorial_repo/alpine-curl:latest
            command:
            - "curl"
            - "http://google.com/"
        $$
        EXTERNAL_ACCESS_INTEGRATIONS = (GOOGLE_APIS_ACCESS_INTEGRATION);
      
      Copy

      Dieser EXECUTE 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.

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/Jobs 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.

Verwenden von Snowflake-Geheimnissen zur Übergabe von Anmeldeinformationen an einen Container

Wenn Ihr Dienst oder Job mit externen Endpunkten (außerhalb von Snowflake) kommuniziert, müssen Sie in Ihrem Container Anmeldeinformationen bereitstellen, die Ihr Anwendungscode verwenden kann. Speichern Sie dazu zunächst Ihre Anmeldeinformationen in Snowflake-Geheimnisobjekten. Als Nächstes fügen Sie in der Dienst- oder Jobspezifikationsdatei das Feld containers.secrets ein, um diese Geheimnisse an die Container zu übergeben.

Sie können diese Anmeldeinformationen entweder an Umgebungsvariablen in den Containern übergeben oder sie in lokalen Dateien in den Containern verfügbar machen. Je nachdem, welche Option Sie wählen, bietet die Spezifikationsdatei Konstrukte, die in den folgenden Abschnitten erläutert werden.

Übergeben von Geheimnissen als Umgebungsvariablen

Um Snowflake-Geheimnisse für Container als Umgebungsvariablen zu übergeben, fügen Sie ein containers.secrets-Feld ein:

containers:
- name: main
  image: <url>
  secrets:
  - snowflakeSecret: <snowflake-secret-name>
    secretKeyRef: <secret-key-reference>
    envVarName: <env-variable-name>
Copy

secretKeyRef: Dieser Wert hängt vom Typ des Snowflake-Geheimnisses ab. Mögliche Werte:

  • username oder 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

Geheimnisse, die als Umgebungsvariablen übergeben werden, können nicht mehr aktualisiert werden, nachdem ein Dienst (oder Job) 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

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

Anmerkung zum Übergeben von Geheimnissen des Typs oauth2 an Umgebungsvariablen

Dies ist kein sinnvolles Szenario, denn wenn OAuth-Token ablaufen, muss ein neues Token an den Container übergeben werden. Aber Geheimnisse, die als Umgebungsvariablen übergeben werden, können nicht aktualisiert werden. Daher sollten Sie keine Geheimnisse vom Typ „oauth2“ als Umgebungsvariablen übergeben.

Übergeben von Geheimnissen mithilfe von lokalen Containerdateien

Um Snowflake-Geheimnisse für Ihren Anwendungscontainer in lokalen Containerdateien zur Verfügung zu stellen, fügen Sie ein containers.secrets-Feld ein:

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

directoryPath: Snowflake erstellt für jeden Geheimnisschlüssel im angegebenen Verzeichnis eine Datei, wobei die Angabe von secretKeyRef nicht erforderlich ist.

Bemerkung

Wenn nach dem Erstellen eines Dienstes (oder Jobs) 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 oder Job starten, erstellt Snowflake zwei Dateien innerhalb der Container: /usr/local/creds/username und /usr/local/creds/password. Ihr Anwendungscode kann dann diese Dateien lesen.

Beispiel 2: Ü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 Job oder Dienst Geheimnisse des „oauth2“-Typs verwendet, wird erwartet, dass der Dienst oder Job dieses Geheimnis für den Zugriff auf ein Internetziel verwendet. Ein OAuth-Geheimnis muss von einer Integration für den externe Zugriff (EAI) erlaubt werden, da sonst CREATE SERVICE und EXECUTE 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 oder einen Job 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 oder Job, 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
      FROM SPECIFICATION
      $$
      spec:
        containers:
          - name: main
            image: <url>
            secrets:
            - snowflakeSecret: testdb.testschema.oauth_secret
              directoryPath: '/usr/local/creds'
        endpoints:
          - name: api
            port: 8080
      $$
      EXTERNAL_ACCESS_INTEGRATIONS = (example_eai);
    
    Copy

Weitere Informationen zu ausgehendem Datenverkehr finden Sie unter Ausgehender Netzwerk-Datenverkehr.

Richtlinien und Einschränkungen

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

  • Dienst-/Jobcontainer haben keine Berechtigungen: Dienst-/Jobcontainer 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. Dienst-/Jobcontainer 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 und Jobs wird nicht unterstützt.

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

    • Snowpark Container Services-Objekte wie Dienste, Jobs, 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, Jobs oder Computepools, wird der Replikationsprozess der Datenbank erfolgreich sein, aber diese einzelnen Objekte innerhalb der Datenbank werden nicht repliziert.

  • Timeout von Jobs: Snowpark Container Services-Jobs werden synchron ausgeführt. Wenn eine Anweisung ein Zeitlimit überschreitet, wird der Job 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 SERVICE ausführen.