Snowflakeにキーペア認証で接続してみる

# はじめに
初めてアドベントカレンダーに参加してみます。

https://qiita.com/advent-calendar/2024/snowflake

シリーズ3の19日目です。

SnowflakeでMFA強制されるので、各種ツールからパスワードを指定してログインさせているようなものが使えなくなるようです。
詳しくは下記、Rakudeji前田さんの記事をご覧ください。

https://zenn.dev/dataheroes/articles/fa0b8c9b0017bb?redirected=1

人じゃなくてツールなのでMFA認証みたいなものはできないです。（スマホにランダムな番号が送られてきて、それを見て入力するみたなやつ）
ですのでSSOとかキーペア認証かみたいな別の方法でのログインが必要になります。

SSOは人用なのでツール用のキーペア認証を試してみたという話です。

# 接続ツール検討
どのツールからSnowflakeに接続トライしようかということで、
Tableauからやってみようと思いました。
ただ、自分はフリーのTableau Publicしか持っていなくて、SnowflakeのODBCドライバをインストールしてもコネクターとしてTableau Publicの画面に出てきませんでした。
![スクリーンショット 2024-12-19 194232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/71fbf892-3b4c-a200-8607-a895019faf85.png)
ぐぬぬ、ダメでした。

Tableau Desktopなら行けるとクラスメソッドさんの記事にはありました。

https://dev.classmethod.jp/articles/ver2024-3-snowflake-tableau-key-pair-auth/

いいなー、Tableau Desktop。

次はPowerBI Desktopです。
接続先にSnowflakeは選択可能でした。おおー、さっきより行ける気がする。
で進むとこんな画面。
![スクリーンショット 2024-12-19 194908.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/d215696a-f00c-90d0-ffc3-0f2e9f85f2cf.png)

ユーザー名、パスワードを入れる方式か、あるいはMicrosoft AccountでSSO？なのか。（Microsoft Accountの方はちょっとよくわかってないです。）
これじゃダメですね。

しょうがないので、外部ツールとは言えないかもしれないけどSnowSQLでキーペア認証を試します。

# 公開鍵、秘密鍵の作成
SnowSQLで試すと書いたものの、まだ出てきません。
まずは自分のPCで公開鍵、秘密鍵を作ります。
コマンドプロンプトを起動してまずは秘密鍵を作ります。
秘密鍵の名前はsnow_rsa_key.p8としました。
```
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 des3 -inform PEM -out snow_rsa_key.p8
```

すると暗号化パスワードを入れろと言われます。
```
Enter Encryption Password:
```
自分で決めて入れましょう。
```
Verifying - Enter Encryption Password:
```
もう一回同じのいれます。
これでローカルPC上にsnow_rsa_key.p8というファイルができています。

次に公開鍵を作ります。
```
openssl rsa -in snow_rsa_key.p8 -pubout -out snow_rsa_key.pub
```
先ほど作った秘密鍵snow_rsa_key.p8を使って公開鍵snow_rsa_key.pubを作成します。
```
Enter pass phrase for snow_rsa_key.p8:
```
秘密鍵snow_rsa_key.p8のパスフレーズを入れろと言われますのでさっき決めたやつを入れます。
これで公開鍵snow_rsa_key.pubができます。

公開鍵snow_rsa_key.pubをテキストエディタで開きます。
```
-----BEGIN PUBLIC KEY-----
xxxxxxxxx
xxxxxxxxx
-----END PUBLIC KEY-----
```
このxxxxxxxxxの部分をメモ帳とかにコピーします。

次に公開鍵のフィンガープリントも出しておきます。
```
openssl rsa -pubin -in snow_rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64
```
これもメモ帳とかにコピーしておきます。

# SnowSightでの手順
お次はSnowflakeの出番、SnowSightを起動します。
TOOL_USERというユーザーをキーペア認証で使える形で作成します。

```
use role useradmin;

create user TOOL_USER RSA_PUBLIC_KEY ='xxxxxxxxx'
TYPE = SERVICE;
```
RSA_PUBLIC_KEYのところに先ほどコピーした公開鍵の文字列をペーストします。
TYPE = SERVICEとすることで「人じゃなくて外部サービス用ユーザーです」という宣言になります。

```
show users;
desc user TOOL_USER;
SELECT TRIM((SELECT "value" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE "property" = 'RSA_PUBLIC_KEY_FP'), 'SHA256:');
```
次に作ったTOOL_USERの情報を見てSELECT文を投げます。
ここで得られたフィンガープリントをメモします。

コマンドプロンプトで出してメモしておいたフィンガープリントと、Snowflakeで得られたフィンガープリントが一致してればOKです。

# SnowSQLでの手順
SnowSQLはインストール済みの前提で進めます。
C:\Users\[PCユーザー]\.snowsql
にSnowSQLのconfigファイルがあります。

なお、私は.snowsqlフォルダの下にkeyフォルダを作って、上の方で作成した秘密鍵と公開鍵を入れておきました。
configファイルに話を戻します。
```
[connections.TOOL_USER]
#Can be used in SnowSql as #connect example
accountname = [アカウント識別子（ハイフンでつないだやつ）]
username = TOOL_USER
dbname = TEST_DB
schemaname = TEST_SCHEMA
private_key_path = C:\Users\[PCユーザー]\.snowsql\key\snow_rsa_key.p8
```
こんな感じで記入します。

ではSnowSQLを起動してみます。
再びコマンドプロンプトです。

```
snowsql -c TOOL_USER
```

```
C:\Users\[PCユーザー]>snowsql -c TOOL_USER
Private Key Passphrase:
* SnowSQL * v1.2.32
Type SQL statements or !help
TOOL_USER#(no warehouse)@TEST_DB.TEST_SCHEMA>
```
Private Key Passphraseのところは自分でセットしたパスフレーズを入れました。
あれ、手動入力？？
環境変数に設定すれば、手動入力しなくてもいけるそうです。

https://docs.snowflake.com/ja/user-guide/snowsql-start#label-snowsql-key-pair-authn-rotation

>SNOWSQL_PRIVATE_KEY_PASSPHRASE 環境変数を使用して、秘密鍵ファイルを復号化するためのパスフレーズを設定します。Linuxまたは MacOS の場合はパスフレーズを引用符で囲みませんが、Windowsの場合は一重引用符または二重引用符を使用する必要があることに注意してください。

これで接続できたからヨシ！
でした。

AzureDataFactoryの接続画面を他の人に見せてもらったところ
- 秘密キー
- 秘密キーパスフレーズ

を画面で設定できるようでした。
私はAzureDataFactoryを触る権限がないので見せてもらっただけなんですが、まあ行けそうですね。

作ったTOOL_USERになんのロールも付与してないので、何もできませんが、この後ロール付与してselectとかができることは確認できました。（本題じゃないので省略）

# 終わりに
初めて秘密鍵、公開鍵を作成しました。
これが昔試験勉強で勉強したやつか。と思いつつ。
すっかり忘れてたけど作ってみるとなんか理解できますね。