❄️

【Snowflake】NWポリシーの変更を許さないProcedureを利用したユーザへのNWポリシーの適用と権限RESOLVE ALLの罠

2024/03/05に公開

本記事で参考になるケース

  • アカウント全体にIP制限をかけ、デフォルトのユーザはそのIPからしか接続できないようにしている.
  • 特定のROLEは上記デフォルトのIP制限もしくは特定の任意のIP制限のみ設定されたユーザを作成できる.
  • 特定のROLEは「特定の任意のIP制限」以外のIPを追加ないし削除はできない.

記事の概要

  • IP制限の設定にはNetwork policyStored Procedureを利用する
  • Stored Procedureを利用してUSERへのNetwork policyのアタッチALTER USERを行う※.
  • グローバル権限RESOLVE ALLを付与することにより、Network Policy関連の権限を一才保有していないROLEでもユーザへのNetwork Policyのアタッチが可能になってしまうため、注意が必要である.

2024/1末に、Stored Procedure内にてALTER USERを用いたNetwork Policyのアタッチが可能となった!

背景

  • アカウント全体にNetwork Policyが設定されており、かつ、他にいくつかのNetwork PolicyがSnowflakeアカウント内に存在している.
  • あるROLE「ROLE_FOR_CREATE_USER」は、ユーザの作成は行えるがNetwork Policyのアタッチは特定の指定されたNetwork Policyしか選択できないようにしたい.

<例>  Snowflake内に下記Network Policyが存在
Network_Policy_α : 123.456.789.111/32のIP制限
Network_Policy_β : 0.0.0.0のIP制限設定
Network_Policy_γ : 987.654.321.000/32のIP制限設定
Network_Policy_θ : 999.888.777.666/32のIP制限設定

  1. アカウントNetwork_Policy_αが設定されている. ALTER ACCOUNT SET NETWORK_POLICY = Network_Policy_α
  2. ROLE「ROLE_FOR_CREATE_USER」を用いて作成するユーザはNetwork_Policy_αNetwork_Policy_γNetwork_Policy_θ のみのIP制限が適応されることとする

つまり、Network Policy βを設定したどこからでもアクセス可能なユーザの作成を許したくはないのである.

対処方法

  1. 特定のUserにNetwork Policyを設定するStored ProcedureであるDATABASE.SCHEMA.ALTER_USER_NETWORK_POLICYをACCOUNTADMINやSECURITYADMINで作成
  2. DATABASE.SCHEMA.ALTER_USER_NETWORK_POLICYの実行権限をROLE_FOR_CREATE_USERに付与
CREATE ROLE ROLE_FOR_CREATE_USER;
GRANT CREATE USER TO ROLE ROLE_FOR_CREATE_USER;

SHOW NETWROK POLICIES;
>`Network_Policy_α`
>`Network_Policy_β`
>`Network_Policy_γ`
>`Network_Policy_θ`


CREATE OR REPLACE PROCEDURE DATABASE_A.SCHEMA_A.ALTER_USER_NETWORK_POLICY("USER_NAME" VARCHAR, "NETWORK_POLICY" VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
STRICT
IMMUTABLE
COMMENT='Self-Service'
EXECUTE AS OWNER
AS '
var userName = USER_NAME.trim().toUpperCase()
var networkPolicy = NETWORK_POLICY.trim().toUpperCase()
var allowedPolicies = "NETWORK_POLICY_γ, NETWORK_POLICY_θ".split(",")     // 注意! NETWORK_POLICY_γ等は大文字
try{
  if (!allowedPolicies.includes(networkPolicy)){
    throw "Not Allowd!!"
  } else {
    var sql = snowflake.createStatement({
        sqlText: "alter user " + userName + " set network_policy = " + networkPolicy
    });
    sql.execute();
    return "SUCCESS: alter user ''" + user_name + "'' set network_policy ''" + networkPolicy + "'';";
  }
} catch (err) {
  return "ERROR: " + err ;
}'
;

GRANT USAGE ON DATABASE database_a TO ROLE ROLE_FOR_CREATE_USER;
GRANT USAGE ON DATABASE schema_a TO ROLE ROLE_FOR_CREATE_USER;
GRANT USAGE ON PROCEDURE DATABASE.SCHEMA.ALTER_USER_NETWORK_POLICY(varchar, varchar) TO ROLE ROLE_FOR_CREATE_USER;

// 検証
USE SECONDARY ROLES NONE; // ROLEの権限を横断して利用することがないようにする(これはSECONDARY ROLESの動作について調べてほしい.)なお、ROLE_FOR_CREATE_USERのみをもつユーザであれば不要である
USE ROLE ROLE_FOR_CREATE_USER;

CREATE USER test_user password = 'pass';
call DATABASE_A.SCHEMA_A.ALTER_USER_NETWORK_POLICY('test_user','Network_Policy_γ');

さて、"NETWORK_POLICY_γ, NETWORK_POLICY_θ".split(",") になぜNetwork_Policy_αが含まれていないかであるが、これは含んでいても含んでいなくともどちらでも良いからである.
なぜならば「アカウントNetwork_Policy_αが設定されている」ため、CREATE USERをして作成したユーザにはでデフォルトでNetwork_Policy_αのIP制限がかかるためである.
※なお当然のことながらユーザ個別に設定されたNETWORK_POLICY_γやθにより、ユーザのNetwork_Policy_αによるIP制限設定は置き換わる. ここはアカウント全体のNetwork Policyとユーザ個別のNetwork Policyの優先度などについて調べてほしい.

注意点 : グローバル権限RESOLVE ALLの罠

さて、ここで表題にあるRESOLVE ALLの罠について説明する.
Snowflakeのグローバル権限には、RESOLVE ALLというものが存在する. これは一見、全てのObjectに対する閲覧SHOW権限を付与するもののように見える.
しかしながら、肝は「Grants the ability to resolve all objects in the account」である.

例えば、今回利用したROLE_FOR_CREATE_USERROLEにこの権限をつけてみよう.

GRANT RESOLVE ALL ON ACCOUNT TO ROLE ROLE_FOR_CREATE_USER;

こうすると何が起きるか?

USE ROLE ROLE_FOR_CREATE_USER;
ALTER USER test_user set network_policy = Network_Policy_β;
> 成功!

!?

つまり、Network Policy関係の権限を一歳保有していないROLE_FOR_CREATE_USERがNetwork Policyのユーザへのアタッチができるようになってしまうのである.

安易にRESOLVE ALLを付与することにより想定外の挙動を許可してしまう可能性があることに注意が必要である.

参考

RESOLVE ALL権限とは?

対応する SHOW <オブジェクト> コマンドでオブジェクトを出力する、アカウント内のすべてのオブジェクトを解決できる権限を付与します。
Grants the ability to resolve all objects in the account, which outputs the object in the corresponding SHOW <objects> command.

https://docs.snowflake.com/ja/user-guide/security-access-control-privileges#global-privileges-account-level-privileges

Discussion