Snowflake × Terraform:依存関係の罠とその解決策
はじめに
ナウキャストでは、自社のデータプロダクト基盤をSnowflake上に構築し、Terraformによるリソース管理を行っています。また社外のクライアント様とのプロジェクトにおいても、Snowflakeを活用したデータ基盤の設計・構築を支援しています。本記事では、SnowflakeリソースをTerraformで管理する際に発生する依存関係の問題とその解決策について解説します。
具体的なケース
Terraformはリソース間の依存関係を解析し、適切な順序でリソースを作成・更新します。しかし、Terraformが自動的に認識することができない依存関係が存在するケースもあります。そのような場合はTerraformが正しい順序でリソースを作成できるよう、depends_on
を引数として与えて明示的に依存関係を指定することができます。ここではdepends_on
による明示的な依存関係の指定が必要となる具体的なケースを解説します。
テーブルに対する操作権限の付与
Snowflakeのロールに対して、スキーマ内のテーブルに対する操作権限(SELECT
, INSERT
, UPDATE
, DELETE
など)を付与する際、そのスキーマに対するUsage
権限を持っている必要があります。また、スキーマに対するUsage
を付与するためには、そのスキーマが属するデータベースに対するUsage
が付与されていなければなりません。しかし、Terraformはこれらの依存関係を認識することができず、自動的に解決することができません。つまり、あるロールに対して「データベースに対するUsageの付与」「スキーマに対するUsageの付与」「テーブルに対する操作権限の付与」をそれぞれ定義するだけではこれらの依存関係をTerraformが解決することができず、apply実行時にエラーとなります。このようなケースでは、以下のようにdepends_on
によって明示的に依存関係を指定することで適切な順序でロールへの権限付与が実行されるようになります。
1. データベースに対するUsageを付与
resource "snowflake_grant_privileges_to_database_role" "usage_database_to_my_role" {
privileges = ["USAGE"]
database_role_name = snowflake_database_role.my_role.fully_qualified_name
on_database = snowflake_database_role.my_role.database
}
2. スキーマに対するUsageを付与
resource "snowflake_grant_privileges_to_database_role" "usage_schema_to_my_role" {
privileges = ["USAGE"]
database_role_name = snowflake_database_role.select_table.fully_qualified_name
on_schema {
schema_name = snowflake_schema.my_schema.fully_qualified_name
}
# データベースに対するUsageを付与した後に実行されるように設定
depends_on = [
snowflake_grant_privileges_to_database_role.usage_database_to_my_role
]
}
3. テーブルの操作権限を付与
resource "snowflake_grant_privileges_to_database_role" "select_all_table_to_my_role" {
privileges = ["SELECT"]
database_role_name = snowflake_database_role.my_role.fully_qualified_name
on_schema_object {
all {
object_type_plural = "TABLES"
in_schema = snowflake_schema.my_schema.fully_qualified_name
}
}
# スキーマに対するUsageを付与した後に実行されるように設定
depends_on = [
snowflake_grant_privileges_to_database_role.usage_schema_to_my_role
]
}
Shareオブジェクトに対する権限付与
Snowflakeには Share という機能があります。Shareとは、データを物理的にコピーすることなく、他のSnowflakeアカウントとデータを共有するための機能です。Shareオブジェクトにテーブルやビューなどの権限を付与し、これらの権限を通じて共有対象のSnowflakeアカウントからデータにアクセスできるように設定します。ここでも前節で解説したものと同様の依存関係が存在します。Shareオブジェクトに対して権限を付与する際も「データベースに対するUsageの付与」「スキーマに対するUsageの付与」「テーブルに対する操作権限の付与」を正しい順序で実行する必要があります。
1. データベースに対するUsageを付与
resource "snowflake_grant_privileges_to_share" "usage_database_to_share" {
to_share = snowflake_share.main.name
privileges = ["USAGE"]
on_database = var.database_name
}
2. スキーマに対するUsageを付与
resource "snowflake_grant_privileges_to_share" "usage_schema_to_share" {
for_each = toset(local.target_schemas) # 共有対象スキーマのリスト
to_share = snowflake_share.main.name
privileges = ["USAGE"]
on_schema = each.key
# データベースに対するUsageを付与した後に実行されるように設定
depends_on = [
snowflake_grant_privileges_to_share.usage_database_to_share,
]
}
3. テーブルの操作権限を付与
resource "snowflake_grant_privileges_to_share" "select_table_to_share" {
for_each = toset(var.target_tables) # 共有対象テーブルのリスト
to_share = snowflake_share.main.name
privileges = ["SELECT"]
on_schema = each.key
# スキーマに対するUsageを付与した後に実行されるように設定
depends_on = [
snowflake_grant_privileges_to_share.usage_schema_to_share,
]
}
Managed Access Schema の Ownership 変更
Snowflakeには Managed Access Schema という機能があります。このオプションが有効化されたスキーマでは、そのスキーマの所有者(OWNERSHIP
権限を持つロール)だけが、そのスキーマ内のオブジェクト(テーブルやビューなど)に対する権限の操作を行うことができます。Managed Access Schema をTerraformで管理する際には依存関係に注意しなければならないケースがあります。それはスキーマの所有者を変更する場合です。
Terraformでスキーマを作成する場合、Terraformの実行ロールがそのスキーマのOWNERSHIP
権限を持つことになりますが、権限管理の方針等によりOWNERSHIP
を別のロールに移譲したい場合があります。しかし、Managed Access Schemaにおいて、そのスキーマ内のオブジェクトに対するOWNERSHIP
のFUTURE GRANTS
が設定されている場合、スキーマのOWNERSHIP
移譲が失敗する場合があります。
例えば、Managed Access Schemaにおいて、スキーマのOWNERSHIP
を持つownership_schema
ロールと、スキーマ内のテーブルのOWNERSHIP
を持つownership_table
ロールをそれぞれ分けて管理する場合を考えます。スキーマについては、Terraform実行ロールからownership_schema
ロールにOWNERSHIP
を移譲します。一方、スキーマ内のテーブルについては、将来作成されるものも含めた全てのテーブルに対するOWNERSHIP
をownership_table
ロールに付与します。この時「ownership_schema
ロールに対してスキーマのOWNERSHIP
を移譲」した後に「ownership_table
ロールに対してテーブルのOWNERSHIP
のFUTURE GRANTS
を実行」するという順序でなければTerraformのapply実行時にエラーが発生します。このようなケースでは、以下のようにdepends_on
を設定することで依存関係の問題を回避します。
1. ownership_schema にスキーマの OWNERSHIP を移譲
resource "snowflake_grant_ownership" "grant_ownership_schema" {
database_role_name = snowflake_database_role.ownership_schema.fully_qualified_name
outbound_privileges = "COPY"
on {
object_type = "SCHEMA"
object_name = snowflake_schema.my_schema.fully_qualified_name
}
}
2. ownership_table にテーブルの OWNERSHIP の FUTURE GRANTS を実行
resource "snowflake_grant_ownership" "grant_ownership_future_table" {
database_role_name = snowflake_database_role.ownership_table.fully_qualified_name
outbound_privileges = "COPY"
on {
future {
object_type_plural = "TABLES"
in_schema = snowflake_schema.my_schema.fully_qualified_name
}
}
# ownership_schemaにスキーマのOWNERSHIPを移譲してから実行
depends_on = [
snowflake_grant_ownership.grant_ownership_schema
]
}
終わりに
TerraformでSnowflakeリソースを構築する際、Terraformが自動的に認識することができない依存関係によりエラーが発生するケースがあります。本記事ではそのような依存関係が問題となる具体的なケースを紹介し、適切な依存関係の指定について解説しました。
とはいえ、すべての開発者が毎回これらの依存関係を意識してTerraformを書くのは大変です。そのため、ナウキャストでは、標準的なリソース構成を定めた上で共通のモジュールを開発し、チーム全体として一貫性を保ちつつ、開発の効率化を図っています。
本記事の内容が、TerraformとSnowflakeを活用する皆さまの参考になれば幸いです。
Discussion