はじめに
前回は、TerraformでTROCCOのユーザーを作ったり消したりして利用イメージをご紹介しました。
今回は、実際にTerraformを使ってどのようにTROCCOのユーザーを管理していくと良さそうか、というところを考えていきたいと思います。
やりたいこと
TerraformでTROCCOのユーザーを作成するには下記情報を .tfファイルに書き込む必要があります。
resource "trocco_user" "example" {
email = "trocco@example.com"
password = "Jb1p4f1uuC"
role = "member"
can_use_audit_log = false
is_restricted_connection_modify = false
}
社内のユーザ管理や弊社Dさんが公開しているサンプルリポジトリを見てどのようにユーザ管理ができれば便利か考えてみました。
以下サンプルリポジトリから抜粋
admins = [
"${local.your_email_before_at}+admin1@${local.your_email_domain}",
]
developers = [
"${local.your_email_before_at}+dev1@${local.your_email_domain}",
"${local.your_email_before_at}+dev2@${local.your_email_domain}",
]
operators = [
"${local.your_email_before_at}+user1@${local.your_email_domain}",
"${local.your_email_before_at}+user2@${local.your_email_domain}",
]
こんな感じでグループごとに所属するメンバー(アドレス)を管理する方法が良さそう。
加えて、もっとこうなったら便利だな~と思ったものは下記です。
- emailのドメインは最初に定義しておいて毎回書かなくて良い状態にしたい
- 権限関連(role、can_use_audit_log、is_restricted_connection_modify)は所属グループで判別して自動で設定してほしい
これらができるように設定を進めていきます。
以下はすべて .tfファイル内の設定になります。
前回の記事で作成した .tfファイルに追記する、もしくは新しく .tfファイルを作成して同ディレクトリに配置しても問題ありません。
emailのドメインを定義する
Terraformでは、variableを使うことで変数を定義できるようです。
ドメイン(primenumber.co.jp)を下記のように定義しました。
variable "domain" {
default = "example.com"
}
ユーザーリストをつくる
今回は例として sales、tech、management の3部署分のユーザーリストを作りました
variable "departments" {
type = map(list(string))
default = {
"sales" = ["user1", "user2"]
"tech" = ["user3", "user4"]
"management" = ["user5"]
}
}
type = map(list(string))
を利用すると文字列のリストが作成できます。
https://qiita.com/hikaru_motomiya/items/d773355d3ffa854c7ad3#list
権限周りは所属グループに合わせて自動で設定する
続いて、権限を自動で設定できるようにします。
部署ごとに、どのように権限をつけるか指定します。
salesチーム、techチームはroleをmember、その他は無効にします。
managementチームはroleをadmin、can_use_audit_logを有効にします。
variable "role" {
type = map(object({
role = string
can_use_audit_log = bool
is_restricted_connection_modify = bool
}))
default = {
management = {
role = "admin"
can_use_audit_log = true
is_restricted_connection_modify = false
}
sales = {
role = "member"
can_use_audit_log = false
is_restricted_connection_modify = false
}
tech = {
role = "member"
can_use_audit_log = false
is_restricted_connection_modify = false
}
}
}
type = map(object ~)
でリストの要素1つずつに型を指定できます。
ユーザーを作成してみる
ChatGPTと話し合いをした結果、下記のようになりました。
resource "trocco_user" "example" {
for_each = tomap({
for idx, user in flatten([
for department, members in var.departments : [
for member in members : {
email = "${member}@${var.domain}"
role = var.role[lower(department)].role
can_use_audit_log = var.role[lower(department)].can_use_audit_log
is_restricted_connection_modify = var.role[lower(department)].is_restricted_connection_modify
}
]
]) : idx => user
})
email = each.value.email
password = "Jb1p4f1uuC"
role = each.value.role
can_use_audit_log = each.value.can_use_audit_log
is_restricted_connection_modify = each.value.is_restricted_connection_modify
}
処理の内容をご紹介していきます。
処理の内容についてはChatGPTを質問責めにして返ってきた内容でふわっと理解しています。
variable "departments"(var.departments)内に含まれるdepartment(部署)に対してループ実行します。キー(部署名)とその値(メンバー)取得し、部署ごとのメンバーリストを作ります。
for department, members in var.departments : [
取得例:
department = "sales", members = ["user1", "user2"]
部署の各メンバーに対してループ処理し、各メンバー毎のリストを作成します。
for member in members : {
このとき、下記内容も一緒に参照します。
role = var.role[lower(department)].role
can_use_audit_log = var.role[lower(department)].can_use_audit_log
is_restricted_connection_modify = var.role[lower(department)].is_restricted_connection_modify
取得例:
member = "user1"
email = "user1@example.com"
var.role_settings["sales"].role → "member"
var.role[lower(department)].can_use_audit_log → false
var.role[lower(department)].is_restricted_connection_modify → false
取得したリストをフラット化(flatten)します。
また、現時点ではキーが部署名のため一意のキーがありません。フラット化した各要素をループ処理してインデックス(idx)を割り当てます。
for idx, user in flatten ~~ : idx => user
Terraformのfor_eachに渡す値は、すべてユニークなキー(マップのキーやセットの要素)が必要です。下記のようにリソースの名前に使用されるため重複が許されないためです。重複しない値をさくっと生成してくれるのがインデックス(idx)です。
Terraform will perform the following actions:
# trocco_user.example["0"] will be created
~~~
# trocco_user.example["1"] will be created
~~~
for_each に渡す値を明示的にマップ型に変換します。リストや他のデータ構造をそのままfor_eachにわたすことができないためです。
for_each = tomap({
今実行しているループで取得した値を各要素に挿入します
email = each.value.email
password = "Jb1p4f1uuC"
role = each.value.role
can_use_audit_log = each.value.can_use_audit_log
is_restricted_connection_modify = each.value.is_restricted_connection_modify
実行してみる
処理の内容を認識したところでterraform plan
を実行してどのような結果になるか見てみます。
>terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
+ create
Terraform will perform the following actions:
# trocco_user.example["0"] will be created
+ resource "trocco_user" "example" {
+ can_use_audit_log = true
+ email = "user5@example.com"
+ id = (known after apply)
+ is_restricted_connection_modify = false
+ password = (sensitive value)
+ role = "admin"
}
# trocco_user.example["1"] will be created
+ resource "trocco_user" "example" {
+ can_use_audit_log = false
+ email = "user1@example.com""
+ id = (known after apply)
+ is_restricted_connection_modify = false
+ password = (sensitive value)
+ role = "member"
}
# trocco_user.example["2"] will be created
+ resource "trocco_user" "example" {
+ can_use_audit_log = false
+ email = "user2@example.com""
+ id = (known after apply)
+ is_restricted_connection_modify = false
+ password = (sensitive value)
+ role = "member"
}
# trocco_user.example["3"] will be created
+ resource "trocco_user" "example" {
+ can_use_audit_log = false
+ email = "user3@example.com""
+ id = (known after apply)
+ is_restricted_connection_modify = false
+ password = (sensitive value)
+ role = "member"
}
# trocco_user.example["4"] will be created
+ resource "trocco_user" "example" {
+ can_use_audit_log = false
+ email = "user4@example.com""
+ id = (known after apply)
+ is_restricted_connection_modify = false
+ password = (sensitive value)
+ role = "member"
}
Plan: 5 to add, 0 to change, 0 to destroy.
想定している設定になっていそうです!
反映させる
terraform apply
で反映してみます。(ドメインは環境に合わせて変更しています)
思った通りに動作して、無事権限の違いがあるアカウントを一括で作ることができました!
メンバーに変更が発生した場合はvariable "departments"
の各部署のメンバーを増減させるだけでよいので管理が単純化できそうですね。
おわりに
Terraformでは、処理を指示している文の中で下記のmember
のように要素の名前を定義し始めるので それどこから出てきた??? となることが多かったです・・・
for department, members in var.departments : [
for member in members : {
また、ループ処理をコードで指定するのは初めてだったのでどのように動作するのかなど全然わからず理解に時間がかかりました。
設定方法を理解するまでは コード管理むずい!!!GUIで設定で良くないか?? と思ったりもしました...。
ただ、設定が終わって実行してみると下記のようなメリットがあると実感でき、コード管理したいというご要望が多い理由もわかったような気がしました。
- 登録するユーザーの権限について考慮しなくて良い(部署だけ把握していればOK)
- 一括で複数ユーザーが操作できる(GUIでポチポチするより圧倒的に早い)(手軽さがすごい)
今回、部署毎でユーザ管理したので、TROCCOのチームもTerraformで管理するようにするとより便利になりそうです。
次はチーム管理もTerraformで行ってみたいと思います!