【Snowflake × Terraform】Cortex Analyst 用の Account Role を作る方法

に公開

はじめに

こんにちは、ナウキャストで LLM エンジニアをしている Ryotaro です。

最近 Cortex Analyst を検証として使う機会が増えてきました。PoC 段階で使う分には sandbox 環境などがあれば、強い権限ですぐに使えますが、本番環境に移行する際には適切な権限管理が必要になってきます。

そこで今回初めて Snowflake の Cortex Analyst を使うための Account Role を Terraform で作ってみて、いろいろ勉強になったので記事にしてみました。

想定する読者

  • Snowflake Cortex Analyst を使う Role が Public 以外に欲しい人
  • Snowflake Cortex Analyst を system user から利用したい人

前提

  • Snowflake のリソースを Terraform で管理していること
  • Snowflake Terraform Provider のバージョンは 2.5.0

必要な権限

公式ドキュメントでは、Cortex Analyst を使うためには以下の権限が必要と記載されています。

権限 オブジェクト
READ または WRITE Semantic Model の YAML ファイルを含むステージ
USAGE Semantic Model で言及されている Cortex Search Service
SELECT Semantic Model で言及されているテーブル

https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst#access-control-requirements

なのですが、Cortex Analyst を使うのは Semantic Model の他、最近新しく出てきた Semantic View も使うことができます。

Semantic View とはデータベースに保存されている物理的なデータに対し、ビジネス上の意味(セマンティクス)を直接定義するための新しいオブジェクトです。中身は従来の Semantic Model と同じですが、それを Snowsight 上から作成・編集したりすることができます。

https://docs.snowflake.com/en/user-guide/views-semantic/overview

このとき Semantic Model は Stage に保存する必要があったので Cortex Analyst を使うためには、Stage に対して READ または WRITE の権限が必要だったのですが、Semantic View を使う場合は Semantic View に対する SELECTREFERENCE の権限が必要となります。ここが一つのポイントです。

作成するオブジェクトの関係性

作成するオブジェクトの全体像を図にしてみました。基本的に database role を一つ作って、その role に対して DB の Object に対する権限を付与します。その後、account role にその database role と Cortex AI を使うための role を紐付けて作成します。

Terraform で作成する

では実際に Terraform で書いていきましょう

Database Object

まず、Cortex Analyst が対象とする DB などのオブジェクトを作ります。

  • Database
  • Schema
  • Stage
################################################################################
# Database Object
################################################################################

resource "snowflake_database" "zenn_db" {
  name    = "ZENN_DB"
}

resource "snowflake_schema" "zenn_schema" {
  database            = snowflake_database.zenn_db.name
  name                = "ZENN_SCHEMA"
  is_transient        = false
  with_managed_access = false
}

### semantic model を利用する場合は stage も用意する
resource "snowflake_stage" "zenn_semantic_model" {
  database  = snowflake_database.zenn_db.name
  schema    = snowflake_schema.zenn_schema.name
  name      = "ZENN_STAGE"
  directory = "ENABLE = true"
}

Account Object / Database Role

次に、上記 DB リソースを利用するための Database role を作成します。下記では READ 権限を付与するための role を作成しています。

基本的に Cortex Analyst を使う場合は DB に対して書き込む操作を想定していないので、READ 権限のみを付与する role を作成します。

################################################################################
# Database role
################################################################################

# Read database role
resource "snowflake_database_role" "zenn_read_role" {
  database = snowflake_database.zenn_db.name
  name     = "${snowflake_database.zenn_db.name}_DB_READ_ROLE"
}

resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_database" {
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_database        = snowflake_database.zenn_db.fully_qualified_name
  privileges = [
    "MONITOR",
    "USAGE",
  ]
  with_grant_option = false
}

resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_schema" {
  privileges         = ["USAGE"]
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_schema {
    all_schemas_in_database = snowflake_database.zenn_db.fully_qualified_name
  }
  with_grant_option = false
}

resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_schema_all_tables_zenn_schema" {
  privileges         = ["SELECT"]
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_schema_object {
    all {
      object_type_plural = "TABLES"
      in_schema          = snowflake_schema.zenn_schema.fully_qualified_name
    }
  }
  with_grant_option = false
}

resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_schema_future_tables_zenn_schema" {
  privileges         = ["SELECT"]
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_schema_object {
    future {
      object_type_plural = "TABLES"
      in_schema          = snowflake_schema.zenn_schema.fully_qualified_name
    }
  }
  with_grant_option = false
}

### semantic model を利用する場合は stage に対して READ 権限を付与する
resource "snowflake_grant_privileges_to_database_role" "zenn_read_on_semantic_stage" {
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  privileges         = ["READ"]
  on_schema_object {
    object_type = "STAGE"
    object_name = snowflake_stage.zenn_semantic_model.fully_qualified_name
  }
}

Semantic View を利用する場合は、Semantic View に対する REFERENCES もしくは SELECT の権限が必要となるので、Semantic View に対して REFERENCES 権限を付与するための role を作成します。

https://docs.snowflake.com/en/user-guide/views-semantic/sql#granting-privileges-on-semantic-views

# Grant REFERENCES privilege on all current semantic views in RFP_APP schema
resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_schema_all_semantic_views_zenn_schema" {
  privileges         = ["REFERENCES", "SELECT"]
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_schema_object {
    all {
      object_type_plural = "SEMANTIC VIEWS"
      in_schema          = snowflake_schema.zenn_schema.fully_qualified_name
    }
  }
  with_grant_option = false
}

# Grant REFERENCES privilege on all future semantic views in RFP_APP schema
resource "snowflake_grant_privileges_to_database_role" "zenn_read_db_role_on_schema_future_semantic_views_zenn_schema" {
  privileges         = ["REFERENCES", "SELECT"]
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  on_schema_object {
    future {
      object_type_plural = "SEMANTIC VIEWS"
      in_schema          = snowflake_schema.zenn_schema.fully_qualified_name
    }
  }
  with_grant_option = false
}

ただ、Snowflake Terraform Provider のバージョンが 2.5.0 では、Semantic View を object type に指定することができず、terraform 上では Semantic View に対して権限を付与することができません。

そのため代替案として、

  • semantic view だけ snowsight から手動でやる
  • snowflake_execute を使って自分で書く
  • semantic view ではなく、semantic model を使う

の 3 つの方法があります。

snowflake_execute を使って自分で書く場合は、以下のようになります。

# Grant REFERENCES and SELECT privileges on all current semantic views in RFP_APP schema using SQL execution
resource "snowflake_execute" "grant_references_select_on_all_semantic_views" {
  execute = "GRANT REFERENCES, SELECT ON ALL SEMANTIC VIEWS IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} TO DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
  revert  = "REVOKE REFERENCES, SELECT ON ALL SEMANTIC VIEWS IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} FROM DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
}

# Grant REFERENCES and SELECT privileges on all future semantic views in RFP_APP schema using SQL execution
resource "snowflake_execute" "grant_references_select_on_future_semantic_views" {
  execute = "GRANT REFERENCES, SELECT ON FUTURE SEMANTIC VIEWS IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} TO DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
  revert  = "REVOKE REFERENCES, SELECT ON FUTURE SEMANTIC VIEWS IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} FROM DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
}

Account Object / Account Role

これで、Semantic View に対して REFERENCESSELECT の権限が付与されます。
最後に Cortex Analyst を使うための Account role を作成します。

ここでのポイントは SNOWFLAKE.CORTEX_USER という role を account role に紐付けている点です。 他にも Cortex Agents や Cortex Search などがありますが、Cortex AI 系の機能を使う時は必ずこの role が必要です。

################################################################################
# Account role
################################################################################

