Snowflakeで秘密鍵を環境変数に格納して認証する
Snowflake ではキーペア認証ができる。
dbt や Terraform などで Snowflake を組み合わせる際には当然認証情報を渡す必要がある。キーペア認証をする場合には基本的には
- private key そのもの
- private key のファイルのパス
のどちらかを渡すことになる。
例えば dbt コマンドを AWS ECS 上で実行するといったことを考えると、 private key そのものを Secrets として環境変数に設定しておき、それを利用してキーペア認証をするといったことがやりたくなる。しかし、 private key そのものを環境変数として格納して使う場合には、利用するライブラリによって渡し方を気をつけないといけないので、そのポイントを紹介する。
秘密鍵のフォーマット PEM について
PEM はいわゆる以下のような鍵などのファイルのエンコーディング形式のこと。
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjffw/G1CpgJsP
ecZMT5b0KOo3dFLYn3jGgenIBjvJEEGGp6bQe4/AaZh5AmSxzi5MWYGiY7OEuPwz
...
ias/p13y8Pms8BI4c4fHqVM=
-----END PRIVATE KEY-----
詳細は RFC 7468 で定義されている。
秘密鍵関連の細かい話は別の記事も書いているので参照してください。
PEM形式の鍵を読み込むにはまずヘッダー -----BEGIN{label}-----
とフッター -----END{label}-----
を取り除き、64文字ごとに改行されている文字列を連結して、 Base64 でデコードする、という流れが必要になる。
なんらかのライブラリで秘密鍵をそのまま渡して Snowflake の認証をする際には、そのライブラリが上記の処理をやってくれるのかどうかで渡し方が変わってくる。つまり、
- PEM 形式の鍵をそのまま渡す
- ヘッダー・フッターを取り除き、改行も削除して
MIIE...
という一行の長い文字列にして( Base64 でデコードする直前まで整形して)渡す
のどちらかに基本的にはなる。
dbt-snowflake での秘密鍵の取り扱い
dbt-snowflake の private_key
の取り扱いを見てみるとこんな感じ。
private_key
を直接 base64 でデコードしている。
よって、「ヘッダー・フッターを取り除き、改行も削除して MIIE...
という一行の長い文字列」を private_key
として渡す必要がある。
terraform-provider-snowflake での秘密鍵の取り扱い
terraform-provider-snowflake の private_key
の取り扱いを見てみるとこんな感じ。
private_key
を標準ライブラリの encoding/pem
の Decode 関数を使って読み込んでいる。
よって、 PEM 形式の鍵をそのまま private_key
として渡せば良い。
snowflake-connector-python での秘密鍵の取り扱い
snowflake-connector-python でも private_key
は利用できる。公式ドキュメントには秘密鍵のファイルパスを渡して読み込む例が記載されている。
実際に認証する部分を確認するとこんな感じ。
private_key
は bytes で渡さないといけないことがわかるので、自分で base64 でデコードした上で渡す必要がある。
例えば export SNOWFLAKE_PRIVATE_KEY='MIIE....'
と秘密鍵を一行にして環境変数に設定しておき、以下のようなコードを書けば認証が通る。
import base64
import os
import snowflake.connector
SNOWFLAKE_ACCOUNT = os.environ['SNOWFLAKE_ACCOUNT']
SNOWFLAKE_PRIVATE_KEY = os.environ['SNOWFLAKE_PRIVATE_KEY']
SNOWFLAKE_USER = os.environ['SNOWFLAKE_USER']
ctx = snowflake.connector.connect(
account=SNOWFLAKE_ACCOUNT,
user=SNOWFLAKE_USER,
private_key=base64.b64decode(SNOWFLAKE_PRIVATE_KEY),
)
with ctx.cursor() as cs:
cs.execute("SELECT current_version()")
one_row = cs.fetchone()
print(one_row[0])
# 7.21.1
まとめ
キーペア認証で秘密鍵を直接渡したいときには、各ライブラリの実装によって渡すべきものが変わるので注意しましょう。
Snowlfake データクラウドのユーザ会 SnowVillage のメンバーで運営しています。 Publication参加方法はこちらをご参照ください。 zenn.dev/dataheroes/articles/db5da0959b4bdd
Discussion