Snowflake に JWT 認証で SQL ステートメントを実行してみた

Snowflake に外部から SQL ステートメントを実行したい場合、外部の連携システムやツールなどが用意している方法を使用すると思います。今回は独自プログラムから実行することを想定して、Curl で SQL ステートメントを実行してみました。

Snowflake 用の秘密鍵と公開鍵を作成

ここでは設定するパスフレーズを test とします。

$ openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 des3 -inform PEM -out rsa_key.p8

Enter Encryption Password: test
Verifying - Enter Encryption Password: test

$ openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub

Enter pass phrase for rsa_key.p8: test
writing RSA key

$ cat rsa_key.pub
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAosOugqX0lnEIRZ7nVwv5
HEpmc05hUggBFaYVs/jHSZb9ptZZ9mN7GufDV7q4iu5XilL8P2peAmTO5jEliuzb
jGlXHJ2xOPhBL6j+dp2B9A//idLe52QQkMEy7oFP2fTdsWGj8l2cLwEqdBnidDl8
z0BMRzH6+khJKWhOCeRQxQmuGaYeyGJX9jknyBtcEweEzztDSnZmYMGN234LJTHD
Cd9U6ZFBERWKZF+DKkxfySI6hjlACqW5WCW7DHYStAH8CILyltkv1tqfwV0xOuVK
h4Aym7ollYNqx89d1u/McIF6GoQHuEdyyuphn87h6hne0zJ3rXsyxBkG30w4B/vs
rQIDAQAB
-----END PUBLIC KEY-----

Snowflake のワークシートからユーザーに公開鍵を登録

ALTER USER mnrst SET RSA_PUBLIC_KEY='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAosOugqX0lnEIRZ7nVwv5
HEpmc05hUggBFaYVs/jHSZb9ptZZ9mN7GufDV7q4iu5XilL8P2peAmTO5jEliuzb
jGlXHJ2xOPhBL6j+dp2B9A//idLe52QQkMEy7oFP2fTdsWGj8l2cLwEqdBnidDl8
z0BMRzH6+khJKWhOCeRQxQmuGaYeyGJX9jknyBtcEweEzztDSnZmYMGN234LJTHD
Cd9U6ZFBERWKZF+DKkxfySI6hjlACqW5WCW7DHYStAH8CILyltkv1tqfwV0xOuVK
h4Aym7ollYNqx89d1u/McIF6GoQHuEdyyuphn87h6hne0zJ3rXsyxBkG30w4B/vs
rQIDAQAB';

登録した公開鍵のフィンガープリントを確認

DESC USER mnrst;

RSA_PUBLIC_KEY_FP 項目が例えば SHA256:1kWUn6nE3EhXBCoAuNJ3uX1PEDA4Wetn7Ta5G5TQHMk= のように表示されている事を確認します。

ローカルで登録したフィンガープリントが同じかを確認

$ openssl rsa -pubin -in rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64

writing RSA key
1kWUn6nE3EhXBCoAuNJ3uX1PEDA4Wetn7Ta5G5TQHMk=

snowsql コマンドで動作確認

$ export sfaccount=abcdefg-hi00000
$ export sfuser=mnrst
$ export SNOWSQL_PRIVATE_KEY_PASSPHRASE=test

$ snowsql -a $sfaccount -u $sfuser --private-key-path rsa_key.p8

Private Key Passphrase: 
* SnowSQL * v1.2.31
Type SQL statements or !help
mnrst#COMPUTE_WH@(no database).(no schema)>!exit

JWT トークンを生成する Python コード snowflake-jwt.py を作成

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from datetime import timedelta, timezone, datetime
import jwt

account = "abcdefg-hi00000".upper()
user = "mnrst".upper()
qualified_username = account + "." + user
public_key_fp = "SHA256:1kWUn6nE3EhXBCoAuNJ3uX1PEDA4Wetn7Ta5G5TQHMk="
now = datetime.now(timezone.utc)
lifetime = timedelta(minutes=59)

payload = {
    "iss": qualified_username + '.' + public_key_fp,
    "sub": qualified_username,
    "iat": now,
    "exp": now + lifetime
}

with open('rsa_key.p8', 'rb') as key_file:
    private_key = serialization.load_pem_private_key(
        key_file.read(),
        password=b'test',
        backend=default_backend()
    )
encoding_algorithm="RS256"
token = jwt.encode(payload, key=private_key, algorithm=encoding_algorithm)
print(token)

JWT トークンを作成

$ pip install pyjwt

$ jwttoken=$(python3 snowflake-jwt.py)

$ echo $jwttoken

Curl で SQL ステートメントを実行

$ curl \
  -H "Authorization: Bearer $jwttoken" \
  -H "X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT" \
  -H "Content-Type: application/json" \
  -d '{"statement": "select current_account()"}' \
  "https://${account}.snowflakecomputing.com/api/v2/statements" \
  | jq .data

[
  [
    "UI53398"
  ]
]

Snowflake 上で同じ SQL ステートメントを実行

参考

https://docs.snowflake.com/ja/developer-guide/sql-api/authenticating#generating-a-jwt-in-python

https://docs.snowflake.com/ja/developer-guide/sql-api/submitting-requests#example-of-a-request

タグ: