ARCHININGEN TECH BLOG
← 記事一覧へ戻る

Snowflake のセキュリティ設計 — ネットワーク制限と認証ポリシー

CONTENTS

Snowflake の入口を 2 層で絞るセキュリティ構成図。上部に人間ユーザー (Snowsight・ドライバ) とサービスユーザー (パイプライン・BI) の 2 つの接続元。第 1 層のネットワーク層では network rule (オフィス IP・VPN IP) を network policy に束ねて許可を宣言し、適用レベルは user > integration > account の順で具体的な方が優先される。許可外の接続元はここで遮断。第 2 層の認証層には authentication policy (認証方式を絞り人間は MFA 必須)・password policy (長さ・試行回数・ロックアウト)・session policy (アイドルタイムアウト) が並び、弱い認証はここで拒否。2 層を通った接続だけが Snowflake アカウントに届く

2026 年 8 月、Snowflake の「単一要素パスワード認証の廃止」ロードマップは最終段階に入りました。2025 年 9 月から段階的に進んできた MFA の強制化は、この 8 月から 10 月にかけて既存ユーザーを含むすべてのユーザーへ適用されます。「うちのアカウントはまだパスワードだけで入れるから大丈夫」という状態は、放っておいてもあと数ヶ月で強制的に終わります。

背景にあるのは 2024 年に相次いだ Snowflake 環境への不正アクセスです。攻撃の主因は Snowflake 本体の脆弱性ではなく、マルウェア等で盗まれたパスワードによる単一要素ログインでした。どこからでも接続でき、パスワード 1 つで入れるアカウントは、認証情報が漏れた瞬間に終わります。逆に言えば、接続元と認証方式を絞ってあれば、パスワードが漏れただけでは侵入は成立しません。

本記事では、Snowflake アカウントの入口の防御を 「どこから来られるか」(ネットワーク制限) と「誰としてどう入るか」(認証ポリシー) の 2 層に分解して設計します。network rule / network policy によるネットワーク制限と、authentication / password / session policy による認証の縛り、そして自分を締め出さずに段階適用する手順までを扱います。特定のクラウドには依存しない内容です。RBAC やマスキングといったデータアクセス側の制御、PrivateLink による閉域構成は本記事のスコープ外とします。

全体像 — 入口を 2 層で絞る

冒頭の図が本記事の全体像です。接続はまず第 1 層のネットワーク制限で「許可された場所から来ているか」を検査され、次に第 2 層の認証ポリシーで「許可された方式で認証しているか」を検査されます。両方を通った接続だけがアカウントに届きます。

設計の前提として押さえておきたいのが、Snowflake のポリシーはどれも**「作る」と「適用する」が分離している**ことです。ポリシーは独立したオブジェクトとして作成し、それをアカウント・ユーザーなどのレベルに後から取り付けます (attach)。この分離のおかげで、同じポリシーをまず特定ユーザーに当てて試し、問題なければアカウント全体へ昇格する、という段階適用が自然にできます。本記事の手順はすべてこの型に沿っています。

もうひとつ、置き場所の癖を先に知っておくと迷いません。network policy だけがアカウントレベルのオブジェクトで、それ以外 (network rule・authentication policy・password policy・session policy) はすべてスキーマレベルのオブジェクトです。つまりデータベースとスキーマの中に置く必要があるので、セキュリティ設定の置き場を最初に決めておきます。

SQL
-- ポリシー系オブジェクトの置き場を先に用意する (SECURITYADMIN 系ロールの管理下に置く)
CREATE DATABASE IF NOT EXISTS security_admin;
CREATE SCHEMA IF NOT EXISTS security_admin.policies;

ネットワーク制限の部品 — network rule

ネットワーク制限の最小部品が network rule です。かつては network policy に ALLOWED_IP_LIST として IP を直書きしていましたが、現在は新規のポリシーには network rule を使うことが公式に推奨されています。IP のリストを「オフィス」「VPN」といった意味のある単位に分けて名前を付けられるため、変更時にどのリストを触ればよいかが自明になるのが利点です。

SQL
-- 接続元の意味ごとに rule を分けて作る (CIDR 表記と単一 IP を混在できる)
CREATE NETWORK RULE security_admin.policies.corp_office
  TYPE = IPV4
  MODE = INGRESS
  VALUE_LIST = ('203.0.113.0/24');

CREATE NETWORK RULE security_admin.policies.corp_vpn
  TYPE = IPV4
  MODE = INGRESS
  VALUE_LIST = ('198.51.100.10', '198.51.100.11');

MODE = INGRESS が「外からの接続」を対象にする指定です (EGRESS は外部ネットワークアクセス用で本記事では使いません)。TYPE には IPV4 のほか、AWS の VPC エンドポイント ID や Azure の Private Link 識別子を指定するタイプもあり、閉域構成へ進む場合も同じ枠組みの延長で設計できます。

network policy の組み立てと適用

作った rule を network policy に束ねます。policy は許可リスト (ALLOWED_NETWORK_RULE_LIST) と遮断リスト (BLOCKED_NETWORK_RULE_LIST) を持ちますが、許可リストだけで組むのが基本形です。許可リストを設定した時点で、そこに含まれない接続元はすべて遮断されるためです。遮断リストは「許可した範囲の中から特定の IP だけ弾きたい」という例外処理に限って使います。

SQL
-- rule を束ねて「この 2 つの経路だけ許可する」と宣言する
CREATE NETWORK POLICY corp_only
  ALLOWED_NETWORK_RULE_LIST = (
    'security_admin.policies.corp_office',
    'security_admin.policies.corp_vpn'
  );

適用は 3 つのレベルから選べます。同時に設定されている場合は具体的なレベルが優先され、user レベル > security integration レベル > account レベルの順で、最も具体的なポリシー 1 つだけが評価されます。

SQL
-- アカウント全体の既定ポリシーとして適用する
ALTER ACCOUNT SET NETWORK_POLICY = corp_only;

-- 特定ユーザーだけ別の経路を許可する (account レベルより優先される)
ALTER USER partner_analyst SET NETWORK_POLICY = partner_only;

この優先順位は「account で全体を縛り、例外だけ user で上書きする」という設計を可能にする一方で、後述する躓きポイントの温床でもあります。user レベルのポリシーは account レベルを置き換える (加算ではない) ことを覚えておいてください。

自分を締め出さないために

ネットワーク制限で誰もが一度は心配するのが「自分を締め出さないか」です。Snowflake には保護機構があり、現在の接続元 IP が許可リストに含まれないポリシーをアカウントや自分自身に適用しようとするとエラーになります。つまり「適用した瞬間に全員締め出し」は起こりにくい設計です。

とはいえ保護機構に頼り切らず、適用前の確認と段階適用を踏むのが安全です。

SQL
-- いま自分がどの IP から接続しているかを確認する
SELECT CURRENT_IP_ADDRESS();

手順は 3 段階をおすすめします。まず上記で自分の接続元 IP が許可リストに入っていることを確認し、次に自分のユーザーだけに user レベルで適用して各クライアント (Snowsight・ドライバ・BI ツール) からの接続を一通り試し、最後に account レベルへ昇格して user レベルの設定を外します。

SQL
-- 段階適用: まず自分だけに当てて試す → 問題なければ account へ昇格
ALTER USER my_admin SET NETWORK_POLICY = corp_only;
ALTER ACCOUNT SET NETWORK_POLICY = corp_only;
ALTER USER my_admin UNSET NETWORK_POLICY;

-- いま account に効いているポリシーを確認する
SHOW PARAMETERS LIKE 'network_policy' IN ACCOUNT;

オフィスの回線更改などで egress IP が変わる日は、旧 IP と新 IP を両方 rule に入れておき、切り替え後に旧 IP を消す、という重ね方をすれば無停止で移行できます。rule と policy が分離しているおかげで、この操作は ALTER NETWORK RULEVALUE_LIST 変更だけで済みます。

認証ポリシー — 2026 年の MFA 強制を前提に

第 2 層は「誰としてどう入るか」です。まず前提として、冒頭で触れた Snowflake の MFA 強制化ロードマップを整理します。

時期 内容
2025 年 9 月〜2026 年 1 月 パスワードで Snowsight にログインする人間ユーザーに MFA 必須
2026 年 5 月〜7 月 新規作成の人間ユーザーは全経路で MFA 必須。LEGACY_SERVICE タイプの新規作成が不可に
2026 年 8 月〜10 月 既存を含む全人間ユーザーにパスワード利用時の MFA 必須。サービスユーザーはキーペア・OAuth・PAT・WIF のみに

