1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TerraformでSnowflake上にリソースを作成する手順

Last updated at Posted at 2023-04-09

はじめに

TerraformでSnowflakeを構築する手順としては、Snowflakeが出しているチュートリアルを参考にすると分かりやすいです。

しかしチュートリアル通りにやっても上手くいかずハマったポイントがあったので、自分なりに手順をまとめました。

環境

  • macOS Ventura 13.1
  • Homebrew 4.0.11

概要

この記事ではチュートリアルを参考にしつつ自分なりに少し修正し、最終的にTerraformを用いて以下リソースをSnowflake上に作成する手順を紹介します。

  • データベース
  • スキーマ
  • ステージ
  • ウェアハウス
  • ユーザー
  • ロール
  • 諸々の権限付与

1. Terraformインストール

ローカルで開発を進めるにはTerraformをインストールする必要があるので、まだしていない場合はインストールしておきましょう。

tfenvをインストール

zsh
$ brew install tfenv

バージョン確認

zsh
$ tfenv --version

インストール可能なTerraformバージョン確認

zsh
$ tfenv list-remote

2023/04/09時点では最新はv1.4.4なのでそれをインストール

zsh
$ tfenv install 1.4.4

インストールしたバージョンのTerraformを使用するように指定

zsh
$ tfenv use 1.4.4

2. Snowflake準備

Snowflakeは無料で30日間のトライアルアカウントを作成できるので、まだない場合はアカウントを作成しておきます。

画面の指示通りに項目を記入していけば簡単にアカウントが作成できます。
私はEditionはスタンダード、クラウドプロバイダーはAWS、リージョンはAsia Pacific (Tokyo)を選択しました。

アカウントを作成するとメールが届くので、アカウントを有効化してログインしておきましょう。

3. 接続準備

以下を実行し、接続に使うための鍵を作成してクリップボードにコピーしておきます。

zsh
$ cd ~/.ssh
$ openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out snowflake_tf_snow_key.p8 -nocrypt
$ openssl rsa -in snowflake_tf_snow_key.p8 -pubout -out snowflake_tf_snow_key.pub
$ cat snowflake_tf_snow_key.pub | pbcopy

次にSnowflake上で以下を実行します。
やってることはTerraformで使用するSnowflakeユーザーの作成と、そのユーザーへのロール付与です。

SQL Worksheet
CREATE USER "tf-snow"
	RSA_PUBLIC_KEY='${生成した公開鍵}'
	DEFAULT_ROLE=PUBLIC
	MUST_CHANGE_PASSWORD=FALSE;

GRANT ROLE SYSADMIN TO USER "tf-snow";
GRANT ROLE SECURITYADMIN TO USER "tf-snow";

※公開鍵をペーストした際に前後に-----BEGIN PUBLIC KEY-----, -----END PUBLIC KEY----—も入ると思うので、それは忘れずに消しておいてください。

作成したユーザーに2つのロールを使用できるようにしていますが、以下のように使い分けます。

  • SYSADMIN: データベースやスキーマ、ウェアハウスなどのオブジェクト作成
  • SECURITYADMIN: ユーザーとロールの作成、権限付与

そして環境変数を設定するためにローカルで以下を実行します。

zsh
$ export SNOWFLAKE_USER="tf-snow"
$ export SNOWFLAKE_PRIVATE_KEY_PATH="~/.ssh/snowflake_tf_snow_key.p8"
$ export SNOWFLAKE_ACCOUNT="${アカウントLocator}"
$ export SNOWFLAKE_REGION="${リージョンID}"

アカウントLocatorはURLに含まれるxy12345のような文字列です。
リージョンIDは、私はアカウント作成時にAWSのAsia Pacific (Tokyo)を選択したので、ap-northeast-1.awsになります。

これらの情報はSnowfalke上で以下を実行することでも確認できます。

SQL Worksheet
SELECT
	current_account() as YOUR_ACCOUNT_LOCATOR,
	current_region() as YOUR_SNOWFLAKE_REGION_ID;

リージョンIDに関しては、ドキュメントを参考に対応するクラウド地域IDに変換する必要があります(必要ならクラウドプロバイダー名も加える)。

環境変数はターミナルを立ち上げる度に入力しないといけないので、snow.envなどのファイルを用意しそこに記載しておくと次回以降入力が楽です。
(Gitでコード管理する場合はsnow.env.gitignoreへ追加するのを忘れずに)

4. Terraform実装

プロジェクトのベースディレクトリにmain.tfを作り、以下を貼り付けてください。

main.tf
terraform {
  required_providers {
    snowflake = {
      source  = "Snowflake-Labs/snowflake"
      version = "0.42.1"
    }
  }
}

provider "snowflake" {
  role  = "SYSADMIN"
}

resource "snowflake_database" "db" {
  name     = "TF_DEMO_DB"
}

resource "snowflake_warehouse" "warehouse" {
  name           = "TF_DEMO_WH"
  warehouse_size = "large"
  auto_suspend = 60
}

Providerのバージョンを0.42.1に固定しています。

