Snowpark Container Services: considerações adicionais sobre serviços

Conexão ao Snowflake de dentro de um contêiner

Quando você inicia um serviço (incluindo serviços de trabalho), o Snowflake fornece credenciais para os contêineres em execução, permitindo que o código do contêiner use drivers para se conectar ao Snowflake e executar SQL (semelhante a qualquer outro código no seu computador conectado ao Snowflake). As credenciais fornecidas são autenticadas como a função do proprietário (a função que criou o serviço). Snowflake fornece algumas informações como variáveis de ambiente em seus contêineres.

Cada objeto no Snowflake tem uma função de proprietário. A função de proprietário do serviço determina quais recursos seu serviço pode executar ao interagir com o Snowflake. Isso inclui a execução de SQL, acesso a estágios e rede serviço a serviço.

Nota

Uma função de proprietário do serviço refere-se à função que criou o serviço. Você também pode definir uma ou mais funções de serviço para gerenciar o acesso aos pontos de extremidade que o serviço expõe. Para obter mais informações, consulte Gerenciamento do acesso aos pontos de extremidade do servidor.

Quando você cria um serviço, o Snowflake também cria um usuário de serviço específico para esse serviço. Quando o serviço executa uma consulta, ele a executa como o usuário do serviço, usando a função de proprietário do serviço. O que o usuário do serviço pode fazer é determinado por essa função de proprietário.

A função de proprietário do serviço não pode ser nenhuma das funções privilegiadas, como ACCOUNTADMIN e SECURITYADMIN. Isso serve para limitar o que um serviço com mau comportamento pode fazer, exigindo que os clientes sejam mais intencionais para permitir que um serviço execute operações administrativas.

Para visualizar as consultas emitidas por um usuário de serviço específico, você pode usar a função ACCOUNTADMIN para visualizar o histórico de consultas. O nome de usuário do usuário de serviço aparece nos seguintes formatos:

  • Para um serviço criado antes do lançamento do servidor 8.35, o nome de usuário do serviço tem o formato SF$SERVICE$unique-id.

  • Para um serviço criado após o lançamento do servidor 8.35, o nome de usuário do serviço é o mesmo que o nome do serviço.

Conexão ao Snowflake

Snowflake fornece as seguintes variáveis de ambiente para você configurar um cliente Snowflake em seu código de serviço:

  • SNOWFLAKE_ACCOUNT: Fornece o localizador de conta para a conta Snowflake na qual o serviço está sendo executado no momento.

  • SNOWFLAKE_HOST: fornece o nome do host usado para conectar-se ao Snowflake.

Snowflake também fornece um token OAuth no contêiner em um arquivo chamado /snowflake/session/token. Ao criar uma conexão, você fornece esse token ao conector.

Ao criar uma conexão com o Snowflake a partir de um contêiner, você deve usar SNOWFLAKE_HOST, SNOWFLAKE_ACCOUNT e o token OAuth. Você não pode usar o token OAuth sem usar também SNOWFLAKE_HOST e não pode usar o token OAuth fora do Snowpark Container Services. Para obter mais informações, consulte Como usar um token OAuth para executar SQL.

Nota

Usar integrações de acesso externo para acessar o Snowflake pode significar enviar informações potencialmente confidenciais pela Internet. Sempre que possível, os serviços devem usar o token OAuth fornecido para acessar o nome de host SNOWFLAKE_HOST. Isso evita a necessidade de acessar o Snowflake pela Internet.

Para obter exemplos de código usando vários drivers Snowflake, consulte Exemplos de conexão do Snowflake.

Exemplos

  • No Tutorial 2 (consulte main.py), o código lê as variáveis de ambiente da seguinte maneira:

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

    O código passa essas variáveis para um código de criação de conexão para o cliente Snowflake de sua escolha. O contêiner usa essas credenciais para criar uma nova sessão, com a função de proprietário como função principal, para executar consultas. O código de exemplo a seguir é o mínimo necessário para criar uma conexão Snowflake em Python:

    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
  • Quando você usa o host padrão (ou seja, você não inclui o argumento host ao criar uma conexão), há suporte para conexão ao Snowflake usando outras formas de autenticação (como nome de usuário e senha). Por exemplo, a conexão a seguir especifica o nome de usuário e a senha para autenticação:

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

    O uso de um host padrão requer integração de acesso externo com uma regra de rede que permite o acesso do seu serviço ao nome de host Snowflake da sua conta. Por exemplo, se o nome da sua conta for MyAccount, o nome do host será myaccount.snowflakecomputing.com. Para obter mais informações, consulte Configuração da saída da rede.

    • Crie uma regra de rede que corresponda ao nome de host da Snowflake API da sua conta:

      CREATE OR REPLACE NETWORK RULE snowflake_egress_access
        MODE = EGRESS
        TYPE = HOST_PORT
        VALUE_LIST = ('myaccount.snowflakecomputing.com');
      
      Copy
    • Crie uma integração usando a regra de rede anterior:

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

Configuração do banco de dados e o contexto do esquema para execução de SQL

Esta seção explica dois conceitos:

  • A lógica que o Snowflake usa para determinar o banco de dados e o esquema no qual criar seu serviço.

  • O método pelo qual o Snowflake transmite essas informações aos seus contêineres, permitindo assim que o código do contêiner execute SQL no mesmo banco de dados e contexto de esquema.

O Snowflake usa o nome do serviço para determinar o banco de dados e o esquema no qual criar um serviço:

  • Exemplo 1: nos seguintes comandos CREATE SERVICE e EXECUTE JOB SERVICE, o nome do serviço não especifica explicitamente um nome de banco de dados e esquema. O Snowflake cria o serviço e o serviço de trabalho no banco de dados e esquema atuais.

    -- 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
  • Exemplo 2: nos seguintes comandos CREATE SERVICE e EXECUTE JOB SERVICE, o nome do serviço inclui um nome de banco de dados e esquema. Snowflake cria o serviço e serviço do trabalho no banco de dados (test_db) e esquema (test_schema) especificados, independentemente do esquema atual.

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

