概要
Google Cloud上でAtlantisというterraformのGitOpsツールを導入している状態で、Snowflakeもterraform管理したいと考えました。
タイミング良く Snowflake Provider で v2.10.0 からWorkload Identity Federation が正式サポートされたので、これを使って実現します。
環境
- Terraform v1.13.4
- snowflakedb/snowflake provider v2.11.0
- hashicorp/google provider v7.9
コンポーネント図

準備
前提として
- Google Cloud上でAtlantis環境が整っている
- Atlantisの実行用サービスアカウントがIAMにある
とします。
Google Cloud
Snowflakeとの連携で必要になるため、サービスアカウントのメールアドレスからIDを確認しておきます。
gcloud iam service-accounts describe "<GSA_EMAIL>" --format="value(uniqueId)"
21 桁の数字のIDが出てくるので、それを使います。
Snowflake
Terraform用ロール作成
まずは専用のロールを作成します。
-- 1. Terraform用ロールを作成 USE ROLE ACCOUNTADMIN; CREATE ROLE IF NOT EXISTS TERRAFORM_ADMIN_ROLE COMMENT = 'Role for Terraform automation (aggregates required privileges)'; -- SYSADMIN: Database/Warehouse/Stage作成 -- ACCOUNTADMIN: Storage Integration作成 -- SECURITYADMIN: Grant操作 GRANT ROLE SYSADMIN TO ROLE TERRAFORM_ADMIN_ROLE; GRANT ROLE ACCOUNTADMIN TO ROLE TERRAFORM_ADMIN_ROLE; GRANT ROLE SECURITYADMIN TO ROLE TERRAFORM_ADMIN_ROLE;
非常に大きな権限を付与しますが、Terraformというインフラ環境構築ツールの用途上権限が不足しているとUXが下がりますし、今回はWorkload Identity Federationによって鍵が不要でセキュリティも担保できるのでこうしています。
Terraform用ユーザ作成
次にユーザを作成します。
先ほどのGoogleCloudのサービスアカウントIDを使います。
-- 2. Terraform用ユーザを作成 USE ROLE SECURITYADMIN; CREATE USER IF NOT EXISTS TERRAFORM_SVC TYPE = SERVICE WORKLOAD_IDENTITY = ( TYPE = GCP SUBJECT = '<SERVICE_ACCOUNT_ID>' ) COMMENT = 'Terraform automation service account with Workload Identity Federation';
先ほど作ったロールを付与します。
GRANT ROLE TERRAFORM_ADMIN_ROLE TO USER TERRAFORM_SVC;
専用ウェアハウスの作成
-- 3. Terraform用ウェアハウスを作成 USE ROLE SYSADMIN; CREATE WAREHOUSE IF NOT EXISTS TERRAFORM_SVC_WH WAREHOUSE_SIZE = XSMALL AUTO_RESUME = TRUE AUTO_SUSPEND = 60 INITIALLY_SUSPENDED = TRUE STATEMENT_TIMEOUT_IN_SECONDS = 300 COMMENT = 'For terraform automation only';
権限を専用ロールに付与します。
USE ROLE SECURITYADMIN; GRANT USAGE ON WAREHOUSE TERRAFORM_SVC_WH TO ROLE TERRAFORM_ADMIN_ROLE;
デフォルトロール・デフォルトウェアハウスの設定
最後にデフォルト値の設定をしておきます。
ALTER USER TERRAFORM_SVC SET DEFAULT_ROLE = TERRAFORM_ADMIN_ROLE, DEFAULT_WAREHOUSE = TERRAFORM_SVC_WH;
Terraform
Snowflakeの設定が終わったら次はTerraformの書き方です。
versions.tf
Terraform, Providerのバージョン指定です。
terraform { required_providers { snowflake = { source = "snowflakedb/snowflake" version = "~> 2.11.0" } google = { source = "hashicorp/google" version = "~> 7.9" } } required_version = ">= 1.13.4" }
注意としてsnowflake providerは2.10以降でないとWIF authenticatorをサポートしていません。
providers.tf
Providerの設定です。
provider "snowflake" { organization_name = var.snowflake_organization_name account_name = var.snowflake_account_name user = "TERRAFORM_SVC" authenticator = "WORKLOAD_IDENTITY" workload_identity_provider = "GCP" } provider "google" { project = var.project_id region = "asia-northeast1" }
ポイント
userにSnowflakeで作ったユーザを指定authenticatorをWORKLOAD_IDENTITYにworkload_identity_providerをGCPに
パラメータ上、ロールやウェアハウスを指定することもできますが、後述しますが逆に指定することでエラーになっていますので外しています。
動作確認
次のようなリソースを定義して、作成できることを確認します。
resource "snowflake_database" "tf_db" { name = "TF_DEMO_DB" is_transient = false } resource "snowflake_warehouse" "tf_warehouse" { name = "TF_DEMO_WH" warehouse_type = "STANDARD" warehouse_size = "XSMALL" max_cluster_count = 1 min_cluster_count = 1 auto_suspend = 60 auto_resume = true enable_query_acceleration = false initially_suspended = true }
トラブルシューティング
遭遇したエラーと対処方法をまとめます。
Error: open snowflake connection: 390101 (08004): User access disabled.
このエラーはSnowflake 側で対象ユーザーが「無効化 (DISABLED=TRUE)」状態になっています。
これは設定が不十分で認証に失敗していると、自動的に無効化されてしまうようです。なので再度有効化します。
USE ROLE ACCOUNTADMIN; ALTER USER TERRAFORM_SVC SET DISABLED = FALSE;
Error: open snowflake connection: 390201 (08004): The requested warehouse does not exist or not authorized.
これは
- ウェアハウスがない
- 権限がない
のどちらかですが、様々な要因があります。
a. ロールに権限がない
権限を付与しましょう。
GRANT USAGE ON WAREHOUSE TERRAFORM_SVC_WH TO ROLE TERRAFORM_ADMIN_ROLE;
b. ロールに権限があるが、ユーザがそのロールやウェアハウスを使おうとしていない
Snowflakeユーザは、ロールやウェアハウスの指定をUSEで設定する方法と、デフォルト設定する方法の2つがあります。
今回のWorkload Identity Federationのように、裏で自動で処理する場合はUSEで指定できないのでデフォルト値の設定をしておくのが良いです。
USE ROLE SECURITYADMIN; ALTER USER TERRAFORM_SVC SET DEFAULT_ROLE = TERRAFORM_ADMIN_ROLE, DEFAULT_WAREHOUSE = TERRAFORM_SVC_WH;
c. providerで指定するロール・ウェアハウスが悪影響
一番ハマったのですが、「↑のようにデフォルト値の設定をしていなくてもproviderでrole・warehouseを指定していれば大丈夫だろう」と考えていました。
provider "snowflake" { organization_name = var.snowflake_organization_name account_name = var.snowflake_account_name user = "TERRAFORM_SVC" authenticator = "WORKLOAD_IDENTITY" workload_identity_provider = "GCP" role = "TERRAFORM_ADMIN_ROLE" warehouse = "TERRAFORM_SVC_WH" }
しかしながらこのように指定した状態ではうまくいかず、またデフォルト値を設定したとしても通りませんでした。
| Snowflakeユーザ デフォルト設定あり |
Snowflakeユーザ デフォルト設定なし |
|
|---|---|---|
| provider指定あり | エラー | エラー |
| provider指定なし | 成功 | エラー |
おそらくではありますが、provider 側で role / warehouse を明示したときの初期化の順序(またはログイン時パラメータの扱い)が、WIF と相性悪くてコケているのかもしれません。
まとめ
Google CloudのIAMをIdPとして、SnowflakeのTerraformの認証を Workload Identity Federation で実現しました。