SnowflakeのMFAを使わない認証について試してみる（その1：キーペア認証）

# はじめに
Snowflakeでは昨年(2024年)後半からパスワード単一認証を徐々に廃止していくことをアナウンスしており、直近では2025年2月に新規のSnowflakeアカウントのパスワード認証にMFAがデフォルトで必須になり、4月には既存のSnowflakeアカウントでも同様の設定となる予定です。これはおそらく2024年の上半期に発生したSnowflakeアカウントに対する大規模なサイバー攻撃（別のところで漏れたパスワードを用いて100社以上のSnowflakeアカウントが攻撃にあい、データの窃取と脅迫の被害を受けたもの。MFA設定済みの企業には被害なし）がきっかけだと思われ、すでに攻撃が発生していることから適用の延期や中止がなされることはないでしょう。
とはいえ、MFAが利用できない環境もあるかと思います。私もお客様から問い合わせを受けたりしたので、ちょっとMFAを使わない認証を試してみることにしました。

# MFAを使わない認証
MFAが必要となるのは、Snowflake側でパスワード認証を行う場合です。これ以外の認証、たとえばキーペア認証、IdPを使ったシングルサインオン(SSO)、外部OAuth認証ではSnowflakeが用意しているMFA設定は不要です（もちろんSSOなどではIdPの設定でMFAが要求される環境もあると思います）。Snowflakeで使えるMFAのデバイスは現状でDUO Mobileのみであり（他のMFAデバイスも増やす予定はあるらしいですが）、SSOを構成して他のMFAを使いたいというニーズもあるかもしれません。
というわけで、今回は以下2つの認証について設定を確認してみましたので、設定手順などを簡単にまとめたいと思います。
* キーペア認証
* IdPにOktaを使ったSSO

とはいえ、すでにQiitaを始めとして各所に同様の情報はあふれているので、ここでは実際にやって引っかかったところについても触れていくつもりです。

