フューチャー技術ブログ

Terraform + Auth0 を調査してみる

TIG DXユニット 1 アルバイトの小林です。

案件で認証プラットフォームであるAuth0を利用しています。

Auth0がHashiCorpとのパートナーシップを結び、TerraformでAuth0リソースの管理が可能となりました。

https://auth0.com/blog/partners-with-hashicorp-terraform/

今回はTerraformで既存のAuth0リソースを移行するという観点で調査を行いました。

Auth0とは

Auth0の概要についてはAuth0導入編をご参照ください。他にも技術ブログにはAuth0関連の記事が沢山あります。

Terraformとは

TerraformとはHashiCorpによって開発されたオープンソースのクラウド管理ツールです。

クラウド環境のインフラの構成をコードに落とし込むことで、Git管理が可能になり、さらに状態を定義することが可能になるため、状態との差分からクラウド環境のリソース変更部分の表示が可能になるため、設定ミスのリスクを低減が見込めます。

技術ブログではTerrafom関連の記事が沢山あるためそちらも合わせてご参照ください。

また、Terraform以外でAuth0のクラウドリソースをコードに落とし込むツールにはauth0-deploy-cliが上げられます。

Auth0 Deploy CLI

https://github.com/auth0/auth0-deploy-cli

Auth0が出しているツールで、テナント構成をyamlに落とし込んだり、yamlに書かれたテナント構成を反映するなど、CI/CDを可能にします。

Auth0 Deploy CLIについては、TIG市川さんのAuth0の設定をバージョン管理し、Auth0 Deploy CLIを利用してデプロイ環境を整えるをご参照ください。

Auth0 Deploy CLIには、dry-runがサポートされておらず 8実際に実行してみるまでテナント構成がどうなるのか分からない、さらに意図していない変更を検出出来ないといった課題があります。

Auth0 Deploy CLI vs Terraform

Auth0環境の構成をAuth0 Deploy CLIで行う場合とTerraformで行う場合について、それぞれの強みと弱みについて調査しました。

Auth0 Deploy CLIの強み

  • テナントの構成をまるっとエクスポートすることが出来ます。
    • rules,hooksもディレクトリに区切ってファイルを作成してくれるなど、親切です。
  • mappingが公式サポートされています。

Auth0 Deploy CLIの弱み

  • Auth0専用のツールなのでこのツールの操作方法を独自で覚える必要があります。
  • dry-run機能が無いため意図していない設定変更が生じうる可能性があります 9

Terraformの強み

  • 独自ツール無しでTerraformだけで済むため、いままでAWSなどでTerraformを使っている場合、学習コストほぼ0で利用出来ます。
  • Terraformにはplanと呼ばれる現在の状態と変更後の状態の差分を表示させる、dry-runに該当する機能があります。
  • Terraform workspaceを利用することで同一のリソースブロックを複数環境で利用することが可能になります。これにより検証環境と本番環境の設定の同一化が比較的容易に実現出来ます。

Terraformの弱み

  • 一括で全リソースをインポートする手段が無いためテナント設定が膨大の場合、Terraformで管理出来る状態に持っていくまでが大変です。
    • terraformのimportをAuth0プロパイダで利用する際、IDの特定方法が複雑(後述)です。

今回、私の所属しているプロジェクトでは、他のクラウドリソースをTerraformで管理していること、
Auth0の構成が複雑になっていることから、planが非常に強力であり、作業ミスのリスクを大幅に減少出来る見込みのため、Terraformを採用することにしました。

Terraformで管理すると

Terraformで管理出来る様になると以下の点で便利になります。

  • 環境毎の設定差異の検出が簡単に出来る。
  • Auth0のリソース更新時にdry-runが可能になり、意図していないリソースの変更や、リソースの更新忘れのリスクを軽減できる。
  • 環境全体がコードに落ちるためGitなどのバージョン管理ツールで管理が出来る様になる。

この記事では以下の2点について扱います。

  • terraform importを利用して既存のAuth0リソースをTerraformに移行できるか
  • 複数環境で設定を統一化出来るか