重要なのは、これが「推奨」ではなく順次強制される既定値の変更だということです。したがって認証ポリシーの設計は「MFA を導入するかどうか」の検討ではなく、「どうせ強制される要件を、自分のアカウントに合った形で先回りして宣言しておく」作業になります。強制が来てから慌てて対応するのと、ポリシーとして自分で書いておくのとでは、例外の把握と移行の計画性がまったく違います。

その宣言の器が authentication policy です。許可する認証方式・MFA の要求・対象クライアントを 1 つのオブジェクトにまとめます。

SQL
-- 人間ユーザー向け: SSO を主経路にしつつ、パスワード利用時は MFA を強制する
CREATE AUTHENTICATION POLICY security_admin.policies.human_auth
  AUTHENTICATION_METHODS = ('SAML', 'PASSWORD')
  MFA_ENROLLMENT = REQUIRED
  MFA_AUTHENTICATION_METHODS = ('PASSWORD')
  CLIENT_TYPES = ('SNOWFLAKE_UI', 'DRIVERS');

-- account の既定として適用する (network policy と同じく user レベルが優先)
ALTER ACCOUNT SET AUTHENTICATION POLICY security_admin.policies.human_auth;

AUTHENTICATION_METHODS が許可する認証方式の許可リストで、MFA_ENROLLMENT = REQUIRED が MFA 登録の強制、MFA_AUTHENTICATION_METHODS が「どの方式で入るときに第 2 要素を要求するか」の指定です。IdP を導入済みなら SSO (SAML) を主経路にして IdP 側の MFA に寄せ、Snowflake 側のパスワードは非常口として MFA 付きで残す、という上記の形が組みやすいはずです。第 2 要素にはパスキーや TOTP アプリも使えるようになっており、以前のように Duo 一択ではありません。

人間とサービスでユーザータイプを分ける

MFA 強制で必ず問題になるのが「パイプラインや BI ツールが使う機械のユーザーはどうするのか」です。機械は MFA のプッシュ通知に応答できません。Snowflake の答えはユーザーの TYPE プロパティによる分離で、人間は PERSON、機械は SERVICE と宣言します。SERVICE タイプのユーザーはそもそもパスワードを持てず、MFA の対象外になる代わりに、キーペア・OAuth・PAT (Programmatic Access Token)・WIF (Workload Identity Federation) といった機械向けの強い認証だけが許可されます。

SQL
-- サービスユーザーはパスワードレスの TYPE = SERVICE で作る
CREATE USER etl_loader
  TYPE = SERVICE
  DEFAULT_ROLE = etl_role
  RSA_PUBLIC_KEY = 'MIIBIjANBgkq...';

-- 認証方式もポリシーで明示しておく (user レベルは account レベルを上書きする)
CREATE AUTHENTICATION POLICY security_admin.policies.service_auth
  AUTHENTICATION_METHODS = ('KEYPAIR', 'OAUTH');
ALTER USER etl_loader SET AUTHENTICATION POLICY security_admin.policies.service_auth;

移行期の妥協案だった LEGACY_SERVICE タイプ (パスワードを使い続けられる機械ユーザー) は、2026 年 5 月から新規作成できなくなっており、8 月からの最終段階で廃止されます。まだ残っているなら、認証方式をキーペア等へ切り替えた上で TYPE = SERVICE への変更が必須です。「人間か機械か」を全ユーザーについて宣言し終えることが、MFA 強制時代の認証設計の土台になります。タイプ未設定 (NULL) のユーザーは人間扱いで MFA 強制の対象になるため、機械ユーザーが紛れていると強制適用の日にパイプラインが止まります。

スクリプト接続には PAT を発行する

認証を締めると、今度は日常の作業が困ります。典型が「人間ユーザーが手元のスクリプトや notebook から接続したい」場面です。MFA を強制した人間ユーザーのパスワードをスクリプトに書いても、第 2 要素の承認に人が応答しなければならず自動化になりません。かといって作業のたびにサービスユーザーを作るのも大げさです。