# キーペア認証
おそらく乗り換え先で一番手っ取り早いのがこちらではないでしょうか。Snowsightには対応していませんが、それ以外の一通りのクライアントやドライバが対応しています。手順はドキュメントのこちらに書いています (https://docs.snowflake.com/ja/user-guide/key-pair-auth) が、ざっと以下の通りです。
1. 秘密鍵を作る
1. 秘密鍵から公開鍵を作る
1. 対象のユーザーに公開鍵を登録する
1. クライアントやドライバの設定でキーペア認証をするように設定し、ログイン

簡単ですね。では一つずつ見ていきましょう。

#  秘密鍵と公開鍵を作る
キーペアは2048ビット以上のRSA方式として作成します。また、秘密鍵と公開鍵ともにPEM形式である必要があります。最初は横着してTeratermでキーペアを作成して試してみましたが、公開鍵のほうがOpenSSH独自形式らしく、次の公開鍵登録ではじかれてしまいました。秘密鍵はPEM形式で作成されるので、秘密鍵から下にも記載しているSnowflakeドキュメントのOpenSSLのコマンドで登録可能な公開鍵は作成できましたが、であれば最初から（秘密鍵作成時から）OpenSSLを使ったほうが良いですね。というわけで、ドキュメントにあるOpenSSLのコマンドをそのままコピペして作成するのが最もトラブルなく済むと思います。

OpenSSLはMacや各種LinuxディストリビューションなどのUNIX系のOSだと初めから入っていることが多いと思います（少なくとも自分のMacとUbuntuには入っていた）。多数派のWindowsだとOpenSSLをダウンロードしてきて別途インストールする必要がありますが、私の環境ではAnacondaをインストールしていたので、こちらに初めからOpenSSLが入っていました。WSLを使っている方も何かしらのLinuxディストリビューションを入れるので、おそらく入っているでしょう。どれを使ってもSnowflakeドキュメントのコマンドは実行可能です。

秘密鍵の作成
```
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
```
秘密鍵から公開鍵を作成
```
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
```
しれっと暗号化なしで作っていますが（--nocryptオプション）、セキュリティが重要な環境の場合は暗号化してパスフレーズも（スクリプトに平文で埋めたりせずに）しっかり管理しましょう（お約束）。

# 対象のユーザーに公開鍵を登録

こちらはSQLのALTER USER文で登録します。ここで注意すべき点は1点、作成されたPEM形式の公開鍵には改行が入っているので、改行を削除する（その時に間違ってほかの文字も消さない）、というところです。

公開鍵の内容
```
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2IoayUiXkOmHQZHsdY/
/5sV+1VztKvWW89NBfpdSjPpXi7M95GH6/Si8IsbSeorC3MNHx/NCVTKD/wyXwLD
od8I/W3F1By5dpYXGdFSD53riuFwnuoco6st1W1dL0O3zJ1OmwtvT1sTmKw3t81g
mhoLxNronC6ZxzmROITnyzZhlCBoEGIZfdiIEmnfExvTbDyO9+2VKHCSKaGXA5Wa
D3QklQNX2UthNYQYCjND8NHg48IRU6R1Vb+3Ht0zsaXHrtj6aoGQ7m6dFq+8k1Rx
7K86dQKADAt1+w0g9JGFKZLv5vZWSreTCrszZi97mRxTgFjm9k+GTle28YrgUwtW
RwIDAQAB
-----END PUBLIC KEY-----
```
ここのヘッダとフッタの行を除いて、改行を削除し、シングルコーテーションで囲ってALTER USER文を実行したのが以下です。

```SQL
ALTER USER hirama SET RSA_PUBLIC_KEY='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2IoayUiXkOmHQZHsdY//5sV+1VztKvWW89NBfpdSjPpXi7M95GH6/Si8IsbSeorC3MNHx/NCVTKD/wyXwLDod8I/W3F1By5dpYXGdFSD53riuFwnuoco6st1W1dL0O3zJ1OmwtvT1sTmKw3t81gmhoLxNronC6ZxzmROITnyzZhlCBoEGIZfdiIEmnfExvTbDyO9+2VKHCSKaGXA5WaD3QklQNX2UthNYQYCjND8NHg48IRU6R1Vb+3Ht0zsaXHrtj6aoGQ7m6dFq+8k1Rx7K86dQKADAt1+w0g9JGFKZLv5vZWSreTCrszZi97mRxTgFjm9k+GTle28YrgUwtWRwIDAQAB';
```

# クライアント・ドライバの設定
ここまででSnowflakeへキーペア認証でログイン可能になりました。デフォルトではすべての認証方法が許可されていますが、カスタム認証ポリシーを利用している方はAUTHENTICATION_METHODSにKEYPAIRが入っていることを確認してみてください。

あとはクライアント側の設定になります。Snowflakeドキュメントに各ドライバごとの設定が書かれていますが、アプリケーションでよく使われているJDBCの設定を見ると、プログラム側でキーを展開して使うサンプルコードがいきなり出てきてわかりづらかったので、アプリを使うだけのユーザー向けに簡単に設定をまとめます。
端的に書くと、接続プロパティに```private_key_file```と```private_key_file_pwd```（パスフレーズを設定している場合）を設定するだけです。なお```private_key_file```には秘密鍵を保存しているパスを指定しますが、Windowsの場合であってもパスの区切りはバックスラッシュではなくスラッシュとなります。ご注意ください。
JDBCを使ったアプリケーションの設定例として、DBeaverの設定をあげておきます。認証の項目にはユーザー名のみを指定し、「ドライバのプロパティ」タブで```private_key_file```を指定しています。
![スクリーンショット 2025-03-06 150034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2337552/8025e2a7-8aa6-49e4-a896-e8a7ca8a6355.png)

![スクリーンショット 2025-03-06 150123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2337552/efc9ada1-68bf-4d28-bb84-f34b496e20c2.png)

もう一つ、よく使われるクライアントとしてVisual Studio CodeのSnowflake拡張機能があります。こちらは接続メニューから「Sign in to another account」を選択してアカウント名を入力し、Continueして認証設定の画面が来たら「Auth Method」で「Key Pair」を選択し、ユーザー名と秘密鍵のパス（ここもパス区切りはスラッシュで）、秘密鍵のパスフレーズ（なければ空欄）を設定すればOKです。
![スクリーンショット 2025-03-06 163618.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2337552/51779a26-f434-49bf-a756-bca604906da2.png)
で、このGUIでの設定は特に問題ないと思うのですが、VS Code拡張ではもう一つ、設定ファイルのconnections.tomlを直接編集する（右上の鉛筆アイコンをクリックすると編集画面が開く）こともできます。私はここからやろうとしてハマったので情報を残しておきます。
直接編集ではこんな感じで設定を入力します。
```
["検証環境 キーペア認証"]
account = "xx00000.ap-northeast-1.aws"
user = "hirama"
authenticator = "SNOWFLAKE_JWT"
private_key_path = "c:/users/daisuke.hirama/rsa_key.p8"
```
この際、```authenticator```の値、```"SNOWFLAKE_JWT"```は、**必ず大文字で**入力してください。既存で登録されていたパスワード認証のauthenticatorは小文字で```snowflake```だったので、そのまま末尾に_jwtをつけたのですが、これがキーペア認証と認識されずに一人でハマってました。GUIで設定しなおし、追加された設定内容を見て初めて気づきました。お粗末。


長くなったので、SSOの設定についてはその2で書きます。