kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Auth0 Terraform Provider: Auth0 の設定を Terraform で管理しよう

Auth0 Terraform Provider を使うと Auth0 の設定を Terraform で宣言的に管理できる.もちろん Terraform の仕組みに沿って terraform plan コマンドで確認してから terraform apply コマンドでデプロイできる❗️Auth0 Terraform Provider を試したログをまとめる.今回は「ゼロから実装」「既存リソースをインポートして実装」を試した \( 'ω')/

github.com

Auth0 Deploy CLI

Auth0 の設定を自動デプロイするときの選択肢として,Auth0 Terraform Provider 以外に YAML ベースの Auth0 Deploy CLI もある💡 a0deploy コマンドを使って Auth0 の設定をエクスポート・インポートできて,Keyword Replacement 機能を使えば YAML ファイルに環境変数を挿入できる拡張性もある.Auth0 Terraform Provider と Auth0 Deploy CLI の比較は以下に載っている📝

auth0.com

ドキュメントにも載っている通り,普段から Terraform を使っているなら Auth0 Terraform Provider を採用するのが良さそう.Auth0 のために Terraform 環境をゼロから構築するのは学習コストも含めて大変さはあるとは思うけど,Auth0 Deploy CLI には terraform plan コマンドに相当するドライラン機能(変更検出)がなく,ドライランのために Auth0 Terraform Provider を採用するという意思決定もあると思う.ちなみに Auth0 Deploy CLI のドライラン機能は2018年から解決されてなく厳しそう💨

github.com

Auth0 Terraform Provider を試す(ゼロから実装)

さっそく Quickstart ドキュメントを参考に Auth0 Terraform Provider を試す❗️

1. M2M Application を追加する

まずは Auth0 を操作するための M2M (Machine-to-Machine) Application を Auth0 コンソールで追加する.今回は Auth0 Terraform Provider という名前にした.そして Domain / Client ID / Client Secret を取得して環境変数に設定しておく.

$ export AUTH0_DOMAIN=''
$ export AUTH0_CLIENT_ID=''
$ export AUTH0_CLIENT_SECRET=''

2. Application: terraform init コマンドを実行する

providers.tf を実装して Auth0 Terraform Provider を取得する.

👾 providers.tf

terraform {
  required_providers {
    auth0 = {
      source  = "auth0/auth0"
      version = ">= 1.4.0"
    }
  }
}

provider "auth0" {}

3. Application: terraform plan コマンドを実行する

次に clients.tf を実装する.まずは Auth0 Application を auth0_client リソースを使って追加する.設定は必要最低限にして,今回は SPA タイプで,URL 関連は http://localhost:3000 にした👌後ほど動作確認で使う.

👾 clients.tf

resource "auth0_client" "sample" {
  name                = "ReactSamples"
  app_type            = "spa"
  callbacks           = ["http://localhost:3000"]
  allowed_origins     = ["http://localhost:3000"]
  allowed_logout_urls = ["http://localhost:3000"]
  web_origins         = ["http://localhost:3000"]
}

そして terraform plan コマンドを実行する.Auth0 Deploy CLI に慣れていると「plan できるの最高じゃん」という気持ちになる😀 実際にオペレーションに自信が持てるようになる.

$ terraform plan
Terraform will perform the following actions:

  # auth0_client.sample will be created
  + resource "auth0_client" "sample" {
      + allowed_logout_urls                 = [
          + "http://localhost:3000",
        ]
      + allowed_origins                     = [
          + "http://localhost:3000",
        ]
      + app_type                            = "spa"
      + callbacks                           = [
          + "http://localhost:3000",
        ]
      + client_id                           = (known after apply)
      + custom_login_page_on                = (known after apply)
      + grant_types                         = (known after apply)
      + id                                  = (known after apply)
      + is_first_party                      = (known after apply)
      + is_token_endpoint_ip_header_trusted = (known after apply)
      + name                                = "ReactSamples"
      + oidc_conformant                     = (known after apply)
      + signing_keys                        = (sensitive value)
      + web_origins                         = [
          + "http://localhost:3000",
        ]
    }

Plan: 1 to add, 0 to change, 0 to destroy.

4. Application: terraform apply コマンドを実行する

最後は terraform apply コマンドを実行する.

$ terraform apply

auth0_client.sample: Creating...
auth0_client.sample: Creation complete after 0s [id=xxxxx]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

できた❗️最高 \( 'ω')/

ReactSamples Application を追加できた

5. API: terraform plan コマンドと terraform apply コマンドを実行する

今度は resource-servers.tf を実装する.Auth0 API を auth0_resource_server リソースを使って追加する.設定は必要最低限にした👌

👾 resource-servers.tf

resource "auth0_resource_server" "sample" {
  name        = "ReactSamples"
  identifier  = "https://react.samples.com"
  signing_alg = "RS256"
}

同じく terraform plan コマンドと terraform apply コマンドを実行する.

