AWS

EC2からSnowflake に接続する:snowflake-connector-pythonの要点(認証・ネットワーク)

numa

はじめに

こんにちは、北海道生活をエンジョイしているぬまです。今回初めて案件の中でSnowflakeを利用しましたので、AWSとの連携についてアプリケーションレイヤーの観点から学んだことをブログにしました。

この記事でわかること

  • パッケージの役割とインストールについて
  • ユーザー名・パスワードでの最小構成の接続とクエリ実行の例を示します。
  • EC2 への認証方法であるキーペア(JWT)と Workload Identity(AWS IAM)の違いと接続コード
  • インスタンスから Snowflake へのアウトバウンドポート設定
  • マルチスレッド時の推奨

1. 概要とインストール

1.1 概要

項目内容
パッケージ名snowflake-connector-python
役割Snowflake に接続し、クエリ実行やデータ転送などを行う公式の Python 用コネクタです。
規格Python Database API v2(PEP-249)に準拠し、ConnectionCursor で操作します。
前提Python 3.9 以上が必要です(3.9 は非推奨のため、3.10 以上の使用が推奨されます)。

1.2 インストール

pip install snowflake-connector-python

AWS 連携(S3 ステージなど)を使わない場合は、boto3 を入れずにインストールできます。

SNOWFLAKE_NO_BOTO=true pip install snowflake-connector-python

2. 基本的な使い方

2.1 接続(ユーザー名・パスワード)

import snowflake.connector

conn = snowflake.connector.connect(
    user="<ユーザー名>",
    password="<パスワード>",
    account="<アカウント識別子>",  # xxx.yyy 形式。snowflakecomputing.com は含めない
    warehouse="<ウェアハウス>",
    database="<DB>",
    schema="<スキーマ>",
)

2.2 クエリ実行

cur = conn.cursor()
cur.execute("SELECT CURRENT_USER(), CURRENT_ROLE()")
rows = cur.fetchall()

2.3 接続のクローズ

conn.close()

コンテキストマネージャを使って閉じることもできます。

1with snowflake.connector.connect(...) as conn:
2    cur = conn.cursor()
3    cur.execute("SELECT 1")

3. 認証方式(EC2 でよく使うもの)

方式用途
キーペア認証パスワードを置かず、ローテーションしやすい
Workload Identity(AWS)EC2 の IAM ロールで認証し、長期クレデンシャルをAWS上に置かなくて済む

EC2 では Workload Identity(AWS IAM) を第一候補にするのがよいです。

