Autenticação no servidor

Este tópico descreve como fazer a autenticação no servidor ao usar a API de SQL do Snowflake.

Quando você envia uma solicitação, a solicitação deve incluir informações de autenticação. As próximas seções explicam como adicionar essas informações à solicitação:

Neste tópico:

Uso de OAuth

Para usar o OAuth, siga estes passos:

  1. Configure o OAuth para a autenticação.

    Consulte Introdução ao OAuth para obter detalhes sobre como configurar o OAuth e obter um token OAuth.

  2. Use o SnowSQL para verificar se você pode usar um token OAuth gerado para se conectar ao Snowflake:

    • Para sistemas Linux e MacOS

    $ snowsql -a <account_identifier> -u <user> --authenticator=oauth --token=<oauth_token>
    
    Copy
    • Para sistemas Windows

    $ snowsql -a <account_identifier> -u <user> --authenticator=oauth --token="<oauth_token>"
    
    Copy
  3. Em cada solicitação de API que você enviar, defina os seguintes cabeçalhos:

    • Authorization: Bearer oauth_token

      onde oauth_token é o token OAuth gerado.

    • X-Snowflake-Authorization-Token-Type: OAUTH

      Observe que você também pode escolher omitir o cabeçalho X-Snowflake-Authorization-Token-Type. Se este cabeçalho não estiver presente, o Snowflake presume que o token no cabeçalho Authorization é um token OAuth.

Uso de autenticação de pares de chaves

Para usar a autenticação por par de chaves, siga esses passos:

  1. Configure a autenticação por par de chaves.

    Como parte desse processo, você deve:

    1. Gerar um par de chaves público-privado. A chave privada gerada deve estar em um arquivo (por exemplo, chamado rsa_key.p8).

    2. Atribua a chave pública a seu usuário do Snowflake. Depois de atribuir a chave ao usuário, execute o comando DESCRIBE USER. Na saída, a propriedade RSA_PUBLIC_KEY_FP deve ser definida como a impressão digital da chave pública atribuída ao usuário.

    Para obter instruções sobre como gerar o par de chaves e atribuir uma chave a um usuário, consulte Autenticação de pares de chaves e rotação de pares de chaves. Para exemplos específicos de como criar uma impressão digital e gerar um token JWT, veja o seguinte:

  2. Use o SnowSQL para verificar se você pode usar a chave privada gerada para conectar ao Snowflake:

    $ snowsql -a <account_identifier> -u <user> --private-key-path <path>/rsa_key.p8
    
    Copy

    Se você tiver gerado uma chave privada criptografada, o SnowSQL solicitará a senha que você criou quando gerou a chave.

  3. Em seu código do aplicativo:

    1. Gere a impressão digital (um hash SHA-256) da chave pública para o usuário. Prefixe a impressão digital com SHA256:. Por exemplo:

      SHA256:hash

      Você também pode executar o comando SQL DESCRIBE USER para obter o valor da propriedade RSA_PUBLIC_KEY_FP.

    2. Gere um web token JSON (JWT) com os seguintes campos na carga útil:

      Campo

      Descrição

      Exemplo

      iss

      Emissor do JWT. Defina-o com o seguinte valor:

      account_identifier.user.SHA256:public_key_fingerprint

      onde:

      • account_identifier é seu identificador da conta Snowflake.

        Se você estiver usando o localizador de contas, exclua qualquer informação de região do localizador de contas.

      • user é seu nome de usuário Snowflake.

      • SHA256:public_key_fingerprint é a impressão digital que você gerou na etapa anterior.

      Nota

      Os valores account_identifier e user devem usar todos os caracteres maiúsculos. Se seu ID da conta contiver pontos (.), você deverá substituí-los por hífens (-), pois os pontos em um identificador de conta fazem com que JWT seja inválido.

      MYORGANIZATION-MYACCOUNT.MYUSER.SHA256:public_key_fingerprint

      sub

      Assunto do JWT. Defina-o com o seguinte valor:

      account_identifier.user

      MYORGANIZATION-MYACCOUNT.MYUSER

      iat

      Tempo de emissão do JWT em UTC. Defina o valor como o valor de tempo atual como segundos ou milissegundos.

      1615370644 (segundos) . 1615370644000 (milissegundos)

      exp

      Tempo de expiração do JWT em UTC. Você pode especificar o valor como segundos ou milissegundos.

      Nota

      Nota: o JWT é válido por, no máximo, uma hora após a emissão do token, mesmo se você especificar um tempo de vencimento mais longo.

      1615374184 (segundos) . 1615374184000 (milissegundos)

    3. Em cada solicitação de API que você enviar, defina os seguintes cabeçalhos:

      • Authorization: Bearer JWT

        onde JWT é o token que você gerou.

      • X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT

Exemplo em Python

As seções a seguir descrevem como gerar um JWT e uma impressão digital usando Python.

