Snowflakeのロール・権限に関するルールとプラクティス
前書き
Snowflakeをデータウェアハウスとして利用し、プロダクトを開発しているソフトウェアエンジニアです。
普段はSnowflakeに関係するデータ基盤の設計から開発などの業務を行なっています。
SnowflakeのリソースはTerraformで管理したり、CIなどの設計など全般業務に取り組んでいます。
Snowflakeのアクセス制御方法
Snowflakeでは、「オブジェクトごとのアクセス制御」と「ロール」という概念でアクセス制御を行なっています。
任意アクセス制御(DAC): 各オブジェクトに所有者がおり、所有者はそのオブジェクトへのアクセスを許可できます。
ロールベースのアクセス制御(RBAC): アクセス権限がロールに割り当てられ、ロールはユーザーに割り当てられます。
ドキュメントにも書いてあるように、以下の4つの概念を理解してロール設計と権限付与を正しく行えば、安全で堅牢な運用をすることができると思っています。
- セキュリティ保護可能なオブジェクト(Securable object)
- ロール(Role)
- 権限(Privilege)
- ユーザー(User)
Snowflake上にある任意のセキュリティ保護オブジェクトへのアクセスは権限が付与されない限りは使用することができないようになっています。つまり、明示的な権限付与が行われない限り、アクセス・操作ができないので安全であると言えます。
階層的にロールを設計をすることができます。つまり、下の階層にあるロールを集約して、新しいロールを作成できます。権限の集約された強いロールを新しく作成していくことができます。一番上のロールは「ORGADMIN」または「ACCOUNTADMIN」になり、その下に「SYSADMIN」や「SECURTYADMIN」などのロールが階層的に設定されています。
権限付与の方法をまとめると以下の流れになります。
- セキュリティ保護オブジェクトへのアクセス権限をロールに付与する(複数のアクセス権を1つのロールに集約します)
- 作成したロールを、他のロールに付与すると階層的にロールを引き受けることが可能です。ユーザーに付与すると、付与されたユーザーはロールを選択することができ、そのロールで権限を行使することでオブジェクトにアクセスすることができるようになります。(上のロールは下のロールになりすますことができると理解してください。)
セキュリティ保護可能なオブジェクト
セキュリティ保護可能なオブジェクトとしては以下の画像にあるものがあげられます。つまり、以下のものはロールに付与されない限り使用できないということになります。
画像の通り、アカウントにあるオブジェクトと、データベース内のスキーマ内で定義できるオブジェクトの2つが基礎になると思います。
ロール
ロールはユーザーに割り当てられ、ユーザーが組織内のビジネス機能に必要なアクションを実行できるようにします。ユーザーには複数のロールを割り当てることができます。これにより、ユーザーはロールを切り替えて(現在のSnowflakeセッションでアクティブなロールを選択する)、個別の権限セットを使用して異なるアクションを実行できます。
これ、基本なので覚えてほしいことになります。ずっと強い権限でやってる人がいるので、いつか事故ってしまいそうだなとか思うことがあります。Snowflakeに「undrop」や「TimeTravel」があるのである程度は大丈夫なんでしょうが、使用できる機能は用途に合わせて絞っておく方が絶対に良いです。
Snowflakeのトラブルシューティングの第一歩目としてロールを確認
ACCOUNTADMIN ロールを使ってオブジェクトを作成しない
ちなみに公式ドキュメントにも「ACCOUNTADMIN ロールを使ってオブジェクトを作成しない」という項目があります。
ACCOUNTADMIN ロールは、システムで初期セットアップタスクを実行し、アカウントレベルのオブジェクトとタスクを日常的に管理することを意図したものです。そのため、これらのオブジェクトに最高レベルの安全なアクセスを持たせる絶対的な必要性がない限り、アカウントでオブジェクトを作成するために使用しないでください。ACCOUNTADMIN ロールでオブジェクトを作成し、ユーザーにこれらのオブジェクトへのアクセスを許可する場合は、これらのユーザーのロールにオブジェクトに対する権限を明示的に付与する必要があります。
新しいロールは
create role ${role_name};
で作成できます。
権限
セキュリティ保護可能なオブジェクトごとに、付与できる権限のセットがあります。既存のオブジェクトの場合、個々のオブジェクトに権限を付与する必要があります(例: mytable テーブルの SELECT 権限)。
テーブルのselect
とかdelete
などを行うレベルの話です。
権限の付与方法
ロールをロールに付与したり、ロールをユーザーに付与する方法は、
grant role ${role_name1} to role ${role_name2};
grant role ${role_name1} to user ${user_name};
で行うことができます。
付与を取り消すには、
revoke role ${role_name1} from role ${role_name2};
revoke role ${role_name1} from user ${user_name};
で行うことができます。
詳しくは以下のドキュメントを確認してください。
ロールの継承・階層的ロール設計は以下の図をみると理解しやすいです。下層のロールをまとめたものをユーザに付与することでユーザはオブジェクトに対するアクション権限を持ちます。また、図のROLE_1が付与されたユーザは、ROLE_2またはROLE_3としてもアクションをすることができるので、用途に応じて切り替えながら(自分で制限しながら)操作をしていく必要があります。
READONLYロールの作り方
readonly権限=selectだけができるロールは以下のリンクが参考になります。
READONLYロールを作るときに必要な権限は以下のようになります。
- データベース: USAGE
- スキーマ: USAGE
- テーブル: SELECT
多くの場合に、データベースやスキーマとかにon future
として権限を与えて、新しく作られるテーブルにも権限が渡るようにするケースが多いかと思います。
ロール設計の例
公式ドキュメントでは、会計士やアナリストなどの実際のユースケースに基づいて紹介されています。ただ、実際にプロダクトで使うときは、これをもとに設計し直す必要があります。
例えば、私の設計では、
- アプリケーション用ロール(dev/stg/prd)
- エンジニア専用ロール
- データサイエンティスト用ロール
- データアナリスト用ロール
- BI用ロール
- 監視用ロール(Datadog)
- Terraform用ロール
- CI用ロール
- DBT用ロール
などの役職別ロールをまず作成して、これらの役職別ロールに対して、データベースへのREADONLYまたはREADWRITE用ロールなどを付与していくことで、安全なアクセス制御を実現しています。
とはいえ、これだけのロールを管理するのはコストがかかるので、Terraformを使って管理をしていたり、on future grantを利用したりして簡潔な設定にしております。
あとは、Sandboxスキーマをいくつか用意して、書き込み権限や削除権限などを与えられるようにして、データ利用者にストレスをできるだけ与えないような設計を意識しています。
Discussion
是非、こちらも確認してみて頂ければと思います。