Snowflakeを使い始めた組織が最初につまずくのが、S3上のデータをどう安全に読み書きさせるか——外部ステージの認証設計です。手早く動かそうとすると CREATE STAGE にアクセスキーとシークレットを直接書き込みたくなりますが、その一行はDDLやメタデータに残り続け、後から回収するのが難しい負債になります。本記事では、キーを一切埋め込まずにSnowflakeとS3を結ぶ STORAGE INTEGRATION と AWS IAMロールの信頼関係(External ID)、そして最小権限のS3ポリシーの組み方を、EMWが検証環境で先に潰しておいた落とし穴とあわせて解説します。
01なぜ「認証」から設計を始めるのか
SnowflakeはAWS上で動くマネージドサービスで、テーブルの実体もSnowflakeが管理するS3に格納されています。一方、社内のデータレイクや他システムが書き出したファイルは、自社アカウントのS3バケットにあります。この自社バケットをSnowflakeから読み書きする窓口が「外部ステージ」です。外部ステージの認証には2通りあり、CREATE STAGE に CREDENTIALS=(AWS_KEY_ID=… AWS_SECRET_KEY=…) とアクセスキーを直接書く方法と、STORAGE INTEGRATION オブジェクトを介してIAMロールを引き受ける方法です。前者は動かすだけなら最短ですが、埋め込んだ認証情報がステージ定義やメタデータ・レプリケーション・バックアップに残り続け(DESC STAGE では AWS_SECRET_KEY の値こそマスクされますが AWS_KEY_ID は表示されます)、ローテーションも棚卸しも困難になります。だからこそ最初に決めるべきは「どうデータを載せるか」ではなく「どう認証を設計するか」です。
02STORAGE INTEGRATION の正体 — Snowflakeが払い出すIAMユーザー
STORAGE INTEGRATION はアカウント単位のオブジェクトで、作成には ACCOUNTADMIN か CREATE INTEGRATION 権限が必要です。TYPE = EXTERNAL_STAGE、STORAGE_PROVIDER = 'S3'、引き受け先の STORAGE_AWS_ROLE_ARN、そして許可するバケットやプレフィックスを列挙する STORAGE_ALLOWED_LOCATIONS を指定します。重要なのは、このオブジェクトを作るとSnowflakeが「あなたのアカウント専用のIAMユーザー」を裏で払い出す点です。その識別子は DESC INTEGRATION の STORAGE_AWS_IAM_USER_ARN と STORAGE_AWS_EXTERNAL_ID に現れます。1つのインテグレーションを起点に、複数の外部ステージが別々のバケットやパスを参照でき、認証情報を一元管理できます。鍵はどこにも登場しません。
Principal は共通化できますが、そのぶん取り違え防止はExternal IDに委ねられます。インテグレーションごとにExternal IDで識別する前提で設計しておくと、後から追加しても管理が破綻しません。03信頼関係の設計 — External ID で「取り違え」を封じる
IAMロール側には2つのポリシーが要ります。1つは「誰がこのロールを引き受けてよいか」を定める信頼ポリシー、もう1つは「引き受けたロールが何をできるか」を定める権限ポリシーです。信頼ポリシーの Principal にSnowflakeが払い出したIAMユーザーARNを、Action に sts:AssumeRole を、そして Condition に sts:ExternalId がインテグレーションのExternal IDと一致すること、を書きます。このExternal IDが肝です。SnowflakeのようなマルチテナントのSaaSでは、払い出されるIAMユーザーARNが顧客間で共通になり得ます。External IDがなければ、別テナントに自社ロールを引き受けられてしまう「confused deputy(取り違え)問題」が成立します。External IDは、AWSがサードパーティ連携で推奨している対策そのものです。
厄介なのは、CREATE OR REPLACE STORAGE INTEGRATION でExternal IDを指定せずに作り直すと、新しいExternal IDが再生成され、既存の信頼ポリシーと噛み合わなくなる点です。IaCで繰り返し適用する運用なら、STORAGE_AWS_EXTERNAL_ID を明示的に固定し、UUIDのような一意な値を自分で採番しておくと、再作成のたびに信頼ポリシーを直す事故を避けられます。
sts:AssumeRole。ロールは一時クレデンシャルで最小権限のS3操作だけを許される。鍵はどこにも保存されない。04「鶏と卵」を解く構築手順
信頼ポリシーにはSnowflakeのIAMユーザーARNが要りますが、そのARNはインテグレーションを作らないと分かりません。一方、インテグレーションにはロールARNが要ります。この鶏と卵は、順序で解きます。まず仮の信頼ポリシー(自アカウントを指す程度)でIAMロールを作成し、そのARNで CREATE STORAGE INTEGRATION を実行。次に DESC INTEGRATION で STORAGE_AWS_IAM_USER_ARN と STORAGE_AWS_EXTERNAL_ID を取得し、それらを信頼ポリシーに反映。最後に CREATE STAGE … STORAGE_INTEGRATION = … でステージを作り、LIST @stage で疎通を確認します。
DESC で取得→信頼ポリシー更新、の順で「鶏と卵」を解く。List や Get 段階で落ちます。CloudTrailの AssumeRole と AccessDenied を見れば、どちらのポリシーを直すべきか一目で分かります。05最小権限のS3ポリシーとAWS基盤との接続
権限ポリシーは用途で絞ります。読み取り専用なら s3:GetObject、s3:GetObjectVersion、そしてバケットに対する s3:ListBucket(s3:prefix 条件でパスを限定)で足り、アンロードするなら s3:PutObject、パージを許すなら s3:DeleteObject を足します。Resource は arn:aws:s3:::bucket/prefix/* のようにプレフィックスまで絞り込みます。加えてSnowflake側の STORAGE_ALLOWED_LOCATIONS(必要なら STORAGE_BLOCKED_LOCATIONS)が二段目のガードレールになり、IAMで許してもインテグレーションの許可リスト外は触れません。IAMとインテグレーション、どちらか片方の許可では成立しない二段構えにしておくのが安全です。
AWS基盤とはさらに要所で噛み合います。バケットをSSE-KMSで暗号化しているなら、ロールの権限ポリシーに kms:Decrypt と kms:GenerateDataKey を加え、KMSキーポリシー側でもそのロールを許可します。閉域で通したいなら、S3のGateway型/Interface型エンドポイント(PrivateLink)経由でトラフィックをVPC内に留められます。イベント駆動でロードするSnowpipeは、S3のイベント通知(SQS)でファイル到着を検知し、同じインテグレーションの認証で取り込みます。いずれも「鍵を配らずロールで束ねる」設計の自然な延長線上にあります。
06落とし穴:検証で先に踏み抜いた「キー直書き」と「過剰権限」
ある基盤構築のPoCで、まず動作確認を優先して CREATE STAGE にアクセスキーを直書きしたステージを作りました。検証の中で確認したのは、DESC STAGE では AWS_SECRET_KEY の値こそマスクされて出力されないものの、AWS_KEY_ID は表示され、そもそもキーを直書きした CREATE STAGE 文自体をGit管理のスクリプトへ取り込む運用にしていたため、認証情報がリポジトリに流れ込む経路が見えてしまった、という点です。Snowflakeも認証情報の直接埋め込みは避け、STORAGE INTEGRATION の利用を強く推奨しています。本番に持ち込む前に気づけたので、本番はすべて STORAGE INTEGRATION 方式に統一し、鍵を保持するステージはゼロにしました。もう1つは権限の過剰付与です。検証当初、切り分けを急いでロールに s3:* とバケット全体を許可したところ、意図していないプレフィックスにも書き込める状態だと分かりました。本番では読み取り系のみに絞り、プレフィックスと STORAGE_ALLOWED_LOCATIONS の二段で範囲を締め、アンロード用は別ロール・別インテグレーションに分離しました。いずれも検証段階で潰したため、本番の設計に傷を残していません。低コストの小規模導入から大規模基盤まで、この「検証で先に踏み抜く」進め方は共通しています。
—まとめ — キーを持たない設計を初期値に
外部ステージは「まず動かす」の誘惑が強い領域ですが、最初にキーを直書きするか、STORAGE INTEGRATION で組むかで、その後の棚卸し・ローテーション・監査のコストが大きく変わります。押さえるべきは3点です。(1)認証はロール引き受けに寄せ、鍵をDDLに残さない。(2)信頼ポリシーはExternal IDで取り違えを封じ、再作成時はExternal IDを固定する。(3)権限はIAMと STORAGE_ALLOWED_LOCATIONS の二段で最小化し、読み取りと書き込みは用途ごとに分ける。この3点を初期値にすれば、規模が小さいうちから安全側に倒したデータ基盤を積み上げられます。
参考情報(一次情報)
- Option 1: Configure a Snowflake storage integration to access Amazon S3 | Snowflake Documentation
- CREATE STORAGE INTEGRATION | Snowflake Documentation
- Create an S3 stage | Snowflake Documentation
- CREATE STAGE | Snowflake Documentation
- DESCRIBE STAGE | Snowflake Documentation
- ALTER STORAGE INTEGRATION | Snowflake Documentation
- Access to AWS accounts owned by third parties (External ID) - AWS IAM
- The confused deputy problem - AWS IAM
EMWはAWSとSnowflakeの両面から、キーを持たない外部ステージ設計と最小権限のデータ基盤構築を支援します。まずはお気軽にご相談ください。
相談する