TerraformでSnowflakeのアクセス制御を管理する

## はじめに
私が所属しているライフイズテックのデータ基盤グループではSnowflakeを利用しています。
その[Snowflake](https://www.snowflake.com/en/)には、下記画像のようにデータベースやユーザーだけでなく、多くのリソースとその各リソースに対しての柔軟な権限設定が可能です。
今回はSnowflakeのアクセス制御にterraformを導入した背景とTerraform導入時の課題などをまとめます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75302/05fb4dbe-b79d-a172-18c9-8738ccadeb4d.png)
出典: [アクセス制御の概要 | Snowflake Documentation
](https://docs.snowflake.com/ja/user-guide/security-access-control-overview)

### 環境・バージョン情報
- Terraform 1.4
- snowflake provider 0.67 


## Terraform導入に至った背景
### 1. 権限の細分化
当初Snowflake内のデータや各種リソースのアクセス制御についてはGUIまたはコマンドで管理・編集していました。
Snowflakeで扱っているデータの種類や量が少なく、利用する事業部や人数が少ない時期はそれで事足りていました。

しかし、利用範囲が複数事業部に広がったり同一の事業部の中でも利用するひとが増えた結果、下記のような要求が発生しました。

- 所属していない事業部のデータへのアクセスを禁止する
- テーブル構造などのSnowflake上のリソースの各種定義を誤って変更してしまうことを防ぐ
- 役割に応じてローデータに近いデータへのアクセスを制御する

そこでデベロッパーやアナリストなどのロール設計を細分化し、各種データへのアクセスや設定の編集権限を細かく設定しました。

### 2. 権限管理の複雑化
権限設定を細く設定したところ下記のような課題が発生しました。

- 権限設定の状態の確認が面倒
    - SnowflakeのGUI上だとroleの継承関係や各種DBやSchemaへの権限は各ページに分散しており、確認方法が煩雑
- アカウント発行や権限の変更を他者からの承認や確認なしに行えてしまう。変更の証跡
- 権限付与の漏れや与えるべきでない権限の付与という権限付与のミスが発生。
    - 権限付与のミスが出た場合は、各リソースの詳細ページを目視確認し修正するという手間が発生。
- 権限の管理上、変更作業の担当者が限られ、タスクの分担ができない。

そこでTerraformを導入しgithubで管理することで、githubのワークフローに乗せて、レビューや承認、変更内容の適用などを行うことにしました。



## Terraformでの管理範囲
TerraformによってSnowflakeのアカウントからテーブルの各カラムまでTerraformで管理できます。
参考: https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest
参考: https://github.com/Snowflake-Labs/terraform-provider-snowflake

しかし、私のチームでは[dbt](https://www.getdbt.com/)を導入済みで、テーブル構造についてdbtとTerraformで整合を取っていくのは現実的ではないという判断から、下記の範囲をTerraformでの管理範囲としました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75302/e9338532-49f1-325a-9dba-6f45235cea3b.png)
※ UDFやStored Procedureは範囲外

## Terraformの導入や運用での課題
### terraformerが未対応
Terraform導入時に既存の各種設定情報をTerraformのtfファイルとして記述するという作業が発生します。
その際に、[GoogleCloudPlatform/terraformer](https://github.com/GoogleCloudPlatform/terraformer)が対応していれば、terraformerによって取り込むことができますが、Snowflakeは対応外のため手動で`terraform import`とtfファイルの記述を行っていく必要があります。

**→ Terraform 1.5よりtfファイルの自動生成が可能になったようです。**
[Terraform 1.5 で既存リソースからの HCL 生成ができるようになるので試してみる](https://zenn.dev/kou_pg_0131/articles/tf-generate-config)


### 権限についての記述が上長
`snowflake_database_grant`や`snowflake_schema_grant`のようにリソースと `USAGE`や `MONITOR`などのPrivilegeの掛け算で設定が必要になるため下記の例のように冗長な記述になり、権限設定が読み取りにくいです。
※上位の権限で`ALL PRIVILEGES`を付与するようなケースの場合は、リソースの記述は1つで済みます。

```terraform
resource "snowflake_schema_grant" "dabase_a_public_all_privileges" {
  database_name = snowflake_database.dabase_a.name
  schema_name   = "PUBLIC"

  privilege         = "ALL PRIVILEGES"
  with_grant_option = true

  roles = [
    snowflake_role.developer.name
  ]
}

resource "snowflake_table_grant" "dabase_a_public_tables_select_on_all" {
  database_name = snowflake_database.dabase_a.name
  schema_name   = "PUBLIC"

  privilege         = "SELECT"
  on_all            = true
  with_grant_option = true

  roles = [
    snowflake_role.analyst.name
  ]
}

resource "snowflake_table_grant" "dabase_a_public_tables_select_on_future" {
  database_name = snowflake_database.dabase_a.name
  schema_name   = "PUBLIC"

  privilege         = "SELECT"
  on_future         = true
  with_grant_option = true

  roles = [
    snowflake_role.analyst.name
  ]
}
```
 
**→ Snowflake公式も権限管理の記述が冗長になることを認識しており、0.68のリリースで[snowflake_grant_privileges_to_role (Resource)](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/grant_privileges_to_role)がリリースされました。**
参考: [ ❄️ Snowflake Official Grant Issues Update](https://github.com/Snowflake-Labs/terraform-provider-snowflake/discussions/1890) 


## 宣伝
ライフイズテック サービス開発部では、月毎に気軽にご参加いただけるカジュアルなイベントを実施しています。開催予定のイベントは、 [connpass のグループ](https://life-is-tech.connpass.com/)からご確認ください。興味のあるイベントがあったらぜひ参加登録をお願いいたします。皆さんのご参加をお待ちしています！