この隙間を埋めるのが PAT (Programmatic Access Token) です。ユーザーに紐づく有効期限付きのトークンで、ドライバやコネクタの password 欄にそのまま渡してパスワードの代わりに使えます。MFA の対話は発生しません。

使うには前提が 2 つあります。1 つ目は、そのユーザーに効いている authentication policy が PROGRAMMATIC_ACCESS_TOKEN を許可していることです。

SQL
-- 認証方式の許可リストに PAT を追加する
ALTER AUTHENTICATION POLICY security_admin.policies.human_auth
  SET AUTHENTICATION_METHODS = ('SAML', 'PASSWORD', 'PROGRAMMATIC_ACCESS_TOKEN');

2 つ目は、そのユーザーに network rule ベースの network policy が適用されていることです。これは PAT の既定の必須要件で、「MFA を省略する代わりに接続元で縛る」という設計になっています。第 1 層のネットワーク制限を先に整備しておくと、PAT はその上に自然に載ります。本記事で ネットワーク → 認証 の順を採ったのはこのためでもあります。

発行はユーザー自身 (または管理者) が実行します。

SQL
-- 有効期限とロール制限を付けて発行する (シークレットの表示は発行時の一度きり)
ALTER USER my_analyst ADD PROGRAMMATIC ACCESS TOKEN pat_notebook
  ROLE_RESTRICTION = 'ANALYST'
  DAYS_TO_EXPIRY = 30;

ROLE_RESTRICTION はトークンで入ったセッションが使えるロールを 1 つに固定する指定で、サービスユーザーでは必須、人間ユーザーでは任意です。任意でも付けることをおすすめします。トークンが漏えいしたときの影響を、そのユーザーの全ロールではなく指定ロール 1 つに限定できるからです。返ってきたトークンシークレットは再表示できないので、その場でシークレットマネージャ等に保存します。使う側は接続情報の password をトークンに置き換えるだけです。

PYTHON
# Python コネクタの例: password 欄に PAT のシークレットを渡す
conn = snowflake.connector.connect(
    account="myorg-myaccount",
    user="my_analyst",
    password=pat_secret,  # 環境変数やシークレットマネージャから読む
)

運用面では、有効期限はデフォルト 15 日・最大 365 日で、authentication policy の PAT_POLICY で上限を組織のルールに合わせて短縮できます。棚卸しと失効の SQL も押さえておきます。

SQL
-- 発行済みトークンの棚卸し・ローテーション・失効
SHOW USER PROGRAMMATIC ACCESS TOKENS FOR USER my_analyst;
ALTER USER my_analyst ROTATE PROGRAMMATIC ACCESS TOKEN pat_notebook;
ALTER USER my_analyst REMOVE PROGRAMMATIC ACCESS TOKEN pat_notebook;

1 ユーザーが持てるトークンは最大 15 本です。無期限の認証情報を配る代わりに「短命のトークンを必要なときに発行し、期限切れで自然に死ぬ」運用へ寄せるのが PAT の趣旨なので、DAYS_TO_EXPIRY は用途に対して欲張らず短めに切るのがおすすめです。

password policy と session policy

残る 2 つは補助的なポリシーです。password policy はパスワードの強度と施行ルールを定めます。MFA と SSO を強制した後もパスワードが残る経路 (非常口の管理者アカウントなど) の品質を下支えする位置づけです。

SQL
-- 長さを主要件にし、総当たり対策のロックアウトを定める
CREATE PASSWORD POLICY security_admin.policies.strong_pw
  PASSWORD_MIN_LENGTH = 14
  PASSWORD_MAX_AGE_DAYS = 0
  PASSWORD_MAX_RETRIES = 5
  PASSWORD_LOCKOUT_TIME_MINS = 30;

ALTER ACCOUNT SET PASSWORD POLICY security_admin.policies.strong_pw;

PASSWORD_MAX_AGE_DAYS = 0 は定期変更の強制を無効にする指定です。定期変更よりも十分な長さと漏えい時の即時失効を重視する、という近年の一般的なガイドライン (NIST SP 800-63B 系) に沿った設定にしています。デフォルトは 90 日なので、明示しないと定期変更が強制される点に注意してください。

session policy はログイン後のセッションの寿命を縛ります。放置された Snowsight のタブや掴みっぱなしの接続が、そのまま第三者の入口になるのを防ぐ層です。