Quando o Snowflake inicia um serviço, ele fornece informações de banco de dados e esquema para os contêineres em execução usando as seguintes variáveis de ambiente:

  • SNOWFLAKE_DATABASE

  • SNOWFLAKE_SCHEMA

O código do contêiner pode usar variáveis de ambiente no código de conexão para determinar qual banco de dados e esquema usar, conforme mostrado neste exemplo:

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

Exemplo

No Tutorial 2, você cria um serviço de trabalho do Snowflake que se conecta ao Snowflake e executa instruções SQL. As etapas a seguir resumem como o código do tutorial usa as variáveis de ambiente:

  1. Na configuração comum (consulte a seção Configuração comum), você cria recursos, incluindo um banco de dados e um esquema. Você também define o banco de dados e o esquema atuais para a sessão:

    USE DATABASE tutorial_db;
    ...
    USE SCHEMA data_schema;
    
    Copy
  2. Depois de criar um serviço de trabalho (executando EXECUTE JOB SERVICE), o Snowflake inicia o contêiner e define as seguintes variáveis de ambiente no contêiner para o banco de dados e o esquema atuais da sessão:

    • SNOWFLAKE_DATABASE é definido como “TUTORIAL_DB”

    • SNOWFLAKE_SCHEMA é definido como “DATA_SCHEMA”

  3. O código do trabalho (consulte main.py no Tutorial 2) lê estas variáveis de ambiente:

    SNOWFLAKE_DATABASE = os.getenv('SNOWFLAKE_DATABASE')
    SNOWFLAKE_SCHEMA = os.getenv('SNOWFLAKE_SCHEMA')
    
    Copy
  4. O código do trabalho define o banco de dados e o esquema como o contexto no qual executar as instruções SQL (função run_job() em main.py):

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

    Nota

    SNOWFLAKE_ACCOUNT, SNOWFLAKE_HOST, SNOWFLAKE_DATABASE, SNOWFLAKE_SCHEMA são variáveis de ambiente que o Snowflake gera para o contêiner do aplicativo, mas SNOWFLAKE_WAREHOUSE não é (o código do aplicativo do Tutorial 2 criou essa variável porque o Snowflake não passa um nome de warehouse para um contêiner).

Como especificar o warehouse para seu contêiner

Se seu serviço se conectar ao Snowflake para executar uma consulta em um warehouse do Snowflake, você terá as seguintes opções para especificar um warehouse:

  • Especifique um warehouse no código do seu aplicativo. Especifique um warehouse como parte da configuração da conexão ao iniciar uma sessão do Snowflake para executar consultas no seu código. Para obter um exemplo, consulte Tutorial 2.

  • Especifique um warehouse padrão ao criar um serviço. Especifique o parâmetro opcional QUERY_WAREHOUSE no comando CREATE SERVICE (ou EXECUTE JOB SERVICE) para fornecer um warehouse padrão. Se o código do seu aplicativo não fornecer um warehouse como parte da configuração da conexão, o Snowflake usará o warehouse padrão. Use o comando ALTER SERVICE para mudar o warehouse padrão.

Se você especificar um warehouse usando ambos os métodos, o warehouse especificado no código do aplicativo será usado.

Como usar um token OAuth para executar SQL

Todos os clientes fornecidos pelo Snowflake oferecem suporte a OAuth como forma de autenticação. Os contêineres de serviço também usam o mecanismo OAuth para autenticação com Snowflake. Por exemplo, quando um contêiner deseja executar SQL, o contêiner cria uma conexão com o Snowflake, semelhante a qualquer outro cliente Snowflake:

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

Quando você cria um serviço, o Snowflake executa os contêineres e fornece um token Oauth para os contêineres usarem no seguinte local dentro do contêiner: /snowflake/session/token.

Observe os seguintes detalhes sobre este token OAuth:

  • Você deve ler o conteúdo do arquivo /snowflake/session/token imediatamente antes de usá-lo porque o conteúdo expira em 10 minutos e o Snowflake atualiza esse arquivo a cada poucos minutos. Depois que um contêiner se conecta ao Snowflake com êxito, o tempo de expiração não se aplica à conexão (como acontece com qualquer sessão criada diretamente pelos usuários).

  • Este token OAuth é válido apenas no serviço específico do Snowflake. Você não pode copiar o token OAuth e usá-lo fora do serviço.

  • Usando o token OAuth, os contêineres se conectam ao Snowflake como o usuário do serviço e usam a função de proprietário do serviço.

  • Usar o token OAuth para se conectar criará uma nova sessão. O token OAuth não está associado a nenhuma sessão SQL existente.

    Nota

    Uma diferença significativa entre a execução de procedimentos armazenados e a execução de um serviço é que os procedimentos armazenados são executados na mesma sessão que o SQL que os executa. Mas toda vez que um contêiner estabelece uma nova conexão, você cria uma nova sessão.

Conexão ao Snowflake de dentro de um contêiner usando os direitos do chamador

Os contêineres executam consultas conectando-se ao Snowflake como o usuário do serviço e usando a função de proprietário do serviço que concede privilégios ao serviço. Em determinados cenários de aplicativos, talvez seja necessário executar consultas usando o contexto do usuário final em vez do usuário do serviço. O recurso de direito do chamador é usado nesse contexto.

Por exemplo, suponha que você crie um serviço que exponha um ponto de extremidade público para fornecer um aplicativo da Web que exiba um painel usando dados armazenados no Snowflake. Você concede a outros usuários da sua conta Snowflake acesso ao painel (concedendo a função de serviço a esses usuários). Quando qualquer um desses usuários finais fizer login no painel, você deseja que o painel exiba apenas os dados aos quais o usuário tem acesso.