前提

  • terraformのバージョンはv0.14.6を利用します。
  • プロパイダはalexkappa/auth0を利用します。
    • バージョンはv0.17.1です。
  • 事前にAuth0のテナントのダッシュボードから、Management APIが利用可能なM2Mのアプリケーションを作成しておき、ClientIDとClientSecretを取得しておく必要があります。

準備手順

作業ディレクトリにmain.tfを作成して以下の様に記載します。

main.tf
terraform {
required_providers {
auth0 = {
source = "alexkappa/auth0"
version = "0.17.1"
}
}
}


provider "auth0" {
domain = "Auth0テナントのドメイン"
client_id = "事前に作成したM2MアプリケーションのClientID"
client_secret = "事前に作成したM2MアプリケーションのClientSecret"
}

その後、terraform initをします。

以上で準備完了です。

terraform importを利用して既存のAuth0リソースをTerraformに移行できるか

TL;DR

一つだけtfstateを弄る必要があるが、可能です。

既存のAuth0リソースをTerraformに移行する際の流れ

まずは移行手順の全体像について記載します。

  • 空のリソース定義を作成する。
  • terraform import で既存のリソースをstateに取り込む
  • terraform state showでstateに取り込んだ既存リソースのパラメータを確認し、先程作成した空のリソース定義に追加していく。
  • terraform planして差分が無くなればそのリソースの移行完了

この手順をAuth0で管理出来る全リソースについて実行します

Terraformで管理出来るリソースの一覧(リソースタイプ)は↓で定義されています。

Docs overview | alexkappa/auth0 | Terraform Registry

かなりの作業量になるため何らかのツールがあるだろうと探してみたのですが、見つけられませんでした。 2

加えてこの手順でAuth0のリソースをインポートするに当たって、ある事象でハマってしまいました。

ハマったポイント: IDが無いリソースタイプがいくつかある。

Terraformで定義されているimportコマンドの書式はこのようになっています。

$ terraform import [options] ADDRESS ID
ADDRESSとは▼

ADDRESS はリソースアドレスの事であり、<given type>.<local name> の形式で表します。

例えば、

resource "auth0_custom_domain" "main_domain" {
}

の様なリソースブロックにおいて、

ADDRESSauth0_custom_domain.main_domainです。


IDはそのリソースをインポートするための識別子です。例えば、Auth0 Custom Dmainのドメイン設定はcd_<random string>の形で割り振られています。

このIDですが、リソースタイプによっては存在しません。例えば、テナント設定である、auth0_tenantにはIDが存在しません。この場合、どうすれば設定のインポートが出来るのか、悩んでいました。

結論としては、IDを適当に自分で決めればインポート出来ました

なぜ適当なIDで通るのか

IDは識別子です。Auth0 のテナント設定に着目すると、IDが無くとも設定が判別できます

IDが振られているリソースタイプである、auth0_roleのプロパイダのソースコード 3とTerraform公式のimportの説明 7を読むと、CLIから受け取ったIDがd.ID()に入っている事が分かります。

同様にIDが不明なリソースタイプである、auth_tenantのプロパイダのソースコード 4を読むと、auth0_roleでは使われていた、d.ID()が使われていない事が分かります。そのため、こちらで適当なIDを入れても問題無いことが分かります。

リソースタイプとIDの対応表

執筆当時プロパイダのドキュメントに、どのパラメータを使えばimportが出来るかの情報がほとんど載っていません。issueにはちらちら書かれていますが、テナント設定のimport方法について書いている人は見つけられませんでした。

そのためリソースタイプとID対応関係について表にまとめてみたので参考にお使い下さい。執筆当時で、この中の全リソースタイプについてimportが出来ている事を確認しています。 5

また、IDの確認が必要なリソースタイプについては、IDが確認しやすい様にManagement APIのAPI Explorerの該当APIのURLを載せています。

