SnowflakeをTerraform化

この記事は[note株式会社のカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/note)の2日目の記事です。

SnowflakeをTerraform化したのでその時の記録となります。

# 背景


noteではデータウェアハウスとしてSnowflakeを採用しています。

Snowflakeではデータベースやスキーマはもちろんウェアハウスや権限など、数多くの管理すべきリソースが存在します。

SnowflakeのWEBインターフェースでももちろんそれらを管理できますが、同時によくある課題も付き纏ってきます。


- 変更の履歴が追いづらい
- いつ変更されたかわからない
- 変更をレビューしづらい
- 同じの環境の再構築・再現が難しい

これらの課題をTerraformによってコード化することで解決を行おうというのが今回の記事の主旨になります。

インフラがコード化されるので、今までの開発の知識やgitなどのツールをそのまま活かすことができます。

# SnowflakeのTerraform化


## Terraformで管理するもの・管理しないもの

まずはTerraformで管理するものを決める必要があります。

管理するものを直接決められれば良いのですが、[リソースの種類](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs)が多いので、管理しないものから先に決めると楽に管理するものを決めることができるように思います。

### 管理しないもの

管理しないものとして今回は以下のように定めました。

- Terraform以外の方法で管理すると決めてあるもの
- チーム外の人が細かく変更する可能性のあるもの
- 今現在使っていないもの
- コード化すると量が膨大なもの


この理由としては、以下のようなものが挙げられます。

- Terraform管理とのバッティングをなくすこと
- Terraformを覚える必要がない人にも変更できる余地を残すこと
- コード化すると逆に管理が大変になってしまうことを防ぐこと

#### 例

noteでは、UDFsやストアドプロシージャはPythonでコーディングを行いCIによってデプロイされるなど別方法で管理されています。

テーブルの権限については、ロール・テーブル・操作(SELECT / INSERT / UPDATE / DELETE)ごとに作られているようで数が膨大です。

```sql
-- テーブルの権限一覧
select * from snowflake.account_usage.grants_to_roles where granted_on = 'TABLE' and granted_to = 'ROLE';
```


future grantなどの機能も考慮に入れるとテーブルの権限管理はTerraformでなくても良いという結論に至りました。

### 管理するもの

管理しないものが決まったので、あとは自動的に管理するものも決められます。
今回は次のリソースをTerraformで管理します。

- snowflake_database
- snowflake_database_grant
- snowflake_file_format
- snowflake_file_format_grant
- snowflake_integration_grant
- snowflake_notification_integration
- snowflake_resource_monitor
- snowflake_resource_monitor_grant
- snowflake_role
- snowflake_role_grants
- snowflake_schema
- snowflake_schema_grant
- snowflake_stage
- snowflake_stage_grant
- snowflake_storage_integration
- snowflake_task
- snowflake_task_grant
- snowflake_user
- snowflake_user_grant
- snowflake_warehouse
- snowflake_warehouse_grant

## 既存のリソースの取り込み

既存のリソースの取り込みのためには、最初にSnowflakeにあるリソースをTerraformのコードに落とし込む必要があります。

noteでは、既にSnowflakeを使い始めて1年以上は経過しているので、手動でこれを行うのは大変です。

AWSなどであればterraformerのようなOSSを使えば簡単に自動で取り込めるかもしれませんが、Snowflake向けのものは見つけることができませんでした。

そこで少し面倒ですが、以下の手順で既存のSnowflakeのリソースをTerraformに取り込むことにしました。