No entanto, como os contêineres, por padrão, executam consultas usando o usuário do serviço e a função de proprietário do serviço, o painel mostra os dados aos quais a função de proprietário do serviço tem acesso, independentemente do usuário final conectado ao ponto de extremidade. Como resultado, os dados no painel do usuário não estão limitados ao que o usuário final tem acesso, o que permite que o usuário acesse dados que não deveriam ter permissão para acessar.

Para limitar o painel para mostrar apenas os dados acessíveis ao usuário conectado, os contêineres de aplicativos precisam executar SQL usando privilégios concedidos ao usuário final. Você pode ativar isso usando os direitos do chamador no aplicativo.

Nota

  • O recurso de direitos do chamador é suportado somente quando acessa um serviço usando o ingresso na rede. O recurso não está disponível ao usar uma função de serviço para acessar o serviço.

  • No momento, o recurso de direitos do chamador não é compatível com Snowflake Native App (aplicativos com contêineres).

Configuração dos direitos do chamador para seu serviço

A configuração dos direitos do chamador para seu aplicativo é um processo de duas etapas.

  1. Defina executeAsCaller como true na especificação de serviço, conforme mostrado no fragmento de especificação a seguir:

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

    Isso informa explicitamente ao Snowflake que o aplicativo pretende usar os direitos do chamador e faz com que o Snowflake insira o cabeçalho Sf-Context-Current-User-Token em todas as solicitações de entrada antes de enviar a solicitação ao contêiner do aplicativo. Esse token de usuário facilita a execução da consulta como o usuário chamador. Se não for especificado, o padrão é executeAsCaller para false.

    A especificação da opção executeAsCaller não afeta a capacidade do serviço de executar consultas como o usuário do serviço e a função de proprietário do serviço. Com o executeAsCaller ativado, o serviço tem a opção de se conectar ao Snowflake como usuário chamador e como usuário de serviço.

  2. Atualize seu código de aplicativo. Para estabelecer uma conexão com o Snowflake em nome do usuário chamador, atualize seu código para criar um token de login que inclua o token OAuth que o Snowflake forneceu ao serviço e o token de usuário do cabeçalho Sf-Context-Current-User-Token. O token de login deve seguir este formato: <service-oauth-token>.<Sf-Context-Current-User-Token>.

    Isso é demonstrado no fragmento de código Python a seguir:

    # 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

No exemplo acima:

  • A função get_login_token lê o arquivo em que o Snowflake copiou o token OAuth para ser usado pelo contêiner.

  • A função get_connection_params cria um token concatenando o token OAuth e o token de usuário do cabeçalho Sf-Context-Current-User-Token. A função inclui esse token em um dicionário de parâmetros que o aplicativo usa para se conectar ao Snowflake.

Para obter um exemplo com instruções passo a passo, consulte Criação de um serviço com os direitos do chamador ativados.

Acesso a um serviço com direitos de chamador configurados

A configuração dos direitos do chamador diz respeito ao seu serviço estabelecendo uma conexão Snowflake em nome do chamador. O modo como você faz login nos pontos de extremidade de entrada do serviço (programaticamente ou usando um navegador) permanece o mesmo. Após o login, aplica-se o seguinte:

  • Acesso a um ponto de extremidade público usando um navegador: depois que o usuário fizer login em um ponto de extremidade, o serviço estabelecerá uma conexão com o Snowflake em nome do usuário chamador usando a função padrão do usuário. Se não houver uma função padrão configurada para o usuário, será usada a função PUBLIC.

  • Acesso a um ponto de extremidade público de forma programática: ao fazer login em um ponto de extremidade programaticamente usando o token JWT, você pode, opcionalmente, definir o parâmetro scope para especificar a função a ser ativada

Atualmente, depois que um serviço estabelece a conexão de direitos de um chamador com o Snowflake em nome do chamador, não há suporte para a troca de funções. Se o seu aplicativo precisar usar funções diferentes para acessar objetos diferentes, configure o usuário para ter todas as funções secundárias ativas por padrão. Para fazer isso, use o comando ALTER USER para definir a propriedade DEFAULT_SECONDARY_ROLES do usuário como (“ALL”):

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

Gerenciamento de concessões do chamador para um serviço

Quando um serviço cria uma sessão de direitos do chamador, a sessão opera como o usuário chamador (não como o usuário do serviço). Quando uma operação é realizada usando essa sessão, o Snowflake aplica duas verificações de permissões:

  1. A primeira verificação de permissões é como se o usuário tivesse criado a sessão diretamente. Essas são as verificações normais de permissão que o Snowflake realiza para o usuário.

  2. A segunda verificação de permissões verifica se o serviço tem permissão para executar a operação em nome de um usuário. O Snowflake verifica isso garantindo que a função proprietária do serviço tenha recebido as concessões de chamador necessárias.

Em uma sessão de direitos do chamador, tanto a verificação de permissão normal quanto a verificação da função proprietária do serviço devem permitir a operação; isso é chamado de direitos restritos do chamador. Por padrão, o serviço não tem permissão para fazer nada em nome de um usuário. Você deve conceder explicitamente concessões de chamador ao serviço para que ele possa ser executado com os privilégios do chamador.

Por exemplo, suponha que um usuário U1 use uma função R1, que tem o privilégio SELECT na tabela T1. Quando U1 faz login no ponto de extremidade público do seu serviço (example_service), que está configurado para usar os direitos do chamador, o serviço estabelece uma conexão com a Snowflake em nome de U1.

Para permitir que o serviço consulte a tabela T1 em nome de U1, você precisa conceder à função de proprietário do serviço os seguintes privilégios:

  1. Privilégios para resolver o nome da tabela, concedendo uma concessão ao chamador que permita que o serviço seja executado com o privilégio USAGE no banco de dados e no esquema dessa tabela.

  2. Privilégios para usar um warehouse para executar consultas, concedendo uma concessão ao chamador que permite que o serviço seja executado com o privilégio USAGE em um warehouse.

  3. Privilégios para consultar a tabela concedendo uma concessão de chamador que permite que o serviço seja executado com o privilégio SELECT na tabela T1.

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