Para um exemplo de geração de um JWT em Python, veja sql-api-generate-jwt.py. O exemplo sql-api-generate-jwt.py usa o módulo PyJWT, que você pode instalar executando:

pip install pyjwt
Copy

Como gerar um JWT em Python

As seções de código a seguir demonstram como gerar um JWT. Para obter um exemplo completo, consulte sql-api-generate-jwt.py.

Nota

Este exemplo se destina a ser utilizado apenas como referência. Não utilize esse código em aplicativos ou ambientes de produção.

from datetime import timedelta, timezone, datetime

# This example relies on the PyJWT module (https://pypi.org/project/PyJWT/).
import jwt

# Construct the fully qualified name of the user in uppercase.
# - Replace <account_identifier> with your account identifier.
#   (See https://docs.snowflake.com/en/user-guide/admin-account-identifier.html .)
# - Replace <user_name> with your Snowflake user name.
account = "<account_identifier>"

# Get the account identifier without the region, cloud provider, or subdomain.
if not '.global' in account:
    idx = account.find('.')
    if idx > 0:
        account = account[0:idx]
    else:
        # Handle the replication case.
        idx = account.find('-')
        if idx > 0:
            account = account[0:idx]

# Use uppercase for the account identifier and user name.
account = account.upper()
user = "<user_name>".upper()
qualified_username = account + "." + user

# Get the current time in order to specify the time when the JWT was issued and the expiration time of the JWT.
now = datetime.now(timezone.utc)

# Specify the length of time during which the JWT will be valid. You can specify at most 1 hour.
lifetime = timedelta(minutes=59)

# Create the payload for the token.
payload = {

    # Set the issuer to the fully qualified username concatenated with the public key fingerprint (calculated in the  previous step).
    "iss": qualified_username + '.' + public_key_fp,

    # Set the subject to the fully qualified username.
    "sub": qualified_username,

    # Set the issue time to now.
    "iat": now,

    # Set the expiration time, based on the lifetime specified for this object.
    "exp": now + lifetime
}

# Generate the JWT. private_key is the private key that you read from the private key file in the previous step when you generated the public key fingerprint.
encoding_algorithm="RS256"
token = jwt.encode(payload, key=private_key, algorithm=encoding_algorithm)

# If you are using a version of PyJWT prior to 2.0, jwt.encode returns a byte string, rather than a string.
# If the token is a byte string, convert it to a string.
if isinstance(token, bytes):
  token = token.decode('utf-8')
decoded_token = jwt.decode(token, key=private_key.public_key(), algorithms=[encoding_algorithm])
print("Generated a JWT with the following payload:\n{}".format(decoded_token))
Copy

Como gerar uma impressão digital em Python

As seções de código a seguir demonstram como gerar a impressão digital. Para obter um exemplo completo, consulte sql-api-generate-jwt.py.

from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat
from cryptography.hazmat.backends import default_backend
..
import base64
from getpass import getpass
import hashlib
..
# If you generated an encrypted private key, implement this method to return
# the passphrase for decrypting your private key. As an example, this function
# prompts the user for the passphrase.
def get_private_key_passphrase():
    return getpass('Passphrase for private key: ')

# Private key that you will load from the private key file.
private_key = None

# Open the private key file.
# Replace <private_key_file_path> with the path to your private key file (e.g. /x/y/z/rsa_key.p8).
with open('<private_key_file_path>', 'rb') as pem_in:
    pemlines = pem_in.read()
    try:
        # Try to access the private key without a passphrase.
        private_key = load_pem_private_key(pemlines, None, default_backend())
    except TypeError:
        # If that fails, provide the passphrase returned from get_private_key_passphrase().
        private_key = load_pem_private_key(pemlines, get_private_key_passphrase().encode(), default_backend())

# Get the raw bytes of the public key.
public_key_raw = private_key.public_key().public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)

# Get the sha256 hash of the raw bytes.
sha256hash = hashlib.sha256()
sha256hash.update(public_key_raw)

# Base64-encode the value and prepend the prefix 'SHA256:'.
public_key_fp = 'SHA256:' + base64.b64encode(sha256hash.digest()).decode('utf-8')
Copy

Exemplo em Java

Para obter um exemplo de geração de um JWT em Java, consulte SimpleStatementsApi.java.

Nota

Este exemplo se destina a ser utilizado apenas como referência. Não utilize esse código em aplicativos ou ambientes de produção.

Esse exemplo usa as seguintes bibliotecas de terceiros:

  • Swagger Codegen: uma biblioteca de código aberto útil no desenvolvimento de REST APIs e aplicativos.

  • Auth0: fornece APIs de Java para autenticação e geração de tokens JWT.

Exemplo em Node.js

Para um exemplo de geração de um JWT em Node.js, veja sql-api-generate-jwt.js.

Nota

Este exemplo se destina a ser utilizado apenas como referência. Não utilize esse código em aplicativos ou ambientes de produção.