TerraformとSnowflakeで考えること

はじめに

SnowflakeクラウドをベースとしたSaaS型のデータプラットフォームです。主要なクラウドAWS/GCP/Azure)に対応しており、企業/組織内の至る所に転がっているデータも「クラウド×Snowflake」で連携できるため、アジリティやスケーラビリティが求められるデータプラットフォームとして大きな強みがあります。

そんな注目を浴びているSnowflakeですが、これまたIaCとして人気のあるTerraformで構築できます。Snowflakeは大量のオブジェクトを組み合わせて管理するため、長くお世話になるならTerraformの利用をぜひとも考えたいところです。

本稿では、Terraform×Snowflakeを検討していく上で自分が感じた検討ポイントや悩みどころを脳内整理を兼ねて記載します。本内容がこれから検討する方の参考になれば幸いです。

SnowflakeとTerraformのざっくりHistory

こちらにまとまっています。

  • 2019年からChan Zuckerberg Initiative (CZI) によりSnowflake向けのTerraformプロバイダが整備開始
  • 2022年5月25日に所有権をChan Zuckerberg Initiative (CZI) からSnowflake-Labsに譲渡
  • 現在はSnowflake-Labsで管理されている

公式サポートも明言されたため、最近ではTerrfaorm×Snowflakeの記事も多く見かけるようになりました。

規模や目的にもよるとは思いますが、これからSnowflakeを始める方はTerraformの利用も視野に入れておくことをおすすめします!

最初の一歩:チュートリアル

まず何から手をつけたほうがよいのだろう...となると思います。幸いチュートリアルが用意されているので、下記サイトを一通り試してみるのをおすすめします。Terraform×Snowflakeの基礎を学ぶことができます。

Terraforming Snowflake

また、下記の内容を一読することもおすすめします。リアルな設計構築ポイントについてとてもわかりやすくまとめられています。このレベルの内容を無料で読ませて頂けるのは感謝感激です。

SnowflakeとTerraformで作るデータ基盤入門

Terraform×Snowflakeの検討ポイント

さっそく本題です。いざ現場で「Terraformをガンガン利用していくぞー!」となると、ちょろっと動作確認するだけでは見えてこなかった様々な検討課題が出てきます。本稿では自分が感じたこと、考えたことをまとめてみます。 注意点ですが、あくまで持論なので、正解か不正解かを述べているわけではありません、「こんなこと言っているやつがいるな」程度にみてもらえればと思います。ユースケースは山ほどありますし、私自身も考えをアップデートしていきます。むしろ、こうしたほうがよいんじゃない?などのコメント大歓迎です!是非是非ご意見頂けると幸いです。

① 役割分担

Terraformを管理するのは誰か?です。いきなりケースバイケース、が正解となる問です。

本稿ではTerraformを担当するチームと、データモデルや分析を検討するチームを分けて考えます。

開発者全員がTerraformを扱えるなら困らないと思いますが、世の中そんなにうまくはいきません。人材確保が困難な時代でSnowflakeもTerraformもできる人をアサインして、チームとして開発を継続していくのはとても難しいチャレンジになると思います。

昨今ではクラウドを扱うインフラエンジニアがTerraformを得意としているので、インフラチームがプロジェクトに存在するなら、餅は餅屋としてお任せした方が進めやすいケースも多いはずです。SQLに慣れているデータ分析のエンジニアにTerraformを一から学んでもらうよりも、得意な領域に注力してもらう方が価値を発揮できると思います。

Snowflakeの活用が広まっていくと同時に、スキルセットの課題はより顕著になってくると思います。また、規模が大きくなればなるほどチームで分担しながら開発を進めていくことになると思います。そのため、ここではTerraformを検討する「インフラチーム」と、データモデルやSQL検討する「データ分析チーム」として話を進めていきます。

② ロール階層

初めにロール階層を検討しましょう。Snowflakeは6つのデフォルトロールが用意されていますが、実際の開発ではカスタムロールの作成が必須です。カスタムロールに適切な権限を付与することで、柔軟なアクセス制御を実現できます。

このアクセス制御方針がTerrfaformの役割分担に関係してきます。つまり、何をどこまで「インフラチーム」にお任せして、どこから「データ分析チーム」で開発するのか、です。