3.1 キーペア認証(SNOWFLAKE_JWT

  • 2048 ビット以上の RSA(PEM)または ECDSA をサポートします。
  • 秘密鍵は暗号化・非暗号化のどちらも利用できます。
conn = snowflake.connector.connect(
    account="<account>",
    user="<user>",
    authenticator="SNOWFLAKE_JWT",
    private_key_file="<秘密鍵のパス>",
    private_key_file_pwd="<パスフレーズ>",  # ある場合
    warehouse="<wh>",
    database="<db>",
    schema="<schema>",
)

Snowflake 側のユーザーに公開鍵を登録する必要があります(キーペア認証の公式ドキュメントを参照してください)。

3.2 Workload Identity(AWS IAM)

EC2 に IAM ロール(インスタンスプロファイル)を付与し、そのロールで Snowflake に認証します。長期のパスワードや秘密鍵を EC2 に置かずに済みます

Snowflake 側(ACCOUNTADMIN など)

  1. AWS IAM で Snowflake 用のロールを作成し、Snowflake が AssumeRole できるように信頼ポリシーを設定します。
  2. セキュリティ統合を作成します。

ユーザー作成の例です(実際の構文・必須項目は環境とバージョンに合わせて公式ドキュメントで確認してください)。

1CREATE USER <snowflake_user>
2  WORKLOAD_IDENTITY = (
3    TYPE = AWS
4    ARN = '<amazon_resource_identifier>'  -- EC2 に付与している IAM ロール
5  )
6  TYPE = SERVICE
7  DEFAULT_ROLE = PUBLIC;  -- Snowflake 側のロール(AWS IAM ロールではない)

EC2 側

  • 上記 ARN に対応する IAM ロールを、EC2 のインスタンスプロファイルに紐付けます。
  • そのロールに、Snowflake のドキュメントが示す AssumeRole 用の権限を付与します。
1{
2  "Version": "2012-10-17",
3  "Statement": [
4    {
5      "Effect": "Allow",
6      "Principal": {
7        "Service": "ec2.amazonaws.com"
8      },
9      "Action": "sts:AssumeRole"
10    }
11  ]
12}

注意: Snowflake が顧客の IAM ロールを AssumeRole して引き受けるのは、ストレージ統合の話と混同しやすいです。Workload identity federation(WIF) で EC2 から接続するだけなら、EC2 ロールに「Snowflake 用の AssumeRole 権限」を追加する必要はありません。

Python

conn = snowflake.connector.connect(
    account="<account>",
    user="<snowflake_user>",  # 先ほど作成した Snowflake ユーザー
    authenticator="WORKLOAD_IDENTITY",
    workload_identity_provider="AWS",
    warehouse="<wh>",
    database="<db>",
    schema="<schema>",
)

コネクタが EC2 のメタデータから一時クレデンシャルを取得し、Snowflake と連携します。


4. EC2 からの接続:ネットワーク

4.1 アウトバウンドで必要なもの

  • ポート 443(HTTPS): Snowflake 本番接続用です。必須です。
  • ポート 80: OCSP(証明書失効チェック)用です。閉じていると OCSP 関連のエラーになることがあります。

ファイアウォールやプロキシで絞る場合は、上記に加えて利用リージョン・Private Link などの要件を、Snowflake のネットワーク要件(公式)で個別に確認してください。


5. マルチスレッドと接続・セッションの扱い

Snowflake のドライバーは ステートフルな接続 を使います。接続とセッションは 1 対 1 で、セッションには既定のデータベース・スキーマ・ロール・各種パラメータが紐づきます。

そのため 複数スレッドで同じ接続やセッションを共有・再利用しない方が良いです。オーバーヘッド削減のために共有しようとすると、次のような不具合の原因になる可能性があります(複数のスレッド間でセッションや接続を再利用する場合の考慮点 より)。

観点共有したときに起き得ること
セッション状態あるスレッドが USE DATABASE などでコンテキストを変えると、他スレッドにも影響する
トランザクション同一セッション上で複数スレッドが関与すると、コミット/ロールバックのタイミングで意図しない永続化・消失が起きる可能性がある
シーケンスカウンタードライバーが再試行に使うカウンタがセッション単位のため、スレッド間で競合し挙動が読みにくくなる
クエリコンテキストキャッシュセッション内でクエリが同時実行されると、キャッシュまわりで不整合が出る可能性がある
最後のクエリ ID並列実行時に「最後のクエリ ID」の解釈が競合する

実装の指針

  • 基本方針: スレッド(または async タスクなど並行単位)ごとに 別の接続 を使います。
  • 認証回数を減らしたい場合: Snowflake は 接続プール の利用を推奨しています。プールに戻す接続はセッションを閉じずに再利用できますが、返却前に アクティブなトランザクションをコミットまたはロールバック してください。また、接続プールでも クエリや DB にだけ効くパラメータUSE DATABASEUSE SCEMA)を変えっぱなしにしないよう注意してください。
  • 非同期クエリ: 1 接続で複数の非同期クエリを同時に走らせたり、非同期実行中に同期クエリを混ぜたりすると競合する可能性がありますので、ドキュメントの注意事項に従ってください。
  • どうしてもスレッド間で共有する場合(非推奨): ドキュメントでは DisableQueryContextCachetrue にしてクエリコンテキストキャッシュを無効にすることなどが触れられています。設計は公式の該当ページで確認してください。

Python Connector 固有のスレッド/プールの詳細は、Python Connector のドキュメント および上記の ドライバ共通の接続・スレッド のページを参照してください。


最後に

今回は私がEC2とSnowflakeの接続をする際に必要となった情報をまとめました。認証方式にWIFを使うことでSnowflakeへの接続が安全かつ管理しやすくなると思いました。

最後まで読んでいただきありがとうございました。

参考(公式)

AUTHOR
numa
numa
記事URLをコピーしました