IDの欄に"id"と書かれていた場合はAPIを叩いた時のJSONレスポンスのキーが”id”の値を指します。
自由と書かれていた場合は先述の理由により、自由に設定出来ます。

Resource Type ID URL 備考
auth0_client “client_id” https://auth0.com/docs/api/management/v2#!/Clients/get_clients
auth0_client_grant “id” https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants
auth0_connection “id” https://auth0.com/docs/api/management/v2#!/Connections/get_connections
auth0_custom_domain “custom_domain_id” https://auth0.com/docs/api/management/v2#!/Custom_Domains/get_custom_domains tfstateの修正が必要 6
auth0_email 自由
auth0_email_template [verify_email,
verify_email_by_code,
reset_email,
welcome_email,
blocked_account,
stolen_credentials,
enrollment_email,
mfa_oob_code,
user_invitation] のどれか一つ
IDによって、インポートされる項目が異なる、
例えば`verify_email`ならば認証メールがインポートされる。
auth0_hook “id” https://auth0.com/docs/api/management/v2#!/Hooks/get_hooks
auth0_prompt 自由
auth0_resource_server “id” https://auth0.com/docs/api/management/v2#!/Resource_Servers/get_resource_servers
auth0_role “id” https://auth0.com/docs/api/management/v2#!/Roles/get_roles
auth0_rule “id” https://auth0.com/docs/api/management/v2#!/Rules/get_rules
auth0_rule_config “key” https://auth0.com/docs/api/management/v2#!/Rules_Configs/get_rules_configs
auth0_tenant 自由
auth0_user “user_id” https://auth0.com/docs/api/management/v2#!/Users/get_users

複数環境で設定を統一化出来るか

複数テナントが推奨されているAuth0において、テナントの設定を統一化したいケースがあると思います。
その際はterraform workspaceと呼ばれる機能を用いて一つのリソースブロックを複数の環境で共有することが可能になります。

dev環境とtest環境があったとして、この二つの環境で同一の設定にさせたい場合について考えます。

先程のmain.tfと同階層にvariables.tfを置きます。

variables.tf
locals {
environments = {
dev = {
auth0_domain = "dev-example.auth0.com",
auth0_client_id = "dev環境のM2MアプリケーションのClientID",
auth0_client_secret = "dev環境のM2MアプリケーションのClientSecret"
}
test = {
auth0_domain = "test-example.auth0.com",
auth0_client_id = "test環境のM2MアプリケーションのClientID",
auth0_client_secret = "test環境のM2MアプリケーションのClientSecret"
}
}
}

main.tfのプロパイダ設定を以下の様に変えます。

main.tf
provider "auth0" {
domain = local.environments[terraform.workspace]["auth0_domain"]
client_id = local.environments[terraform.workspace]["auth0_client_id"]
client_secret = local.environments[terraform.workspace]["auth0_client_secret"]
}

Terraformのworkspaceを追加しましょう。main.tfで以下のコマンドを実行します。

$ terraform workspace new dev
$ terraform workspace new test

以下の様に表示されます(現在いるworkspaceに*が付きます。)

$ terraform workspace list
default
dev
* test

今自分が入っているworkspaceはterraform workspace listで確認します。

移動したい場合はterraform workspace [移動先のworkspace名]です。

dev環境を正としたい場合は先程のリソースのimport手順をworkspaceがdevの状態で進めます。その後、workspaceをtestに変更してからリソースブロックを変更せずにterraform importを全リソースに対して行います。

最後に、terraform planでdev環境とtest環境の設定の差分が表示されます。

一部だけ設定を変えたい

test環境の時だけ空のルールであるempty-rule.js、その他の環境の時はsome-rule.jsを動かしたいケースについて考えてみます。

HCLの組み込み関数fileと三項演算子により実現出来ます。

resource "auth0_rule" "some_rule" {
name = "some_rule"
script = terraform.workspace == "test" ? file("./empty-rule.js") : file("./some-rule.js")
}

Terraformの組み込み関数replaceを使えば、同一のファイルを参照しつつ振る舞いを返る事が可能になります。