ここでは「インフラチーム」がTerraformでデータベース・スキーマを作成し、「データ分析チーム」がそのデータベース・スキーマ上で自由にテーブルやビューを操作できるように、下記のようなロール階層とします。

ロール階層について詳細を述べませんが、正直難しいテーマだと思います。SYSADMIN配下にカスタムロールを紐づける方針まではよいですが、後の設計は自由です。先輩方がたくさんの知見を残してくれているので、参考にしながら検討を進めてくのがよいと思います。

公式ドキュメント:アクセス制御の概要

2021/03/01 Snowflake を始めるときのおすすめユーザ権限管理構成

2022/05/16 Snowflakeのアクセス制御

2023/01/31 Terraform による Snowflake ロール作成 ~ Functional role + Access role モデル ~

SnowDDLのドキュメント:Role hierarchy

メモ:運用を考慮すると、オンライン・バッチ処理で動かしているウェアハウスと、アドホックにクエリを実行するウェアハウスが重複しないようにウェアハウスのUSAGEを設計することもポイントになるでしょう。

③ Terraform管理対象オブジェクト

具体的に何をTerraformで構築するのか?です。

2023/2時点でSnowflake Providerは63のResourcesを提供しており、今後のアップデートで更に増えていくことが予想されます。つまり、いろいろできるけど結局何を構築したらよいのだろう...と悩むことになります。この検討には、先ほどのロール階層に加えて、要件と体制を合わせて考えます。

要件次第でSnowpipeからPIPEオブジェクトが登場し、データ共有ならSHAREオブジェクトを検討するようになります。ここは都度変更されるため、検討の枠組みを整備したり、改善のプロセスを整備できれば、自ずと管理対象が適正化されていくと思います。

体制はスキルセットや運用が関連します、例えばTerraformを知らない運用チームがメンテ作業をできるようにするなら、必ずしもTerraformの利用が正義とはならない、などです。

従ってこれも「プロジェクト次第だねー」が正解となります。もう何度聞いたかわからないセリフですね。

では具体的な検討内容をみていきます。

Terraform実行ユーザーに付与するロールは?

SnowflakeオブジェクトをTerraformで扱うには、Snowflake上にTerraform実行ユーザーを作成します。そして、Terraform実行ユーザーにSnowflakeオブジェクトの操作権限を付与します。

CREATE USER "TF_DEV" RSA_PUBLIC_KEY='RSA_PUBLIC_KEY_HERE' DEFAULT_ROLE=PUBLIC MUST_CHANGE_PASSWORD=FALSE;

GRANT ROLE SYSADMIN TO USER "TF_DEV";
GRANT ROLE SECURITYADMIN TO USER "TF_DEV";

つまり、Terraform実行ユーザーに付与した権限が、Terraformで扱えるSnowflakeオブジェクトになります。

個人的には、デフォルトロールのSYSADMIN・SECURITYADMIN権限を付与して、ACCOUNTADMIN権限を付与しない方針で問題ないと思います。理由はシンプルで、SYSADMIN・SECURITYADMINはデータベース作成や権限付与のためさすがに必要であること、ACCOUNTADMIN権限の付与は公式でも述べられているように最小限にしたほうがよいからです。実際、ACCOUNTADMINが必要となる操作はそこまで多くないので、個人的にはそこまで困らないと思っています。

もしACCOUNTADMIN権限が必要となるオブジェクトをTerraformで扱いたい場合は、Terraform実行ユーザーにACCOUNTADMINを付与する前に、まずはロールへの権限委譲を考えてみるのがよいと思います。例えば、リソースモニター共有オブジェクトストレージ統合あたりが判断に迷うポイントになると思います。どちらにしても、運用しながら改善していく方針でも十分だと思います。

Terraform対象とするオブジェクト

次に何のオブジェクトを対象とするか?です。

Terraform実行ユーザーにSYSADMIN・SECURITYADMIN権限を付与する前提として、下記Snowflakeオブジェクトを例にTerraform利用方針を記載してみます。備考は個人的なメモとして残しておきます。なお、クラウドAWSを利用する前提でIAMと記載しています。