SQL
-- アイドルが続いたセッションを失効させる (デフォルトは 240 分)
CREATE SESSION POLICY security_admin.policies.std_session
  SESSION_IDLE_TIMEOUT_MINS = 60
  SESSION_UI_IDLE_TIMEOUT_MINS = 30;

ALTER ACCOUNT SET SESSION POLICY security_admin.policies.std_session;

SESSION_UI_IDLE_TIMEOUT_MINS は Snowsight 用、SESSION_IDLE_TIMEOUT_MINS はドライバ等を含む全クライアント用です。人が画面を放置しがちな UI 側を短めに、バッチが長時間クエリを流すことのあるドライバ側を長めに、と分けて設定できます。

導入の順番 — 実践レシピ

ここまでの部品を、既存アカウントへ安全に導入する順番に並べます。いきなりポリシーを当てず、棚卸しから始めるのが鉄則です。いま誰がどこからどんな認証で入っているかを知らずに制限を掛けると、必ず何かが止まります。

最初に LOGIN_HISTORY で実態を確認します。

SQL
-- 直近 90 日の接続元 IP と認証方式を棚卸しする
SELECT client_ip,
       first_authentication_factor,
       second_authentication_factor,
       count(*) AS logins
FROM snowflake.account_usage.login_history
WHERE event_timestamp >= dateadd('day', -90, current_timestamp())
  AND is_success = 'YES'
GROUP BY 1, 2, 3
ORDER BY logins DESC;

first_authentication_factorPASSWORDsecond_authentication_factor が NULL の行が、単一要素パスワードで入っている「MFA 強制で影響を受ける」接続です。client_ip の一覧は、そのまま network rule の許可リストの素材になります。あわせてユーザータイプの宣言漏れも確認します。

SQL
-- TYPE 未設定 (NULL) のユーザーを洗い出す — 機械ユーザーが紛れていれば要対応
SELECT name, type, disabled, last_success_login
FROM snowflake.account_usage.users
WHERE deleted_on IS NULL
ORDER BY type NULLS FIRST;

棚卸しが済んだら、影響の読みやすい順に適用していきます。

  1. ネットワーク制限から: 棚卸しした IP を network rule → network policy にまとめ、自分の user → account の順で段階適用する。認証より先にやるのは、仮に認証情報が漏れていても接続元で止まる状態を最初に作れるからです
  2. ユーザータイプの宣言: 機械ユーザーを TYPE = SERVICE 化し、キーペア等へ認証を切り替える。ここが移行作業のボリュームゾーンです
  3. 認証ポリシーの適用: human 向けポリシーを account に、service 向けポリシーを該当ユーザーに適用する
  4. password / session policy: 最後に補助の 2 つを account へ適用する

躓きポイント

user レベルのポリシーが抜け穴になる

account レベルでポリシーを締めても、user レベルに緩いポリシーが付いていればそちらが優先されて account の制限は効きません。過去の暫定対応で付けた user レベルのポリシーが残っているのは典型的な穴です。何がどこに付いているかは POLICY_REFERENCES で棚卸しできます。

SQL
-- ポリシーの適用先を一覧し、user レベルの例外を把握する
SELECT policy_name, policy_kind, ref_entity_domain, ref_entity_name
FROM snowflake.account_usage.policy_references
WHERE policy_kind IN ('AUTHENTICATION_POLICY', 'SESSION_POLICY', 'PASSWORD_POLICY')
ORDER BY policy_kind, ref_entity_name;

例外を user レベルで作ること自体は正当な設計です。問題なのは例外が管理されていないことなので、このクエリを定期実行して「例外の一覧」が常に説明できる状態を保ってください。

固定 IP を持たない接続元

SaaS の BI ツールやマネージドなワークフローサービスは、接続元 IP が広いレンジで変動することがあります。ベンダーが公開している IP レンジを専用の network rule に切り出しておくと、レンジ改定時の追従がその rule の更新だけで済みます。レンジすら公開されていないサービスの場合、account レベルの許可リストに入れると穴が大きくなりすぎるので、そのサービス専用のユーザーに user レベルの network policy を当てて影響範囲をユーザー単位に閉じ込める、という妥協が現実的です。