Qualquer função em sua conta que tenha o privilégio global MANAGE CALLER GRANT pode conceder concessões de chamador. Para obter mais informações sobre as concessões do chamador, consulte GRANT CALLER e Direitos restritos do chamador.

Exemplo

É fornecido um exemplo de um serviço que usa o recurso de direitos do chamador ao executar consultas SQL em nome dos usuários. Para obter mais informações, consulte Criação de um serviço com os direitos do chamador ativados.

Configuração do ingresso na rede

Para permitir que qualquer coisa interaja com seu serviço pela internet, você declara as portas de rede nas quais seu serviço está escutando como pontos de extremidade no arquivo de especificação de serviço. Esses pontos de extremidade controlam a entrada.

Por padrão, os pontos de extremidade de serviço são privados. Somente funções de serviço e comunicações serviço a serviço podem fazer solicitações aos pontos de extremidade privados. Você pode declarar um ponto de extremidade como público para permitir solicitações a um ponto de extremidade da internet. A função de proprietário do serviço deve ter o privilégio BIND SERVICE ENDPOINT na conta:

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

Para obter um exemplo, consulte Tutorial 1.

Nota

Atualmente, apenas serviços, não serviços de trabalho, oferecem suporte à entrada de rede.

Entrada e segurança de aplicativos da web

Você pode criar um serviço Snowpark Container Services para hospedagem na web usando o suporte do ponto de extremidade público (entrada de rede). Para maior segurança, Snowflake emprega um serviço de proxy para monitorar solicitações recebidas de clientes para o seu serviço e respostas de saída do seu serviço para os clientes. Esta seção explica o que o proxy faz e como ele afeta um serviço implantado no Snowpark Container Services.

Nota

Ao testar um serviço localmente, você não está usando o proxy Snowflake e, portanto, haverá diferenças entre sua experiência ao executar um serviço localmente e quando implantado no Snowpark Container Services. Revise esta seção e atualize sua configuração local para melhores testes.

Por exemplo:

  • O proxy não encaminha uma solicitação HTTP recebida se a solicitação usar um método HTTP banido.

  • O proxy envia uma resposta 403 ao cliente se o cabeçalho Content-Type na resposta indicar que a resposta contém um executável.

Além disso, o proxy também pode injetar novos cabeçalhos e alterar os cabeçalhos existentes na solicitação e na resposta, tendo em mente o seu contêiner e a segurança de dados.

Por exemplo, ao receber uma solicitação, seu serviço pode enviar HTML, JavaScript, CSS e outros conteúdos de uma página da Web para o navegador do cliente na resposta. A página da web no navegador faz parte do seu serviço, atuando como interface do usuário. Por motivos de segurança, se o seu serviço tiver restrições (como uma restrição ao estabelecimento de conexões de rede com outros sites), você também poderá querer que a página da Web do seu serviço tenha as mesmas restrições.

Por padrão, os serviços têm permissões limitadas para acessar a Internet. O navegador também deve restringir o acesso do aplicativo cliente à Internet e o possível compartilhamento de dados na maioria dos casos. Se você configurar uma integração de acesso externo (EAI) para permitir que seu serviço acesse example.com (consulte Configuração da saída da rede), a página da Web do seu serviço também deverá poder acessar example.com por meio de seu navegador.

O proxy Snowflake aplica as mesmas restrições de rede ao serviço e à página da web adicionando um cabeçalho Content-Security-Policy (CSP) na resposta. Por padrão, o proxy adiciona uma linha de base CSP na resposta para proteção contra ameaças de segurança comuns. A segurança do navegador é um esforço máximo para equilibrar funcionalidade e segurança. É uma responsabilidade compartilhada para garantir que essa linha de base seja apropriada para seu caso de uso. Além disso, se o seu serviço estiver configurado para usar um EAI, o proxy aplicará as mesmas regras de rede de EAI a CSP para a página da web. Este CSP permite que a página da web no navegador acesse os mesmos sites que o serviço pode acessar.

As seções a seguir explicam como o proxy Snowflake lida com solicitações de entrada para o seu serviço e modifica as respostas de saída do seu serviço para os clientes.

Solicitações recebidas no serviço

Quando chega uma solicitação, o proxy faz o seguinte antes de encaminhar a solicitação ao serviço:

  • Solicitações recebidas com métodos HTTP banidos: se uma solicitação HTTP recebida usar qualquer um dos métodos HTTP banidos a seguir, o proxy não encaminhará a solicitação para seu serviço:

    • TRACE

    • OPTIONS

    • CONNECT

Respostas enviadas aos clientes