テナント環境毎に挙動が変わるRuleをTerraformで管理してみます。

初めに以下の様なスクリプトを保存し、

set-env.js
 function setEnv(user, context, callback) {
const idTokenClaims = context.idToken || {};
idTokenClaims["http://example.com/env"] = "###AUTH0_TENANT###";

context.idToken = idTokenClaims;

return callback(null, user, context);
}

以下の様にリソース定義を行います。

resource "auth0_rule" "set_env" {
name = "set_env"
script = replace(file("./set-env.js"),"###AUTH0_TENANT###",terraform.workspace)
}

このように書く事でdev環境では

set-env.js
 function setEnv(user, context, callback) {
const idTokenClaims = context.idToken || {};
idTokenClaims["http://example.com/env"] = "dev";

context.idToken = idTokenClaims;

return callback(null, user, context);
}

として、test環境では

set-env.js
 function setEnv(user, context, callback) {
const idTokenClaims = context.idToken || {};
idTokenClaims["http://example.com/env"] = "test";

context.idToken = idTokenClaims;

return callback(null, user, context);
}

として環境毎に振る舞いを変える事が出来ました。

まとめ

今回はTerraform + Auth0の環境構築について、既存のAuth0環境の移行を観点として調査を行いました。

調査結果をまとめると、

  • importの手順に一癖あるが、一応全リソースを移行出来る。
  • workspaceを用いて複数のテナントで環境を同一にしつつ、一部だけ環境毎に振る舞いを変えることが出来る。

ことが分かりました。

既存のAuth0環境をTerraformに移行したい場合の考慮材料にして頂ければ幸いです。

ここまで読んで頂きありがとうございました。

終わりに

私事で恐縮ですが、2019年の2月からアルバイトとして働いてきたFutureを今日で退職します。

この2年を通してFutureで沢山の技術を学び、自身のスキルを大幅に向上させることが出来ました。

2年間本当にお世話になりました。ありがとうございました!


  1. 1.TIG: Technology Innovation Groupの略で、フューチャーの中でも特にIT技術に特化した部隊です。DXユニット: TIGの中にありデジタルトランスフォーメーションに関わる仕事を推進していくチームです。
  2. 2.執筆中にterraformerと呼ばれる既存のインフラリソースをリソース定義(.tf)や状態(.tfstate)に落とし込むCLIツールは見つけたのですが、執筆当時はまだ対応リストに記載されていません。
  3. 3.https://github.com/alexkappa/terraform-provider-auth0/blob/master/auth0/resource_auth0_role.go#L86
  4. 4.https://github.com/alexkappa/terraform-provider-auth0/blob/master/auth0/resource_auth0_tenant.go#L256
  5. 5.あくまで全リソースタイプについて確認しているため、リソースタイプのauth0_email_templateのIDはverify_emailreset_emailのみ確認済みです。
  6. 6.このリソースタイプはどうリソースブロックを編集してもterraform planで差分を無くす事が出来ません。verification_methodがManagement APIの仕様上importされないため、tfstate側がnullと設定されてしまうからです。スキーマ定義を見ると、RequiredForceNewが付いているためこのままではリソースの再生成が走ってしまいます。そのため、.tfstate,.tfの両方についてverification_method = "txt"に強制的に変更することでterraform planで差分を表示させない様に設定出来ます。この問題はプロパイダのリポジトリのissueでも言及されていました。 Importing auth0_custom_domain resource forces recreation · Issue #294 · alexkappa/terraform-provider-auth0
  7. 7.Resources - Import - Terraform by HashiCorp
  8. 8.Support Test Mode · Issue #70 · auth0/auth0-deploy-cliissue自体は記載されています。
  9. 9.一応Auth0 Deploy CLIでは、意図していないリソースの破壊を防ぐためにAUTH0_ALLOW_DELETEフラグが設定可能です。https://github.com/auth0/auth0-deploy-cli/blob/master/examples/yaml/README.md#config