$ terraform plan
Terraform will perform the following actions:

  # auth0_resource_server.sample will be created
  + resource "auth0_resource_server" "sample" {
      + enforce_policies                                = (known after apply)
      + id                                              = (known after apply)
      + identifier                                      = "https://react.samples.com"
      + name                                            = "ReactSamples"
      + signing_alg                                     = "RS256"
      + signing_secret                                  = (known after apply)
      + skip_consent_for_verifiable_first_party_clients = (known after apply)
      + token_dialect                                   = (known after apply)
      + token_lifetime                                  = (known after apply)
      + token_lifetime_for_web                          = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

$ terraform apply
auth0_resource_server.sample: Creating...
auth0_resource_server.sample: Creation complete after 1s [id=xxxxx]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

おー \( 'ω')/

ReactSamples API を追加できた

6. 動作確認をする

追加した Auth0 Application と Auth0 API を使って動作確認をする.今回はサクッと試せる Auth0 React Samples を使う.

github.com

フロントエンドを起動して,Log in ボタンを押すと Auth0 の認証画面が出て,Sign up ボタンからサインアップするとログインできた❗️Auth0 Terraform Provider で追加したリソースを期待通りに使えた.

Auth0 React Samples: 初期画面

Auth0 React Samples: ログイン画面

Auth0 React Samples: ログイン後

7. Google 認証を無効化する

デフォルトでは Google 認証が有効化されていて,ログイン画面に Continue with Google が表示されている.今度は Auth0 Terraform Provider で Google 認証を無効化する.

さっそく connections.tf を実装する.Auth0 Terraform Provider には auth0_connection_client リソースと auth0_connection_clients リソースがあって,併用はしないようにとドキュメントに書かれていた.今回は auth0_connection データソースと auth0_connection_client リソースを使って Auth0 Application と Auth0 Connection を紐付ける🔗

ただし Auth0 Connection は自動的に設定されてしまっていて,一度 Terraform リソースを作ってから削除してみた😇(もしくはリソースをインポートする案もあると思う)

👾 connections.tf

connection_idUsername-Password-AuthenticationIdentifiergoogle-oauth2Identifier を Auth0 コンソールから取得しておく.

data "auth0_connection" "username_password_authentication" {
  connection_id = "con_xxxxx"
}

data "auth0_connection" "google_oauth2" {
  connection_id = "con_xxxxx"
}

resource "auth0_connection_client" "sample_username_password_authentication" {
  client_id     = auth0_client.sample.id
  connection_id = data.auth0_connection.username_password_authentication.connection_id
}

resource "auth0_connection_client" "sample_google_oauth2" {
  client_id     = auth0_client.sample.id
  connection_id = data.auth0_connection.google_oauth2.connection_id
}

terraform plan コマンドと terraform apply コマンドを実行する.

$ terraform plan
Terraform will perform the following actions:

  # auth0_connection_client.sample_google_oauth2 will be created
  + resource "auth0_connection_client" "sample_google_oauth2" {
      + client_id     = "xxxxx"
      + connection_id = "con_xxxxx"
      + id            = (known after apply)
      + name          = (known after apply)
      + strategy      = (known after apply)
    }

  # auth0_connection_client.sample_username_password_authentication will be created
  + resource "auth0_connection_client" "sample_username_password_authentication" {
      + client_id     = "xxxxx"
      + connection_id = "con_xxxxx"
      + id            = (known after apply)
      + name          = (known after apply)
      + strategy      = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

$ terraform apply
auth0_connection_client.sample_google_oauth2: Creating...
auth0_connection_client.sample_username_password_authentication: Creating...
auth0_connection_client.sample_google_oauth2: Creation complete after 0s [id=con_xxxxx::xxxxx]
auth0_connection_client.sample_username_password_authentication: Creation complete after 0s [id=con_xxxxx::xxxxx]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

次に無効化する Google 認証を削除する(今回はコメントアウトにした).

👾 connections.tf

# resource "auth0_connection_client" "sample_google_oauth2" {
#   client_id     = auth0_client.sample.id
#   connection_id = data.auth0_connection.google_oauth2.connection_id
# }

もう一度 terraform plan コマンドと terraform apply コマンドを実行すると Google 認証を削除できた❗️

$ terraform plan
Terraform will perform the following actions:

  # auth0_connection_client.sample_google_oauth2 will be destroyed
  # (because auth0_connection_client.sample_google_oauth2 is not in configuration)
  - resource "auth0_connection_client" "sample_google_oauth2" {
      - client_id     = "xxxxx" -> null
      - connection_id = "con_xxxxx" -> null
      - id            = "con_xxxxx::xxxxx" -> null
      - name          = "google-oauth2" -> null
      - strategy      = "google-oauth2" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

$ terraform apply
auth0_connection_client.sample_google_oauth2: Destroying... [id=con_xxxxx::xxxxx]
auth0_connection_client.sample_google_oauth2: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

Google 認証を削除できた

Auth0 React Samples: ログイン画面(Google 認証なし)

イイ感じ❗️

Auth0 Terraform Provider を試す(既存リソースをインポートして実装)

現状まだ experimental(実験的機能)ではあるけど,Auth0 の既存設定を Terraform の import ブロックとしてエクスポートする機能がある👀 さっそく Auto-generating Terraform config from Auth0 tenant ドキュメントを参考に試す❗️

1. GenerateSamples Application を追加する

インポート対象として Auth0 コンソールで Auth0 Application を追加しておく❗️

GenerateSamples Application を追加した

2. Auth0 CLI をセットアップする

ドキュメントを参考に Auth0 CLI(auth0 コマンド)をセットアップする.

$ auth0 --version
auth0 version 1.4.0 54e9a30eeb58a4a7e40e04dc19af6869036bfb32

auth0.github.io

3. auth0 tf generate コマンドを実行する

そして auth0 tf generate コマンドを実行すると,指定した tmp-auth0-tf ディレクトリに auth0_generated.tfauth0_import.tf などがエクスポートされる👌 auth0_generated.tf ファイルにはリソース実装が含まれていて,auth0_import.tf には import ブロックが含まれている.対象のリソースが多くコード量はそこそこ多かった.

$ auth0 tf generate --output-dir tmp-auth0-tf
Fetching data from Auth0... done
Generating Terraform configuration... done

4. 既存リソースを Terraform 管理にする

エクスポートされた auth0_generated.tfauth0_import.tf などをそのままデプロイして紐付けることもできるけど,今回は GenerateSamples Application の import ブロックとリソース実装を抜き出して clients.tf に追加してみた.

👾 clients.tf

import {
  id = "xxxxx"
  to = auth0_client.generatesamples
}

resource "auth0_client" "generatesamples" {
  allowed_clients                       = []
  allowed_logout_urls                   = ["http://localhost:3000"]
  allowed_origins                       = ["http://localhost:3000"]
  app_type                              = "spa"
  callbacks                             = ["http://localhost:3000"]
  client_aliases                        = []
  client_metadata                       = {}
  cross_origin_auth                     = false
  cross_origin_loc                      = null
  custom_login_page                     = null
  custom_login_page_on                  = true
  description                           = null
  encryption_key                        = {}
  form_template                         = null
  grant_types                           = ["authorization_code", "implicit", "refresh_token"]
  initiate_login_uri                    = null
  is_first_party                        = true
  is_token_endpoint_ip_header_trusted   = false
  logo_uri                              = null
  name                                  = "GenerateSamples"
  oidc_backchannel_logout_urls          = []
  oidc_conformant                       = true
  organization_require_behavior         = null
  organization_usage                    = null
  require_pushed_authorization_requests = false
  sso                                   = false
  sso_disabled                          = false
  web_origins                           = ["http://localhost:3000"]
  jwt_configuration {
    alg                 = "RS256"
    lifetime_in_seconds = 36000
    scopes              = {}
    secret_encoded      = false
  }
  native_social_login {
    apple {
      enabled = false
    }
    facebook {
      enabled = false
    }
  }
  refresh_token {
    expiration_type              = "expiring"
    idle_token_lifetime          = 1296000
    infinite_idle_token_lifetime = false
    infinite_token_lifetime      = false
    leeway                       = 0
    rotation_type                = "rotating"
    token_lifetime               = 2592000
  }
}

5. terraform plan コマンドと terraform apply コマンドを実行する

そして terraform plan コマンドと terraform apply コマンドを実行して既存リソースをインポートできた👌

$ terraform plan
Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

$ terraform apply
auth0_client.generatesamples: Importing... [id=xxxxx]
auth0_client.generatesamples: Import complete [id=xxxxx]

Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

6. 既存リソースを更新する

インポートしたリソースの更新を試すため,GenerateSamples Application の description を更新した.ちなみに encryption_key はエクスポートした状態だと Payload validation error: 'Too few properties defined (0), minimum 1' on property encryption_key (The client's encryption key). というエラーになったため,行ごと削除した.

👾 clients.tf

-  description                           = ""
-  encryption_key                        = {}
+  description                           = "This is an application to try the `auth0 tf generate` command"

terraform plan コマンドと terraform apply コマンドを実行すると description を更新できた❗️

$ terraform plan
Terraform will perform the following actions:

  # auth0_client.generatesamples will be updated in-place
  ~ resource "auth0_client" "generatesamples" {
      + description                           = "This is an application to try the `auth0 tf generate` command"
        id                                    = "xxxxx"
        name                                  = "GenerateSamples"
        # (21 unchanged attributes hidden)

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

$ terraform apply
auth0_client.generatesamples: Modifying... [id=xxxxx]
auth0_client.generatesamples: Modifications complete after 0s [id=xxxxx]

description を更新できた

まとめ

Auth0 Terraform Provider を使って Auth0 の設定を Terraform で宣言的に管理しよう❗️