O proxy Snowflake aplica essas modificações à resposta enviada pelo seu serviço antes de encaminhar a resposta ao cliente.

  • Limpeza de cabeçalho: o proxy Snowflake remove esses cabeçalhos de resposta, se presentes:

    • X-XSS-Protection

    • Server

    • X-Powered-By

    • Public-Key-Pins

  • Cabeçalho de resposta Content-Type: se sua resposta de serviço incluir o cabeçalho Content-Type com qualquer um dos seguintes valores de tipo MIME (que indicam um executável), o proxy Snowflake não encaminhará essa resposta ao cliente. Em vez disso, o proxy enviará uma resposta 403 Forbidden.

    • application/x-msdownload: executável da Microsoft.

    • application/exe: executável genérico.

    • application/x-exe: outro executável genérico.

    • application/dos-exe: DOS executável.

    • application/x-winexe: executável do Windows.

    • application/msdos-windows: MS-DOS executável do Windows.

    • application/x-msdos-program: MS-DOS executável.

    • application/x-sh: script de shell Unix.

    • application/x-bsh: script de shell Bourne.

    • application/x-csh: script de shell C.

    • application/x-tcsh: script de shell Tcsh.

    • application/batch: arquivo em lote do Windows.

  • Cabeçalho de resposta X-Frame-Options: para evitar ataques de clickjacking, o proxy Snowflake define esse cabeçalho de resposta como DENY, evitando que outras páginas da Web usem um iframe para a página da Web do seu serviço.

  • Cabeçalho de resposta Cross-Origin-Opener-Policy (COOP): Snowflake define o cabeçalho de resposta COOP como same-origin para impedir que janelas de origem cruzada de referência acessem sua guia de serviço.

  • Cabeçalho de resposta Cross-Origin-Resource-Policy (CORP): Snowflake define o cabeçalho CORP como same-origin para evitar que sites externos carreguem recursos expostos pelo ponto de extremidade de entrada (por exemplo, em um iframe).

  • Cabeçalho de resposta X-Content-Type-Options: o proxy Snowflake define esse cabeçalho como nosniff para garantir que os clientes não alterem o tipo MIME indicado na resposta pelo seu serviço.

  • Cabeçalho de resposta Cross-Origin-Embedder-Policy (COEP): o proxy Snowflake define o cabeçalho de resposta COEP como credentialless, o que significa que ao carregar um objeto de origem cruzada, como uma imagem ou um script, se o objeto remoto não suportar o protocolo Cross-Origin Resource Sharing (CORS), o Snowflake não enviará as credenciais ao carregá-lo.

  • Cabeçalho de resposta Content-Security-Policy-Report-Only: o proxy Snowflake substitui esse cabeçalho de resposta por um novo valor direcionando o cliente para enviar os relatórios CSP ao Snowflake.

  • Cabeçalho de resposta Content-Security-Policy (CSP): por padrão, o proxy Snowflake adiciona a seguinte linha de base CSP para proteção contra ataques comuns da Web.

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

    Há duas considerações sobre política de segurança de conteúdo:

    • Além da política de segurança de conteúdo de linha de base que o proxy adiciona, o próprio serviço pode adicionar explicitamente um CSP na resposta. Um serviço pode optar por aumentar a segurança adicionando um CSP mais rigoroso. Por exemplo, um serviço pode adicionar o seguinte CSP para permitir scripts somente de self.

      script-src 'self'
      
      Copy

      Na resposta resultante enviada ao cliente, haverá dois cabeçalhos CSP. Ao receber a resposta, os navegadores do cliente aplicam a política de segurança de conteúdo mais rigorosa que inclui as restrições adicionais especificadas por cada política.

    • Se você configurar uma integração de acesso externo (EAI) para permitir que seu serviço acesse um site externo (Configuração da saída da rede), o proxy Snowflake criará um CSP que permite que sua página da web acesse esse site. Por exemplo, suponha que uma regra de rede associada a EAI permita acesso de saída de serviço a example.com. Em seguida, o proxy Snowflake adiciona este cabeçalho de resposta CSP:

      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

      Os navegadores respeitam a política de acesso ao conteúdo recebida na resposta. Neste exemplo, os navegadores permitem que o aplicativo acesse example.com, mas não outros sites.

Considerações sobre ingresso e SSO

Ao acessar o ponto de extremidade público pela Internet, você pode descobrir que a autenticação por nome de usuário/senha funciona, mas SSO resulta em uma página em branco ou no erro: «A integração do clienteOAuth com o ID do cliente fornecido não foi encontrada.»

Isso acontece quando você está usando o estilo antigo de autenticação federada (SSO) com o Snowflake em vez da versão mais recente de integração de segurança, conforme explicado em Configuração do Snowflake para usar a autenticação federada. Faça o seguinte para verificar:

  1. Execute a seguinte consulta:

    SHOW PARAMETERS LIKE 'SAML_IDENTITY_PROVIDER' IN ACCOUNT;
    
    Copy

    Se esse parâmetro estiver definido, então, em algum momento, você estava usando a autenticação federada antiga.

  2. Se o parâmetro anterior foi definido, execute as seguintes consultas para verificar se você tem uma integração de segurança SAML:

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

    Se você não tiver nenhuma integração do tipo SAML2, então está usando a versão antiga de autenticação federada.

Nesse caso, a solução é migrar da autenticação federada antiga para a nova autenticação federada da integração. Para obter mais informações, consulte Migração para uma integração de segurança SAML2.

Configuração da saída da rede

O código do seu aplicativo pode exigir acesso à internet. Por padrão, os contêineres de aplicativos não têm permissão para acessar a internet. Você precisa ativar o acesso à internet usando integrações de acesso externo (EAIs).

Normalmente, você deseja que um administrador de conta crie EAIs para gerenciar o acesso externo permitido de serviços (incluindo serviços de trabalho). Os administradores da conta podem então conceder o uso de EAI a funções específicas que os desenvolvedores usam para executar serviços.

O exemplo a seguir descreve as etapas para criar uma EAI que permite o tráfego de saída para destinos específicos determinados usando regras de rede. Em seguida, consulte a EAI ao criar um serviço para permitir solicitações para destinos específicos da internet.

Exemplo

Suponha que você queira que o código do seu aplicativo envie solicitações para os seguintes destinos:

  • Solicitações de HTTPS para translation.googleapis.com

  • Solicitações de HTTP e HTTPS para google.com

