Snowflake が段階的に「ユーザー名+パスワード」だけのサインインを廃止へと進めるなか、ASP.NET/.NET アプリ側の接続方式を見直す必要が出てきました。本記事では、.NET から安全に Snowflake へ接続するための実運用レベルの選択肢(鍵ペア認証/Programmatic Access Token/Workload Identity Federation)を整理し、手順・接続文字列・移行のコツをまとめて解説します。
Snowflake のパスワード廃止の背景と影響範囲
Snowflake はセキュリティ強化の一環として、単一要素のパスワードサインインを段階的に廃止しています。特にアプリケーションやサービス等の非対話ユーザー(TYPE=SERVICE)は、最終的にパスワードでの接続が不可となる計画です。人手によるサインイン(TYPE=PERSON)はパスワードを用いる場合、原則として MFA が必須化されます。現在の計画では、2025 年〜2026 年にかけて段階的な適用が続き、2026 年 10 月までに強固な認証への全面移行が完了する想定です。
- 対象の見極め:アプリ/バッチ/API 経由の接続は、従来の「ユーザー名+パスワード」からの移行が必須。
- 推奨アプローチ:Workload Identity Federation(WIF) > 鍵ペア認証 > Programmatic Access Token(PAT)の順で、運用要件に合わせて選定。
ASP.NET/.NET で選べるパスワードレス認証方式(比較)
| 方式 | 概要 | 主な設定手順(要点) | 接続文字列の要点 | メリット | 留意点 |
|---|---|---|---|---|---|
| 鍵ペア認証(Key Pair / SNOWFLAKE_JWT) | RSA/ECDSA の公開鍵・秘密鍵で署名し、パスワード不要で接続 | 1) OpenSSL で 2048bit 以上の鍵を生成 2) ALTER USER <user> SET RSA_PUBLIC_KEY='<publicKey>'3) .NET ドライバーを最新化 4) 接続文字列に AUTHENTICATOR=SNOWFLAKE_JWT と秘密鍵を指定 | AUTHENTICATOR=SNOWFLAKE_JWTPRIVATE_KEY_FILE または PRIVATE_KEY(必要に応じて PRIVATE_KEY_FILE_PWD) | 高い安全性/鍵ローテーションしやすい/オンプレでも可 | 秘密鍵の保護と配布が運用ポイント。改行やエンコードの扱いで接続エラーになりやすい |
| Programmatic Access Token(PAT) | Snowflake が発行する短命なトークンをパスワード欄に指定して接続 | 1) ALTER USER ADD PROGRAMMATIC ACCESS TOKEN で発行(必要なら ROLE_RESTRICTION を付与)2) トークン値を安全に保管(表示は作成時のみ) 3) 有効期限とローテーションの運用を準備 | PASSWORD=<token_secret>( AUTHENTICATOR の特別指定は不要) | 鍵管理が不要で導入が容易/GUI・SQL で発行・失効を制御可能 | 期限切れリスク/ローテーションの自動化が必須。ネットワークポリシーや役割制限の設計が重要 |
| Workload Identity Federation(WIF) | クラウドのネイティブ ID(Azure Managed Identity / AWS IAM / GCP SA 等)で秘密情報を保存せず接続 | 1) Snowflake 側で WIF を有効化し対象サービスユーザーを設定 2) 認証ポリシーで許可プロバイダーや発行者を制限 3) .NET ドライバーを WIF 対応版(4.8.0 以降推奨 5.x)に更新 4) 実行環境(例:Azure のユーザー割当て MI)は環境変数で ID を指示 | AUTHENTICATOR=WORKLOAD_IDENTITYWORKLOAD_IDENTITY_PROVIDER=AZURE|AWS|GCP|OIDC | 秘密情報の配布・保管が不要/最小権限と短命クレデンシャルで強固/CI/CD と相性良し | クラウド基盤の設定とバージョン要件を満たす必要。オンプレ単体運用には不向き |
接続文字列と C# 実装例
前提:.NET ドライバーのバージョン
- 鍵ペア認証/PAT:現行の Snowflake .NET ドライバー(4.x/5.x)で利用可能。最新版への更新を推奨。
- WIF:4.8.0 以降で対応(最新 5.x を推奨)。
鍵ペア認証(SNOWFLAKE_JWT)
鍵の作成(OpenSSL)
# 秘密鍵(非暗号化)
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
# 秘密鍵(暗号化)
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 des3 -inform PEM -out rsa_key.p8
# 公開鍵
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
公開鍵の登録(Snowflake)
ALTER USER app_user SET RSA_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----MIIBIj...';
.NET 接続文字列(ファイル指定)
// Windows のパスはエスケープ(\\)に注意
string connStr =
"account=ACME;" +
"user=app_user;" +
"authenticator=SNOWFLAKE_JWT;" +
"private_key_file=C:\\\\secrets\\\\rsa_key.p8;" +
"private_key_file_pwd=<必要ならパスフレーズ>" +
"role=SYSADMIN;warehouse=COMPUTE_WH;db=SALES;schema=PUBLIC;";
using var conn = new Snowflake.Data.Client.SnowflakeDbConnection();
conn.ConnectionString = connStr;
conn.Open();
.NET 接続文字列(秘密鍵を文字列で埋め込む)
string privateKeyPem = Environment.GetEnvironmentVariable("SF_PRIVATE_KEY_PEM")!;
// 改行は \n、Base64 の '=' は "==" になるケースに注意(ドライバーの仕様差分によりエスケープが必要)
string connStr =
"account=ACME;user=app_user;authenticator=SNOWFLAKE_JWT;" +
$"private_key={privateKeyPem};role=SYSADMIN;warehouse=COMPUTE_WH;db=SALES;schema=PUBLIC;";
つまずきやすいポイント
- 認証子の表記:一部のバージョンでは
authenticatorの値が大文字小文字に敏感でした。SNOWFLAKE_JWTと大文字で指定すると安全です。 - JWT 無効エラー:公開鍵の登録ミス、アカウント識別子/ユーザー名の不一致、システム時刻のずれが典型原因。サーバー時刻の同期も確認を。
- 鍵ローテーション:
RSA_PUBLIC_KEYとRSA_PUBLIC_KEY_2を併用して無停止で切替可能。更新後に古い鍵を UNSET。
Programmatic Access Token(PAT)
トークンの発行(Snowflake)
-- サービスユーザーの場合は ROLE_RESTRICTION を必須で指定するのが基本
ALTER USER app_user ADD PROGRAMMATIC ACCESS TOKEN app_token
ROLE_RESTRICTION = 'APP_ROLE'
DAYS_TO_EXPIRY = 15
COMMENT = 'app backend token';
-- 返される token_secret はこの時だけ表示。安全に保管すること
運用コマンド(例)
-- 有効なトークンの一覧
SHOW USER PROGRAMMATIC ACCESS TOKENS FOR USER app_user;
-- トークンのローテーション(新しい secret を発行し旧 secret を失効)
ALTER USER app_user ROTATE PROGRAMMATIC ACCESS TOKEN app_token;
.NET 接続文字列
string token = Environment.GetEnvironmentVariable("SF_APP_PAT")!;
string connStr =
"account=ACME;user=app_user;" +
$"password={token};" + // パスワード欄に token_secret をそのまま指定
"role=APP_ROLE;warehouse=APP_WH;db=SALES;schema=PUBLIC;";
using var conn = new Snowflake.Data.Client.SnowflakeDbConnection { ConnectionString = connStr };
conn.Open();
運用の勘所
- 期限管理:
DAYS_TO_EXPIRYで寿命を短く保ち、失効前に自動ローテーションするジョブを用意。 - 権限の絞り込み:
ROLE_RESTRICTIONを活用して、トークン利用時の権限を明示的に限定。 - 制約:PAT で認証した同一セッション内ではそのトークンのローテーションは不可。管理セッションを分離する。
Workload Identity Federation(WIF)
概要:アプリやコンテナが稼働する基盤(Azure/AWS/GCP/OIDC)のネイティブ IDで Snowflake に接続する方式。秘密鍵やトークンを保管・配布しないため、長期運用のセキュリティと運用負荷の両面で最有力の選択肢です。
前提:
- Snowflake 側:対象ユーザーは
TYPE=SERVICE、認証ポリシーで許可プロバイダーや発行者(テナント等)を制限。 - クライアント側:.NET ドライバーは 4.8.0 以降(推奨 5.x)。
Azure(Managed Identity)の例
- ユーザー割当て MI を使う場合、アプリ実行環境に
MANAGED_IDENTITY_CLIENT_IDを設定して ID を指示。
.NET 接続文字列(WIF)
string connStr =
"account=ACME;" +
"user=svc_app;" + // Snowflake のサービスユーザー
"authenticator=WORKLOAD_IDENTITY;" + // WIF を選択
"workload_identity_provider=AZURE;" + // 実行基盤を指定(AWS/GCP/OIDC も可)
"role=APP_ROLE;warehouse=APP_WH;db=SALES;schema=PUBLIC;";
using var conn = new Snowflake.Data.Client.SnowflakeDbConnection { ConnectionString = connStr };
conn.Open(); // 実行環境のネイティブ ID で秘密情報なしに認証
WIF の利点と設計ポイント
- シークレットレス運用:鍵・トークンの保管/配布が不要になり、漏えい面積を縮小。
- ゼロトラスト指向:発行者やアカウント単位で「どの基盤からの接続を許可するか」を認証ポリシーで厳密に制御。
- マルチクラウド:AWS IAM / Entra ID / GCP SA / OIDC を横断して同一の接続モデルで統一。
ユースケース別の推奨方針
| ユースケース | 推奨方式 | 理由 |
|---|---|---|
| クラウド常駐の API/バッチ/マイクロサービス | WIF | 秘密情報を持たずに接続。IdP と役割制御を一元化 |
| オンプレや閉域網からの常時接続 | 鍵ペア認証 | 鍵配布とローテーションを運用に組み込めば長期安定。依存が少ない |
| 導入初期・PoC・GUI 主体の利用 | PAT | 発行が簡単で学習コストが低い。後から WIF/鍵へ移行しやすい |
移行ステップ(.NET 観点の実務ガイド)
- 影響範囲の棚卸し:接続文字列をスキャンし、パスワード利用の箇所とサービスユーザーを洗い出し。
- 方式の選定:稼働基盤・保守体制・監査要件を踏まえて WIF / 鍵 / PAT をアプリ単位で決定。
- ドライバー更新:Snowflake .NET ドライバーを最新(推奨 5.x)へ。テストから先行適用。
- 認証ポリシー設計:WIF の許可プロバイダー、PAT の
ROLE_RESTRICTION、鍵のローテーション頻度を定義。 - シークレット管理:鍵・PAT は必ず Secrets/Key Vault/Parameter Store 等に格納し、アプリには環境変数で注入。
- 監視実装:PAT の期限(
SHOW USER PROGRAMMATIC ACCESS TOKENS)や接続エラーを監視。期限アラート&自動ローテーションを投入。 - 段階的切替:ステージング → カナリア → 本番。鍵は
RSA_PUBLIC_KEY_2を使い無停止で差し替え。
セキュリティ実装のベストプラクティス
- サービスユーザー化:アプリ用ユーザーは
TYPE=SERVICEとし、人手ログインと混在させない。 - 最小権限:アプリごとに専用ロールを作成し、
ROLE_RESTRICTIONで PAT の権限を拘束。二次ロールへの依存を避ける。 - ネットワーク制御:必要に応じてネットワークポリシーで PAT の利用元を限定。
- 可観測性:クエリタグ(
QUERY_TAG)でアプリ別に可視化。ログと監査証跡を関連付ける。 - 鍵の保管:秘密鍵はファイル権限を最小化し、配布にはセキュアストアを使用。CI/CD ではアーティファクトに混入させない。
.NET 固有のトラブルと対処集
| 症状 | 原因の多く | 対処 |
|---|---|---|
JWT token is invalid | 公開鍵未登録/ユーザー不一致/アカウント識別子のミス/時刻ずれ | 公開鍵を再設定、account と user を再確認、時刻同期 |
Could not read private key ... incorrect private key format | 改行コードや = の扱い、PKCS#8 以外の形式 | -----BEGIN ...----- 形式の PEM/PKCS#8 を使用。文字列埋め込み時は \n と = エスケープに注意 |
| WIF で接続不可 | ドライバー未更新/許可プロバイダー未設定/Azure のユーザー割当て MI の Client ID 未指定 | .NET ドライバーを 4.8.0+ に更新、authenticator=WORKLOAD_IDENTITY/WORKLOAD_IDENTITY_PROVIDER を指定、MANAGED_IDENTITY_CLIENT_ID を設定 |
| PAT の期限切れ | ローテーション運用の未整備 | 期限前アラートと自動ローテーション(管理セッション)を導入 |
実装サンプル(最小構成の C#)
using System.Data;
using Snowflake.Data.Client;
public static class SnowSample
{
public static void RunWithKeyPair()
{
var cs = "account=ACME;user=app_user;authenticator=SNOWFLAKE_JWT;" +
"private_key_file=C:\\secrets\\rsa_key.p8;" +
"role=APP_ROLE;warehouse=APP_WH;db=SALES;schema=PUBLIC;";
using var conn = new SnowflakeDbConnection { ConnectionString = cs };
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "select current_user(), current_role(), current_version()";
using var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine($"{rdr.GetString(0)} / {rdr.GetString(1)} / {rdr.GetString(2)}");
}
}
public static void RunWithPAT()
{
var token = Environment.GetEnvironmentVariable("SF_APP_PAT")!;
var cs = "account=ACME;user=app_user;" +
$"password={token};role=APP_ROLE;warehouse=APP_WH;db=SALES;schema=PUBLIC;";
using var conn = new SnowflakeDbConnection { ConnectionString = cs };
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "call system$wait(1)"; // 簡易ダミー
cmd.ExecuteNonQuery();
}
public static void RunWithWIF()
{
var cs = "account=ACME;user=svc_app;authenticator=WORKLOAD_IDENTITY;" +
"workload_identity_provider=AZURE;role=APP_ROLE;warehouse=APP_WH;db=SALES;schema=PUBLIC;";
using var conn = new SnowflakeDbConnection { ConnectionString = cs };
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "select current_account(), current_region()";
using var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine($"{rdr.GetString(0)} / {rdr.GetString(1)}");
}
}
}
移行チェックリスト(貼って使える)
- 接続先アカウント識別子(
<org>-<account>等)を全アプリで統一/明示。 - .NET ランタイムと Snowflake .NET ドライバーの互換性確認(ターゲットフレームワーク、ネイティブ依存なし)。
- WIF を採用する場合、対象サービスユーザーを
TYPE=SERVICEとし、認証ポリシーで許可するプロバイダーと発行者を限定。 - 鍵ペアの場合、鍵生成・配布・回収・保管の RACI とローテーション頻度を決定。
RSA_PUBLIC_KEY_2を用いた無停止切替手順を文書化。 - PAT の場合、
DAYS_TO_EXPIRYとローテーション自動化(失効前 N 日での再発行)を実装。ROLE_RESTRICTIONで権限を限定。 - CI/CD で秘密情報を扱う場合、リポジトリに残らない設計(環境変数注入・マスキング出力)とレビューゲートを設定。
- 監査・運用:接続失敗の検知(メトリクス/アラート)、ユーザー/ロールの棚卸し、不要トークンの削除。
まとめ:.NET からの最適解
パスワード廃止の流れに合わせ、まずは WIF によるシークレットレス接続を第一候補として検討し、基盤や要件の都合で難しい場合は鍵ペア認証、導入初期や簡便さを重視する場合にPATを選ぶ、という優先順位が現実解です。どの方式も .NET 側は接続文字列の変更で対応でき、移行自体は難しくありません。大切なのは「鍵/トークンの運用(保管・期限・ローテーション)」「認証ポリシーでの制限」「監視」の 3 点を最初から組み込むことです。これらを押さえれば、Snowflake への .NET 接続は安全かつ長期安定で運用できます。
付録:簡易レシピ
鍵ペア認証の 3 ステップ
- OpenSSL で
rsa_key.p8とrsa_key.pubを作成。 ALTER USER app_user SET RSA_PUBLIC_KEY='<pub>'。authenticator=SNOWFLAKE_JWT; private_key_file=...を接続文字列に追加。
PAT の 3 ステップ
ALTER USER ADD PROGRAMMATIC ACCESS TOKEN app_token ROLE_RESTRICTION='APP_ROLE' DAYS_TO_EXPIRY=15。- 出力された
token_secretを安全に保管。 - 接続文字列の
password=にtoken_secretを設定。
WIF の 3 ステップ
- Snowflake で WIF と認証ポリシーを設定し、サービスユーザーに適用。
- .NET ドライバーを 4.8.0+(推奨 5.x)へ更新。
authenticator=WORKLOAD_IDENTITY; workload_identity_provider=<AZURE|AWS|GCP|OIDC>を接続文字列に設定。
Q&A:最初に何を選べばよい?
クラウド常駐のモダンワークロードなら WIF 一択。オンプレや閉域でクラウドの IdP を使いづらいなら、鍵ペア認証が堅実です。まずは開発・検証環境で新方式を導入し、エラー監視と期限アラートを整えてから本番に切り替えるのが安全です。

コメント