チュートリアルでは0.35以上の最新のバージョンを使用するようにしていますが、比較的新しいバージョンだと、スタンダードエディションではエラーが出てしまします。
ウェアハウス作成時にスタンダードディションでは利用できないパラメータが自動で追加されてしまうことが原因で起こるエラーで、2023/04/09時点で最新のバージョン0.61.0でも解決はしていないようです。
そのため問題なく使える0.42.1あたりを使用するのが妥当だと思います。

5. Terraform実行

プロジェクトのディレクトリで以下を実行します。
Terraformの実行に必要な依存関係や、状態を保持するファイルがローカルにダウンロードされます。

zsh
$ terraform init

Gitでコード管理している場合、作成された状態ファイルなどはpushしてしまわないように.gitignoreに追加しておきましょう。

.gitignore
*.terraform*
*.tfstate
*.tfstate.*

次に以下を実行し、Terraformを実行した場合の変更内容を確認します。

zsh
$ terraform plan

データベースとウェアハウスを作成するという変更内容になっていると思います。
リソースの変更内容に問題がなければ、以下を実行します。

zsh
$ terraform apply

再度変更内容が表示され適用して良いか聞かれると思うので、問題なければyesと入力してください。

成功するとSnowfalke上でデータベースとウェアハウスが作成されます。

▼ データベース
スクリーンショット 2023-04-09 3.00.23.png
▼ ウェアハウス
スクリーンショット 2023-04-09 3.00.45.png

6. リソースの追加

最後にその他のリソースを作っていきましょう。
main.tfに以下を追加してください。

main.tf
// SECURITYADMINロールで操作できるように
provider "snowflake" {
  alias = "security_admin"
  role  = "SECURITYADMIN"
}

// ロール作成
resource "snowflake_role" "role" {
  provider = snowflake.security_admin
  name     = "TF_DEMO_ROLE"
}

// データベースへの権限付与
resource "snowflake_database_grant" "grant" {
  provider          = snowflake.security_admin
  database_name     = snowflake_database.db.name
  privilege         = "USAGE"
  roles             = [snowflake_role.role.name]
  with_grant_option = false
}

// スキーマ作成
resource "snowflake_schema" "schema" {
  database     = snowflake_database.db.name
  name         = "TF_DEMO_SCHEMA"
}

// デフォルトスキーマへの権限付与
resource "snowflake_schema_grant" "schema_default_grant" {
  provider          = snowflake.security_admin
  database_name     = snowflake_database.db.name
  schema_name       = snowflake_schema.schema.name
  privilege         = "USAGE"
  roles             = [snowflake_role.role.name]
  with_grant_option = false
}

// スキーマへの権限付与(今後作成されるものも含む)
resource "snowflake_schema_grant" "schema_grant" {
  provider          = snowflake.security_admin
  database_name     = snowflake_database.db.name
  privilege         = "USAGE"
  roles             = [snowflake_role.role.name]
  with_grant_option = false
  on_future         = true
}

// テーブルへの権限付与(今後作成されるものも含む)
resource "snowflake_table_grant" "table_grant" {
  provider      = snowflake.security_admin
  database_name = snowflake_database.db.name
  privilege     = "SELECT"
  roles         = [snowflake_role.role.name]
  on_future     = true
}

// ビューへの権限付与(今後作成されるものも含む)
resource "snowflake_view_grant" "view_grant" {
  provider      = snowflake.security_admin
  database_name = snowflake_database.db.name
  privilege     = "SELECT"
  roles         = [snowflake_role.role.name]
  on_future     = true
}

// ステージ作成
resource "snowflake_stage" "stage" {
  name     = "TF_DEMO_STAGE"
  database = snowflake_database.db.name
  schema   = snowflake_schema.schema.name
}

// ステージへの権限付与
resource "snowflake_stage_grant" "stage_grant" {
  provider      = snowflake.security_admin
  database_name = snowflake_database.db.name
  schema_name   = snowflake_schema.schema.name
  stage_name    = snowflake_stage.stage.name
  privilege     = "READ"
  roles         = [snowflake_role.role.name]
  depends_on    = [snowflake_stage.stage]
}

// ユーザー作成
resource "snowflake_user" "user" {
  provider             = snowflake.security_admin
  name                 = "TF_DEMO_USER"
  password             = "password"
  default_role         = ""
}

それぞれやっていることはコメントに書いてある通りです。

コード追加後、planで変更を確認し問題がなければapplyします。

zsh
$ terraform plan
$ terraform apply

Snowflake上で確認すると、TF_DEMO_ROLEというロールが作成され、TF_DEMO_DB.TF_DEMO_SCHEMAの操作権限を持っていることが分かります。
スクリーンショット 2023-04-09 15.15.25.png

その後TF_DEMO_DBに別のスキーマやテーブルを作成すると、ON_FUTUREが効いていることによりTF_DEMO_ROLEに権限が与えられることも確認できます。
スクリーンショット 2023-04-09 15.17.20.png

他の作成したリソースに関しても意図した通りに作成されていると思います。

その他設定できるリソースやパラメータなどはTerraformのProviderページを参考にしてください。

まとめ

Terraformで基本的なリソースを作成する手順を紹介しました。
今回作成したコードは以下にアップしています。

実際に運用する際には、ファイル分割や状態ファイルの保管方法、リソースが増えた場合の処理の共通化など、まだまだ考慮する観点があります。
これらに関してはまた記事を書こうと思います。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?