Siga estas etapas para permitir que seu serviço acesse esses domínios na Internet:

  1. Criação de uma integração de acesso externo (EAI). Isso requer permissões apropriadas. Por exemplo, você pode usar a função ACCOUNTADMIN para criar uma EAI. Este é um processo de duas etapas:

    1. Use o comando CREATE NETWORK RULE para criar uma ou mais regras de rede de saída listando destinos externos aos quais você deseja permitir acesso. Você pode realizar este exemplo com uma regra de rede, mas para ilustração, criamos duas regras de rede:

      1. Crie uma regra de rede chamada translate_network_rule:

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

        Esta regra permite conexões TCP com o destino translation.googleapis.com. O domínio na propriedade VALUE_LIST não especifica o número da porta opcional, portanto a porta padrão 443 (HTTPS) é assumida. Isso permite que seu aplicativo se conecte a qualquer URL que comece com https://translation.googleapis.com/.

      2. Crie uma regra de rede chamada 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

        Isso permite que seu aplicativo se conecte a qualquer URL que comece com http://google.com/ ou https://google.com/.

      Nota

      Para o parâmetro VALUE_LIST, você deve fornecer um nome de host completo. Curingas (por exemplo, *.googleapis.com) não são suportados.

      O Snowpark Container Services oferece suporte apenas às regras de rede que permitem as portas 22, 80, 443, e 1024+. Se uma regra de rede referenciada permitir acesso a outras portas, a criação do serviço falhará. Entre em contato com seu representante de conta se precisar do uso de portas adicionais.

      Nota

      Para permitir que seu serviço envie solicitações HTTP ou HTTPS para qualquer destino na internet, especifique «0.0.0.0» como o domínio na propriedade VALUE_LIST. A regra de rede a seguir permite enviar solicitações «HTTP» e «HTTPS» para qualquer lugar na Internet. Somente as portas 80 ou 443 são suportadas com «0.0.0.0».

      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. Crie uma integração de acesso externo (EAI) que especifique que as duas regras de rede de saída anteriores são permitidas:

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

      Agora o administrador da conta pode conceder o uso da integração aos desenvolvedores para permitir que executem um serviço que pode acessar destinos específicos na Internet.

      GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE test_role;
      
      Copy
  2. Crie o serviço fornecendo EAI conforme mostrado nos exemplos a seguir. A função do proprietário que está criando o serviço precisa do privilégio USAGE no privilégio EAI e READ bre os segredos referenciados. Observe que você não pode usar a função ACCOUNTADMIN para criar um serviço.

    • Crie um serviço:

      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

      Este exemplo de solicitação CREATE SERVICE usa uma especificação de serviço sequencial e especifica a propriedade opcional EXTERNAL_ACCESS_INTEGRATIONS para incluir a EAI. A EAI especifica as regras de rede que permitem o tráfego de saída do serviço para destinos específicos.

    • Execute um serviço de trabalho:

      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

      Este exemplo de comando EXECUTE JOB SERVICE especifica a especificação embutida e a propriedade opcional EXTERNAL_ACCESS_INTEGRATIONS para incluir a EAI. Isso permite o tráfego de saída do trabalho para destinos especificados nas regras de rede permitidas por EAI.

Saída da rede usando conectividade privada

Em vez de rotear a saída da rede pela Internet pública, você pode optar por direcionar o tráfego de saída do seu serviço por meio de um ponto de extremidade de conectividade privada.

Primeiro, você precisa criar o ponto de extremidade de conectividade privada em sua conta do Snowflake. Em seguida, configure uma regra de rede para permitir que o tráfego de saída use a conectividade privada. O processo de configuração de uma integração de acesso externo (EAI) permanece o mesmo descrito na seção anterior.

Nota

A comunicação privada exige que tanto o Snowflake quanto a conta de nuvem do cliente usem o mesmo provedor de nuvem e a mesma região.

Por exemplo, se você quiser habilitar o acesso de saída da Internet do seu serviço a um bucket S3 Amazon por meio de conectividade privada, faça o seguinte:

  1. Habilite a conectividade do link privado para o serviço de ponto de extremidade autônomo (Amazon S3). Para obter instruções passo a passo, consulte AWS Private Link para Amazon S3.

  2. Chame a função do sistema SYSTEM$PROVISION_PRIVATELINK_ENDPOINT para provisionar um ponto de extremidade de conectividade privada em seu Snowflake VNet. Isso permite que o Snowflake se conecte ao serviço externo (neste exemplo, o Amazon S3) usando conectividade privada.

    USE ROLE ACCOUNTADMIN;
    
    SELECT SYSTEM$PROVISION_PRIVATELINK_ENDPOINT(
      'com.amazonaws.us-west-2.s3',
      '*.s3.us-west-2.amazonaws.com'
    );
    
    Copy
  3. Na conta do provedor de nuvem, aprove o ponto de extremidade. Neste exemplo, para a Amazon AWS, consulte Como aceitar ou rejeitar solicitações de conexão na documentação do AWS. Além disso, para aprovar o ponto de extremidade no Azure, consulte a documentação do Azure.

  4. Use o comando CREATE NETWORK RULE para criar uma regra de rede de saída que especifique os destinos externos aos quais você deseja permitir o acesso.

    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

    O valor do parâmetro TYPE é definido como PRIVATE_HOST_PORT. Isso indica que a regra de rede permite que o tráfego de rede de saída use a conectividade privada.

  5. As demais etapas para criar uma EAI e usá-la para criar um serviço são as mesmas explicadas na seção anterior (consulte Configuração da saída da rede).

Para obter mais informações sobre como trabalhar com pontos de extremidade de conectividade privada, consulte o seguinte:

Configuração de comunicações de rede entre contêineres

Há duas considerações:

  • Comunicações entre contêineres de uma instância de serviço: se uma instância de serviço executar vários contêineres, esses contêineres poderão se comunicar entre si por meio do host local (não há necessidade de definir pontos de extremidade na especificação de serviço).

  • Comunicação entre contêineres em vários serviços ou múltiplas instâncias de serviço: contêineres pertencentes a diferentes serviços (ou diferentes instâncias do mesmo serviço) podem se comunicar usando pontos de extremidade definidos em arquivos de especificação. Para obter mais informações, consulte Comunicações serviço a serviço.

