auth0をterraformで管理する


色々と便利なauth0ですが、いわゆるInfrastructure as a Codeがパッとできなかったのでメモ。

## terraform の auth0 providerを入れる
terraformのインストールは省略。

まず適当にファイルを用意

```
provider "auth0" {
  domain          = "moge.com"
  client_id       = "aaa"
  client_secret   = "bbb"
}
```

で、`terraform init` するとエラー。officialにないのかよ！

```
Initializing provider plugins...
- Checking for available provider plugins...

Provider "auth0" not available for installation.

A provider named "auth0" could not be found in the Terraform Registry.

This may result from mistyping the provider name, or the given provider may
be a third-party provider that cannot be installed automatically.

In the latter case, the plugin must be installed manually by locating and
downloading a suitable distribution package and placing the plugin's executable
file in the following directory:
    terraform.d/plugins/darwin_amd64

Terraform detects necessary plugins by inspecting the configuration and state.
To view the provider versions requested by each module, run
"terraform providers".


Warning: Skipping backend initialization pending configuration upgrade

The root module configuration contains errors that may be fixed by running the
configuration upgrade tool, so Terraform is skipping backend initialization.
See below for more information.


Error: no provider exists with the given name
```

野良pluginなのでdownloadして `terraform.d/plugins/darwin_amd64` に置けという話でした。なのでtarを持って来て解凍。


```
mkdir temp
cd temp

curl -OL https://github.com/alexkappa/terraform-provider-auth0/releases/download/v0.2.1/terraform-provider-auth0_v0.2.1_darwin_amd64.tar.gz

tar xzvf terraform-provider-auth0_v0.2.1_darwin_amd64.tar.gz
mv terraform-provider-auth0_v0.2.1 ..
cd ..
rm -Rf temp
```

試したところ `terraform.d/plugins/darwin_amd64` じゃなくてカレントディレクトリでも大丈夫っぽい。CIのときとかだとちゃんと配置すべきかもしれないけれど、ローカルでやる分にはカレントディレクトリでも問題なさそう。


その後に `terraform apply` したら `Apply complete! Resources: 0 added, 0 changed, 0 destroyed.` と出るのでauth0 providerはインストールおk。

## terraformでauth0をprovision

### tokenを取得して動かす
出だしからアレですが、auth0をまるっとterraform化というのは無理っぽいです。

というのもterraformが使用するAPIに必要なtokenを先に入手しないとダメだから。
大体以下のような手順。


 * アカウント作成orログインしてテナントを作る（手動）
 * トークン取得用のApplicationを作成（手動）
 * 作ったApplicationからtokenを取得（手動）
 * 取得したtokenをterraformで使う（ここから自動）

しかもテナントAのトークンで新しくテナントBを作るというのが不可能でした。
なのでテナントは自前で作った後にそれ以降の作成をterraformに任せるという感じに。
上記のauth0 providerだとテナントは作れるっぽいんですが、謎。

とはいえAWSで使う場合とは違って、まるっと名前を変えて別環境を作るみたいなのを認証の環境で頻繁にやるとはあまり思えないので、全部自動にしようと頑張りすぎるところではないのかもしれない。

設定に残すことが重要なのであって自動化に時間をかけすぎてしまうのはアレかなと。100個作るとかいうなら話は別だけど100個作るときになってから考えましょう。


#### auth0 テナント作成
右上メニュー -> Create Tenant -> 好きなドメイン名を入れる -> CREATE

#### Application作成
 * 左メニュー -> Application -> 右上の Create Application
 *  Nameは適当に。application typeは **Machine to Machine Application**
 * APIの選択 **Auth0 Management API** を選択 -> Select All -> Authorize ボタン
 * 作ったApplicationのページに行く -> Settingタブから **Client ID** と **Client Secret** を取って来てterraformに設定

### メモ
 * 普通にSPAで認証するときはSingle Page Applicationを使うけれど、ここではterraform用のapi keyが欲しいのでMachine to Machineを選ぶ
 * **Auth0 Management API** を選ぶのが重要。SPAで使用する際は認証を管理してもらうだけなので不要だが、今回はauth0を外部から操作するための権限が欲しいので **Auth0 Management API** を選ぶ。
   * **Auth0 Management API** にあたる部分は自分でも作成可能なので、よしなにドメインを作成して、自分でscopeを決めれば自分のアプリでauth0に任せっきりでRBACができる。今度試す。
 * **Auth0 Management API** で **Select All** は危険なので開発終わったら適宜権限を絞る。


### 完成したtfファイル
```
variable "auth0_domain" {}
variable "auth0_client_id" {}
variable "auth0_client_secret" {}

variable "application_name" { default = "Test" }
variable "application_domain" { default = "https://example.com" }

provider "auth0" {
  domain        = var.auth0_domain
  client_id     = var.auth0_client_id
  client_secret = var.auth0_client_secret
}

resource "auth0_client" "app" {
  name                  = var.application_name
  description           = "(Managed by Terraform)"
  app_type              = "spa"
  is_first_party        = true
  oidc_conformant       = true
  callbacks             = [ "${var.application_domain}/callback" ]
  allowed_origins       = [ var.application_domain ]
  allowed_logout_urls   = [ var.application_domain ]
  web_origins           = [ var.application_domain ]
  grant_types           = [ "authorization_code", "implicit", "refresh_token" ]
  custom_login_page_on  = true
  token_endpoint_auth_method = "none"
  is_token_endpoint_ip_header_trusted = false

  jwt_configuration {
    lifetime_in_seconds = 36000
    secret_encoded = true
    alg = "RS256"
  }
}

resource "auth0_resource_server" "api" {
  name        = "${var.application_name} (Managed by Terraform)"
  identifier  = "https://api.example.com"
  signing_alg = "RS256"

  scopes {
    value       = "create:foo"
    description = "Create foos"
  }

  scopes {
    value       = "create:bar"
    description = "Create bars"
  }

  allow_offline_access                            = false
  token_lifetime                                  = 86400
  skip_consent_for_verifiable_first_party_clients = true
}
```

自分のアプリでRBACを使って見たいのでAPIもついでに作成。
設定はこれで終わり。今度はクライアント側を試しましょう。


## 参考

https://blog.pirox.dev/2019/05/31/083201
https://github.com/alexkappa/terraform-provider-auth0