オブジェクト TF対象 備考
DBSCHEMA タイムトラベルの保持期間 data_retention_time_in_days をチーム間で合わせて環境差異として設定する。
enable_multiple_grants期待した動きにならない報告もあるので権限付与をTerraformに統一して利用しないことにする。
GRANT ROLE TO DB 「データ分析チーム」の管理者にOWNERSHIPを付与する。
ロール階層でアクタを整理しながらUSAGEを付与する。
GRANT ROLE TO SCHEMA データベースと同様にOWNERSHIPとUSAGEを付与する、加えて要件に応じて必要な権限を付与する。
デフォルトで作成されるPUBLICスキーマの利用方針も検討しておく。
TABLE - 複雑になるためTerraformでは管理しない。
「データ分析チーム」が、テーブルを含むスキーマ配下のオブジェクトを自由に作成/管理できるようにする。
GRANT ROLE TO TABLE on_futuretrue となる場合はTerraformで管理する。
テーブル設計方針をチーム間で合意しておく。
全てのテーブルを対象に権限を付与することができないことに注意して実装する。
ROLE カスタムロールを管理する。
GRANT ROLE TO ROLE Terraformの実装にとりかかる前に、ロール階層の設計をチーム間で合意しておくこと。
WAREHOUSE パラメータに注意する。こちらが参考になる。
GRANT ROLE TO WAREHOUSE ロール階層と合わせて確認する、アドホックなクエリで利用するウェアハウスが業務処理のウェアハウスに影響を及ぼさないか、など。
STAGE ストレージ統合をSQLで作成するため、手続き的な構築となることに注意する。
GRANT ROLE TO STAGE ステージを参照するロール階層と照らし合わせて意識合わせしておく。
STORAGE INTEGRATION - ACCOUNTADMIN権限を必要とするのでTerraformで管理しない。SQLで作成してData Sourcesとして読み込む。
GRANT ROLE TO STORAGE INTEGRATION ストレージ統合の参照にもACCOUNTADMIN権限を必要とするので、Terraformで扱えるようにUSAGE権限を付与する。
AWS IAM ROLEIAM POLICY STAGE用に作成する。外部ID設定のため、IAMロール作成→ストレージ統合作成→ストレージ統合のように手続き的な対応となることに注意する。
USER ケースバイケースだが、個人的にはTerraform対象外にしてもよい考えている。
理由はSSOでユーザー管理を外出ししたり、運用ではTerraformなしで作業できることが望ましいケースもあるため。
GRANT ROLE TO USER 同上。

再掲ですが、Terraform対象とするSnowflakeオブジェクトは要件やプロジェクトの方針次第で変わります。ただ、どのようなケースであろうと方針を表や箇条書きで整理してみるのがよいと思います。

命名規則と環境差異

チーム間の意識合わせが超重要です。そりゃそうだろうという話ですが、ここを曖昧にすると後で傷口が広がるおそれがあります。

Terraformを利用するなら、モジュール化して各環境面の設定を効率化したり、可能な限り条件分岐を減らした記述を心掛けたいところです。もし命名規則や環境差異をチーム間で意識合わせしていないと、命名から用途を読み取りにくくなったり、コード内で無理やり分岐したりと、徐々に品質への影響が懸念されます。

中長期的に品質を確保していくためにも、チーム間でオブジェクトの命名規則と環境差異の方針を合わせておきましょう。

命名規則

よくある命名規則の方針と変わりませんが、Snowflakeクラウドと連携することが多いため、Snowflakeのアカウントとクラウドの環境面をラベルに追加しておくのもありだと思います。

# sample
[組織・プロジェクト名]_[Snowflakeアカウント名]_[Snowflake or クラウド環境面]_[機能識別子]_<[任意]>_[オブジェクト名]_[ナンバリング]

環境差異

まずはSnowflakeクラウドのアカウントと環境面について、どう連携するか意識合わせしましょう。 チーム間の意識合わせの際には、こんな問いをしてみるのがよいと思います。

  • クラウドアカウントとSnowflakeアカウントは1対1か?
  • クラウドアカウント内の環境面とSnowflakeアカウントは1対1か?それともN対1か?
  • Snowflakeに構築するオブジェクトは、クラウドのどのアカウント・環境面と連携するのか?
  • 上記オブジェクトはクラウドの各環境面に対して共通設定か?それとも設定差異はあるか?設定差異がある場合どこか?