Como passar credenciais para um contêiner usando segredos do Snowflake

Há muitos motivos pelos quais você pode querer passar credenciais Snowflake gerenciadas para seu contêiner. Por exemplo, seu serviço pode se comunicar com pontos de extremidade externos (fora do Snowflake), caso em que será necessário fornecer informações de credenciais em seu contêiner para que o código do aplicativo as utilize.

Para fornecer as credenciais, primeiro armazene-as em objetos secretos Snowflake. Em seguida, na especificação do serviço, use containers.secrets para definir quais objetos secretos usar e onde colocá-los dentro do contêiner. É possível passar essas credenciais para variáveis de ambiente nos contêineres ou disponibilizá-las em arquivos locais nos contêineres.

Especificando segredos Snowflake

Especifique um segredo Snowflake por nome ou referência (a referência é aplicável somente no cenário com Native Applications):

  • Passe o segredo Snowflake por nome: É possível passar um nome secreto como valor do campo snowflakeSecret.

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

    Observe que você pode opcionalmente especificar <secret-name> diretamente como o valor snowflakeSecret.

  • Passe o segredo Snowflake por referência: Ao usar o Snowpark Container Services para criar um Native App (um aplicativo com contêineres), o produtor e os consumidores do aplicativo usam contas Snowflake diferentes. Em alguns contextos, um Snowflake Native App instalado precisa acessar objetos secretos existentes na conta do consumidor que existem fora do objeto APPLICATION. Nesse caso, os desenvolvedores podem usar a sintaxe da especificação “segredos por referência” para manipular credenciais, conforme mostrado:

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

    Observe que a especificação usa objectReference em vez de objectName para fornecer um nome de referência de segredo.

Especificação do posicionamento dos segredos dentro do contêiner

É possível dizer ao Snowflake para colocar os segredos nos contêineres como variáveis de ambiente ou gravá-los em arquivos de contêiner locais.

Como passar os segredos como variáveis de ambiente

Para passar segredos Snowflake para contêineres como variáveis de ambiente, inclua envVarName no campo containers.secrets.

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

O valor secretKeyRef depende do tipo de segredo Snowflake. Os valores possíveis são os seguintes:

  • username ou password se o segredo do Snowflake for do tipo password.

  • secret_string se o segredo do Snowflake for do tipo generic_string.

Observe que o Snowflake não atualiza segredos passados como variáveis de ambiente após a criação de um serviço.

Exemplo 1: como passar segredos do tipo senha como variáveis de ambiente

Neste exemplo, você cria o seguinte objeto de segredo do Snowflake do tipo password:

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

Para fornecer esse objeto de segredo do Snowflake às variáveis de ambiente (por exemplo, LOGIN_USER e LOGIN_PASSWORD) em seu contêiner, adicione o seguinte campo containers.secrets no arquivo de especificação:

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

Neste exemplo, o valor snowflakeSecret é um nome de objeto totalmente qualificado porque os segredos podem ser armazenados em um esquema diferente do serviço que está sendo criado.

O campo containers.secrets neste exemplo é uma lista de dois objetos snowflakeSecret:

  • O primeiro objeto mapeia username no objeto do segredo do Snowflake para a variável de ambiente LOGIN_USER em seu contêiner.

  • O segundo objeto mapeia password no objeto do segredo do Snowflake para a variável de ambiente LOGIN_PASSWORD em seu contêiner.

Exemplo 2: como passar segredos do tipo cadeia_de_caracteres_genérica como variáveis de ambiente

Neste exemplo, você cria o seguinte objeto de segredo do Snowflake do tipo generic_string:

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

Para fornecer esse objeto do segredo do Snowflake para variáveis de ambiente (por exemplo, GENERIC_SECRET) em seu contêiner, adicione o seguinte campo containers.secrets no arquivo de especificação:

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

Gravação de segredos em arquivos de contêiner locais

Para disponibilizar segredos Snowflake para o contêiner do aplicativo em arquivos de contêiner locais, inclua um campo containers.secrets: Para disponibilizar os segredos Snowflake para o contêiner do aplicativo em arquivos de contêiner locais, inclua directoryPath em containers.secrets:

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

O Snowflake preenche os arquivos necessários para o segredo neste directoryPath especificado; não é necessário especificar secretKeyRef. Dependendo do tipo de segredo, o Snowflake cria os seguintes arquivos no contêiner no caminho de diretório fornecido:

  • username e password, se o segredo Snowflake for do tipo password.

  • secret_string se o segredo do Snowflake for do tipo generic_string.

  • access_token se o segredo do Snowflake for do tipo oauth2.

Nota

Após a criação de um serviço, se o objeto do segredo do Snowflake for atualizado, o Snowflake atualizará os arquivos do segredo correspondentes nos contêineres em execução.

Exemplo 1: como passar segredos do tipo senha em arquivos de contêiner locais

Neste exemplo, você cria o seguinte objeto de segredo do Snowflake do tipo password:

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

Para disponibilizar essas credenciais em arquivos de contêiner locais, adicione o seguinte campo containers.secrets no arquivo de especificação:

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

Quando você inicia o serviço, o Snowflake cria dois arquivos dentro do contêiner: /usr/local/creds/username e /usr/local/creds/password. O código do seu aplicativo pode então ler esses arquivos.

Exemplo 2: Como passar segredos do tipo generic_string em arquivos de contêiner locais

Neste exemplo, você cria o seguinte objeto de segredo do Snowflake do tipo generic_string:

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

Para fornecer este objeto secreto Snowflake em arquivos de contêiner locais, adicione o seguinte campo containers.secrets no arquivo de especificação:

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

Quando você inicia o serviço, o Snowflake cria este arquivo dentro dos contêineres: /usr/local/creds/secret_string.

Exemplo 3: Como passar segredos do tipo oauth2 em arquivos de contêiner locais