1. Terraform用のユーザー作成([公式ドキュメント](https://quickstarts.snowflake.com/guide/terraforming_snowflake/index.html#2)通り)  
(ACCOUNTADMINロールの付与は[推奨されていない](https://docs.snowflake.com/ja/user-guide/security-access-control-considerations#avoid-using-the-accountadmin-role-for-automated-scripts)らしい)
2. [Snowflake providerのドキュメント](https://github.com/Snowflake-Labs/terraform-provider-snowflake/tree/main/docs/resources)をスクレイピング
3. (2)の結果を元にPythonのクラスを生成
4. (3)の結果とSQLでTerraformのコードを生成
5. terraform planを行い差分が出ないように修正(手作業)


### 権限のTerraform化について


Snowflakeの権限リソースはTerraformでは大きく2つの管理方法があるようでした。


- ① `snowflake_<リソース名>_grant`を利用するもの
- ② `snowflake_grant_privileges_to_role` を利用するもの

①の方法はコードが冗長で管理が難しくなるため、②が導入されたという経緯のようです。

実際①の方法で、`snowflake_file_format_grant`などをコード化してterraform planを実行すると以下のような警告が表示されます。

```shell
$ terraform plan

... <省略> ...

Warning: Deprecated Resource
│
│   with snowflake_file_format_grant.a_4f7108a1_f414_46ce_af52_b976fea8cb3c,
│   on config_file_format_grant.tf line 1, in resource "snowflake_file_format_grant" "a_4f7108a1_f414_46ce_af52_b976fea8cb3c":
│    1: resource "snowflake_file_format_grant" "a_4f7108a1_f414_46ce_af52_b976fea8cb3c" {
│
│ This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.
```

> This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.


①の方法は非推奨であり将来的なメジャーバージョンのリリースで削除されるため、②の方法を使えということのようです。

それでも今回は①の方法を採用しました。

詳しくは以下の記事にありますが、②の方法では現状OWNERSHIP権限が管理できないようだったからです。

[https://qiita.com/s11y/items/40d2307696016530c0d0](https://qiita.com/s11y/items/40d2307696016530c0d0)

### 成果物

これらの手順の中でできたものが[こちら](https://github.com/watanany/snowflake_resource_tracker_py/tree/main)になります。

- [Pythonのクラスの生成結果](https://github.com/watanany/snowflake_resource_tracker_py/blob/main/resource_tracker/types.py#L92-L1066)
- Terraformコード生成用の[SQL](https://github.com/watanany/snowflake_resource_tracker_py/blob/main/resource_tracker/sql.py)

各手順で何を行ったかはREADMEをご覧いただければと思います。


# 感想


今回は初めてのTerraformということもありかなり手間取ってしまいました。

普段SQLで使用しているSnowflakeについても、Terraform化にあたりオブジェクトや権限周りがどうなっているかをちゃんと調査する必要でした。

Terraform化ではTerraformを知っているのはもちろん、管理対象のインフラについての知識が求められるということに気付かされるタスクでした。

現状は開発用のSnowflakeアカウントがないので、機会があれば別アカウントで環境を再現できるかは見ていきたいです。


# その他参考にしたドキュメント


#### SQL作成の際に何を見たら良いかわからなかった時の参考

[Snowflakeで付与されている権限を知りたいときに使うSHOW GRANTSコマンドを一通り試してみた #SnowflakeDB | DevelopersIO](https://dev.classmethod.jp/articles/snowflake-try-all-show-grants-command/)

#### 何をTerraformで管理するべきかの参考

[Terraform で Snowflake の何を管理するべきか](https://zenn.dev/dataheroes/articles/2021-12-23-terraform)

#### Snowflakeの各オブジェクトがどのように収まっているかについて

- [セキュリティ保護可能なオブジェクト](https://docs.snowflake.com/ja/user-guide/security-access-control-overview#securable-objects)
- [Snowflakeのロール・権限に関するルールとプラクティス](https://zenn.dev/mnagaa/articles/bfd40e819cbed3)

![image](https://res.craft.do/user/full/ca3c6c79-6b63-6fa8-1300-ce4f010f9a9d/doc/9097A014-86AD-4804-8B79-66FDCC8D394A/BBBBF9DC-0038-4C7B-AA51-1F87284E9F76_2/cxgbxfNyodLL6YxwUCMpPy894yFa4mWQ4UgPLkRgT94z/Image.png)

各リソースが何に依存しているかもよくわかるのでこの図はとても助かった。



#### Snowflakeで権限はどのように管理されているかについて

- [ロール階層と権限の継承](https://docs.snowflake.com/ja/user-guide/security-access-control-overview#role-hierarchy-and-privilege-inheritance)

![image](https://res.craft.do/user/full/ca3c6c79-6b63-6fa8-1300-ce4f010f9a9d/doc/9097A014-86AD-4804-8B79-66FDCC8D394A/D1744388-5F6A-4A63-9871-5501DE51124F_2/ysrJgL6wmkAYxy6VpslO3wbwFSwnWa8kxi6lro7EDMoz/Image.png)

MySQLと違いユーザーに対してではなくロールに対して権限は付与される。

さらにロールは継承構造を形づくることができ、ほとんどの権限は上位のロールに引き継がれる。

権限管理についてはぼんやりと捉えていたのでこの図もとても参考になりました。


# Snowflake Command Line Interface !?

Terraform化した後に知った情報ですが、Snowflake Command Line Interfaceというものが出るようです。

[Snowday 2023で発表された新機能を公式ブログやYouTubeを参考にまとめてみた #Snowday | DevelopersIO](https://dev.classmethod.jp/articles/snowflake-summary-of-snowday-2023-refer-blog-youtube/#toc-14)
> - Snowflake Command Line Interface　※まもなくパブリックプレビュー
> 	- CLIを用いて、Snowflakeのインフラ関連の変更の自動化や、Snowflakeのインフラをコードで定義し、デプロイの自動化やテストが行える

今からSnowflakeをコードで管理にする場合はこれを待ってからでも良いかもしれない。


---

noteの技術記事が読みたい方はこちらもどうぞ！
[note株式会社のカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/note)
[noteエンジニアチームの技術記事](https://engineerteam.note.jp/)