# Warehouse
resource "snowflake_warehouse" "zenn_warehouse" {
  name                                = "ZENN_WH"
  auto_resume                         = true
  auto_suspend                        = 30
  enable_query_acceleration           = false
  max_cluster_count                   = 1
  max_concurrency_level               = 8
  min_cluster_count                   = 1
  scaling_policy                      = "STANDARD"
  statement_queued_timeout_in_seconds = 0
  statement_timeout_in_seconds        = 300
  warehouse_size                      = "XSMALL"
  warehouse_type                      = "STANDARD"
}

# Account role (for Cortex / semantic model)
resource "snowflake_account_role" "zenn_cortex_role" {
  name = "ZENN_CORTEX_ROLE"
}

# Grant USAGE privilege on warehouse
resource "snowflake_grant_privileges_to_account_role" "zenn_cortex_role_on_warehouse" {
  privileges        = ["USAGE"]
  account_role_name = snowflake_account_role.zenn_cortex_role.name
  on_account_object {
    object_type = "WAREHOUSE"
    object_name = snowflake_warehouse.zenn_warehouse.fully_qualified_name
  }
}

# Grant SNOWFLAKE.CORTEX_USER to account role
resource "snowflake_grant_database_role" "zenn_grant_cortex_user" {
  database_role_name = "SNOWFLAKE.CORTEX_USER"
  parent_role_name   = snowflake_account_role.zenn_cortex_role.name
}

# Grant database role to account role
resource "snowflake_grant_database_role" "zenn_cortex_role_grant_db_read_role" {
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  parent_role_name   = snowflake_account_role.zenn_cortex_role.name
}

これで、Cortex Analyst を使うための role が作成されました。

まとめ

Snowflake の Cortex Analyst を使うための Account Role を作る方法を紹介しました。ポイントは以下の 2 点でした。

  • SNOWFLAKE.CORTEX_USER という role を account role に紐付けている点
  • Semantic View を利用する場合は REFERENCES もしくは SELECT の権限が必要で、Terraform では対応されていないので、以下の 3 つの方法で対応する必要がある点
    • snowflake_execute を使う
    • semantic view だけ snowsight から手動でやる
    • semantic model を使う

というの 2 点でした。

Semantic View の権限付与に関しては、issue が起票されているので、今後のバージョンアップで対応されると思います。対応されれば、grant_privileges_to_database_role を使って Terraform で権限付与する形で記載できるようになると思います。

Snowflake の Terraform 実装は今回が初でしたが role 周りも色々と勉強になりました。弊社メンバーの方々にも色々と相談しながら作成しました。よかったらそちらの記事も見てみてください!

https://techblog.finatext.com/snowflake-access-control-and-cost-management-0e69d2d1ad1f

おまけ

Cortex Analyst から Cortex Search を使う場合も同様に Database role に対して Search Service の USAGE 権限を付与する必要があります。

resource "snowflake_grant_privileges_to_database_role" "zenn_usage_on_all_cortex_search_zenn_db" {
  database_role_name = snowflake_database_role.zenn_read_role.fully_qualified_name
  privileges         = ["USAGE"]
  on_schema_object {
    all {
      object_type_plural = "SEARCH_SERVICES"
      in_schema          = snowflake_schema.zenn_schema.fully_qualified_name
    }
  }
}

ただこれもまだ Terraform では対応されていないなので、snowflake_execute を使って自分で書く必要があります。

# Grant USAGE privilege on all current search services in RFP_APP schema using SQL execution
resource "snowflake_execute" "grant_usage_on_all_cortex_search" {
  execute = "GRANT USAGE ON ALL SEARCH SERVICES IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} TO DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
  revert  = "REVOKE USAGE ON ALL SEARCH SERVICES IN SCHEMA ${snowflake_database.zenn_db.name}.${snowflake_schema.zenn_schema.name} FROM DATABASE ROLE ${snowflake_database_role.zenn_read_role.fully_qualified_name}"
}

We are Hiring!

この件についてもっと詳しく知りたい、議論したい、はたまたナウキャストという会社に興味を持ったという方は、カジュアル面談フォームから連絡ください。

https://herp.careers/v1/finatexthd/vZWzSlI_B-qk

Finatext Tech Blog

Discussion