Neste exemplo, você cria o seguinte objeto de segredo do Snowflake do tipo 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

Para disponibilizar essas credenciais em arquivos de contêiner locais, adicione o seguinte campo containers.secrets no arquivo de especificação:

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

Snowflake busca o token de acesso do objeto do segredo do OAuth e cria /usr/local/creds/access_token nos contêineres.

Quando um serviço usa segredos do tipo oauth2, espera-se que o serviço use esse segredo para acessar um destino da internet. Um segredo oauth deve ser permitido pela integração de acesso externo (EAI); caso contrário, CREATE SERVICE ou EXECUTE JOB SERVICE falharão. Este requisito de EAI extra se aplica apenas a segredos do tipo oauth2 e não a outros tipos de segredos.

Em resumo, as etapas típicas na criação de tal serviço são:

  1. Crie um segredo do tipo oauth2 (mostrado anteriormente).

  2. Crie uma EAI para permitir o uso do segredo por um serviço. Por exemplo:

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION example_eai
      ALLOWED_NETWORK_RULES = (<name>)
      ALLOWED_AUTHENTICATION_SECRETS = (testdb.testschema.oauth_secret)
      ENABLED = true;
    
    Copy
  3. Crie um serviço que inclua um campo containers.secrets na especificação. Isso também especifica a propriedade opcional EXTERNAL_ACCESS_INTEGRATIONS para incluir uma EAI para permitir o uso do segredo oauth2.

    Um exemplo de comando CREATE SERVICE (com especificação inline):

    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

Para obter mais informações sobre saída, consulte Configuração da saída da rede.

Diretrizes e limitações

  • Limitações gerais: Se você encontrar algum problema com essas limitações, entre em contato com seu representante de conta.

    • É possível criar até 200 serviços em sua conta Snowflake.

    • Cada serviço pode expor até 100 pontos de extremidade.

    • As seguintes limitações se aplicam quando você habilita o acesso à Internet (consulte Configuração da saída da rede) usando integrações de acesso externo (EAIs).

      • Cada serviço pode oferecer suporte para até 10 EAIs (consulte CREATE SERVICE e ALTER SERVICE).

      • Cada EAI pode ter até 100 nomes de host.

    • O Snowpark Container Services oferece suporte à conectividade privada de saída tanto no AWS quanto no Azure. A conectividade privada de entrada está em versão preliminar para o AWS. Entre em contato com o representante da sua conta se precisar de conectividade privada de entrada no Azure.

    • Ao acessar o ponto de extremidade público pela Internet, você pode descobrir que a autenticação por nome de usuário/senha funciona, mas SSO resulta em uma página em branco ou no erro: «A integração do clienteOAuth com o ID do cliente fornecido não foi encontrada.» Para obter informações sobre como resolver esse problema, consulte Considerações sobre ingresso e SSO.

  • Requisitos da plataforma de imagem: atualmente, o Snowpark Container Services exige imagens da plataforma Linux/AMD64.

  • Contêineres de serviço não são privilegiados: os contêineres de serviço não são executados como privilegiados e, portanto, não podem alterar a configuração do hardware no host e podem alterar apenas configurações de OS limitadas. Os contêineres de serviço só podem executar configurações do sistema operacional que um usuário normal (ou seja, um usuário que não requer root) pode fazer.

  • Como renomear o banco de dados e o esquema:

    • Não renomeie bancos de dados e esquemas onde você já criou um serviço. Renomear é efetivamente mover um serviço para outro banco de dados e esquema, que não é compatível. Por exemplo:

      • O nome do serviço DNS continuará refletindo o banco de dados antigo e o nome do esquema.

      • As informações de banco de dados e esquema que o Snowflake forneceu aos contêineres de serviço em execução continuarão a se referir aos nomes antigos.

      • Os novos logs que os serviços ingerem na tabela de eventos continuarão a fazer referência ao banco de dados antigo e aos nomes de esquema.

      • A função de serviço continuará a fazer referência ao serviço no banco de dados e esquema antigos e, quando você invocar a função de serviço, ela falhará.

    • Uma especificação de serviço pode fazer referência a objetos como estágios Snowflake e repositórios de imagens. Se você renomear os nomes do banco de dados ou do esquema onde esses objetos residem, será necessário atualizar manualmente os nomes do banco de dados e do esquema dos objetos referenciados na especificação de serviço.

  • Descarte e cancelamento de um banco de dados e esquema:

    • Quando você descarta o banco de dados ou esquema pai, os serviços são excluídos de forma assíncrona. Isso significa que um serviço pode continuar em execução por algum tempo antes que os processos internos o removam.

    • Se você tentar cancelar um banco de dados ou esquema excluído anteriormente, não há garantia de que os serviços serão restaurados.

  • Transferência de propriedade: a transferência de propriedade de serviços (incluindo serviços de trabalho) não é suportada.

  • Replicação: ao lidar com replicação no Snowflake, observe o seguinte:

    • Os objetos do Snowpark Container Services, como serviços, pools de computação e repositórios, não podem ser replicados.

    • Se você criar um repositório em um banco de dados, o banco de dados inteiro não poderá ser replicado. Nos casos em que o banco de dados contém outros recursos, como serviços ou pools de computação, o processo de replicação do banco de dados será bem-sucedido, mas esses objetos individuais no banco de dados não serão replicados.

  • Tempo limite dos serviços de trabalho: os serviços de trabalho do Snowpark Container Services são executados de forma síncrona. Se uma instrução expirar, o serviço de trabalho será cancelado. O tempo limite padrão da instrução é de dois dias. Os clientes podem alterar o tempo limite definindo o parâmetro STATEMENT_TIMEOUT_IN_SECONDS usando ALTER SESSION.

    ALTER SESSION SET statement_timeout_in_seconds=<time>
    
    Copy

    Configure-o antes de executar o comando EXECUTE JOB SERVICE.