環境差異の例を挙げてみます。

  • このデータベースとスキーマは開発面だけあればよいのだよね
  • この環境面のデータベースだけはこのスキーマを追加してほしい
  • この環境面だけステージが必要ほしいのよ、あと特定のスキーマだけを対象としたい

モジュール化の影響も含めてチーム間で目線を合わせられるとよいでしょう。なお、1回きりの意識合わせではないので、持続的なヒアリングを通じてチーム間のコミュニケーションの成熟度を上げていくことが品質担保につながるでしょう。

Terraform未経験の方が自律的にここまで考慮するのは難しいと思いますので、早い段階から本検討の必要性/重要性を伝えるような動きを「インフラチーム」ができるとよいと思います。

⑤ Terraformモジュールとディレクトリ構造

いきなりモジュールやディレクトリ構造を考えるのではなく、アカウントと環境面の構造を整理しておくのがよいと思います。ここではアカウント内に複数の環境面が存在するようなモデルを考えてみます。

この構成のモジュール分割について考えてみます。

  • Snowflakeアカウントレベルのモジュール
    • ロール、ウェアハウスと関連するGRANTを管理
  • ② ステージ準備用モジュール
    • ステージ用のIAMリソースを管理
  • ③ 開発用途のモジュール
    • 開発用途のデータベース/スキーマ/ステージと関連するGRANTを管理
    • ロール、ウェアハウス、IAMリソース、STORAGE INTEGRATIONをData Sourcesで参照
    • ①②の後に作成
  • ④ 商用用途のモジュール
    • 商用用途のデータベース/スキーマ/ステージと関連するGRANTを管理
    • 他は③と同様

この構成のメリデリは以下となります。

- 内容
メリット ・条件分岐を削減できる
・tfstateの肥大化を抑えられる
・商用への更新影響範囲を削減できる
デメリット ・モジュール追加方針を決めにくい
・一部手続き的な段取りが必要
・管理するモジュールや設定ファイルが多くなる

続いてディレクトリ構造の例です。上記方針さえ決まってしまえばあとは型にはめるような感じになると思います。

.
├── cloud(AWS_GCP_Azure...)
│   ├── envs
│   │   └── (略)
│   └── modules
│       └── (略)
└── snowflake
    ├── envs
    │   ├── account_dev
    │   │   └── snowflake_common
    │   │       └── main.tf
    │   ├── account_prod
    │   │   └── (略)
    │   ├── account_stg
    │   │   └── (略)
    │   ├── env_dev01
    │   │   └── snowflake_dev
    │   │       └── main.tf
    │   ├── env_dev02
    │   │   └── (略)
    │   ├── env_dev03
    │   │   └── (略)
    │   ├── env_dev04
    │   │   └── (略)
    │   ├── env_prod01
    │   │   └── (略)
    │   └── env_stg01
    │       └── (略)
    └── modules
        ├── snowflake_common
        │   ├── grant_role_to_role.tf
        │   ├── grant_role_to_warehouse.tf
        │   ├── locals.tf
        │   ├── main.tf
        │   ├── roles.tf
        │   ├── variables.tf
        │   └── warehouses.tf
        ├── snowflake_dev
        │   ├── data.tf
        │   ├── db_schema.tf
        │   ├── grant_role_to_db.tf
        │   ├── grant_role_to_schema.tf
        │   ├── grant_role_to_stage.tf
        │   ├── grant_role_to_table.tf
        │   ├── locals.tf
        │   ├── main.tf
        │   ├── stages.tf
        │   └── variables.tf
        ├── snowflake_iam
        │   └── (略)
        └── snowflake_main
            └── (略)

メモ:余力あればサンプルコードを公開する

おわりに

最初は技術的なことを中心に書いていこうと思っていましたが、感じたことを自由気ままにに記載していたら、Terraform×Snowflakeの検討を推進にはチーム間の連携がとても大切であると再確認でき、全体的にチーム間の意識合わせをしっかりやっていきましょう!という内容になってしまいました。また最後の方は力尽きたので気が向いたときに補足します。

もともと書こうと思っていた実装の具体的なところや変更/削除の注意点などについては次回書きたいと思います。(忘れないうちに残しておきたいな...)

リアルはより複雑になると思いますが、Terraform×Snowflakeの検討を推進していく際の参考になれば幸いです。