クラウド上のサービスから Snowflake へ接続する場合も同じ問題が起きます。たとえば GCP では、Cloud Run や Cloud Functions といったマネージドサービスの egress IP は既定では固定されません。そのため既定構成のまま繋ぐなら、各クラウドが公式に公開している IP レンジを network rule に登録しておく必要があります。

ただし公式レンジはリージョン全体で共有される広い範囲なので、これを許可することは「同じクラウド・同じリージョンの他社ワークロードも通す」ことを意味します。絞りたい場合は、GCP なら Cloud NAT で固定の egress IP を持たせてその IP だけを許可する (AWS なら NAT Gateway、Azure なら NAT Gateway / 静的 Public IP)、という構成に寄せる方が network policy の趣旨に合います。公式レンジの登録は「まず繋がる状態を作る」暫定策、固定 egress IP 化が本命、と位置づけるのがおすすめです。

account_usage の反映遅延と client_ip の見え方

account_usage 系ビューには反映遅延があり、LOGIN_HISTORY は最大 2 時間ほど遅れます。「ポリシーを当てた直後に効果をクエリで確認」はできないので、適用直後の検証は実際にクライアントから接続して行ってください。また client_ip に記録されるのは Snowflake から見えた接続元、つまりプロキシや NAT の egress IP です。社内の端末個々の IP ではない点を、許可リスト設計時に取り違えないようにしてください。

権限は SECURITYADMIN 系に集約する

network policy の作成にはグローバルの CREATE NETWORK POLICY 権限、account への適用には追加の権限が必要で、実務上は SECURITYADMIN (またはその配下の専用ロール) に集約するのが素直です。スキーマレベルのポリシー群も冒頭で作った security_admin データベースごと SECURITYADMIN 系ロールの所有にしておくと、「データを触るロール」と「セキュリティ設定を触るロール」の分離が保てます。ACCOUNTADMIN を日常の設定作業に使い回さないでください。

制約事項 (2026 年 8 月時点)

  • MFA 強制の最終段階 (既存ユーザーへの適用) は 2026 年 8 月〜10 月の間にアカウントごとに順次適用されます。自分のアカウントへの適用時期と影響ユーザーは、Snowsight の通知と移行支援画面 (Strong Authentication Hub) で確認できます
  • LEGACY_SERVICE タイプは新規作成不可で、廃止が予定されています。残存ユーザーの移行は待ったなしです
  • SESSION_IDLE_TIMEOUT_MINS に設定できるのは 5〜240 分の範囲です
  • network policy の変更は新規の接続から評価されます。確立済みのセッションが即座に切断されるとは限らないため、「遮断したはずの経路の既存セッション」は別途の失効措置 (ABORT_SESSION 等) を検討してください
  • 旧来の ALLOWED_IP_LIST と network rule を同じポリシーで併用した場合は network rule 側が優先されます。挙動が読みにくくなるので、移行するならポリシー単位で一括で行ってください

いずれも仕様は更新されていくため、適用前に公式ドキュメントの最新の記載を確認することをおすすめします。

まとめ

Snowflake の入口の防御は、「どこから来られるか」と「誰としてどう入るか」の 2 問に分解し、それぞれをポリシーとして宣言しておく、の一点に尽きます。ネットワーク層は network rule を network policy に束ねて account へ、認証層は authentication policy で人間に MFA を・機械にキーペア等を強制し、password / session policy で残りを下支えする。どのポリシーも「作る」と「適用する」が分離しているので、user レベルで試してから account へ昇格する段階適用で、ロックアウトの不安なく進められます。

導入の順番は、LOGIN_HISTORY の棚卸し → ネットワーク制限 → ユーザータイプの宣言とサービスユーザーの認証切り替え → 認証ポリシー → password / session policy、の流れをおすすめします。棚卸しを最初に置くのは、制限の設計図が実態から得られるからです。

冒頭の状況に戻ると、MFA の強制適用はこの 8 月から 10 月にかけて、待っていてもやって来ます。強制される側として受け身で迎えるか、自分のアカウントに合ったポリシーを先に宣言して迎えるかの違いは、当日のパイプライン停止の有無として現れます。まずは棚卸しのクエリ 1 本から始めてみてください。

参考リンクをまとめておきます。

更新履歴

    • Snowflake のネットワーク制限と認証ポリシーの記事を公開