
Terraform+CSV+GitHub ActionsでGitHub Organizationのメンバー管理をやってみた-①概要・利用方法編
こんにちは!クラウド事業本部の吉田です。
皆さん、GitHub Organization利用していますか?
GitHub Organizationを運用するにあたって、課題の1つとなってくることはメンバー管理だと思います。
GitHub Organizationでのメンバー管理に関するトラブルとして以下が考えられます。
- Onwer権限を持つユーザーが少なく、メンバー管理の負荷が特定の人に集中する
- 余裕がないタイミングで作業をするとミスをする可能性が高くなる
- Owner権限を持つユーザーが大量にあり各々がメンバーを追加するためメンバー管理が難しくなる
- 誰のものがわからないGitHubユーザーがある
- Organizationに招待していいユーザーなのか精査できていない
- 全ユーザーの権限管理がおざなりになる
このような問題に対応するためにTerraformによるIaC化がよく活用されています。
他社の事例:
当記事はTerraform+CSV+GitHub Actionsを利用して、GitHub Organizationのメンバー管理をする方法を紹介させていただきます。
内容が多いため、記事を分割しております。
当記事は仕組みの概要と利用方法を解説しております。
この仕組みを導入する際は、当記事で大まかな内容を把握した後、初期構築の記事を参照し構築してください。
また、詳細な仕組みに関しても別記事でまとめます。
記事リンク
- Terraform+CSV+GitHub ActionsでGitHub Organizationのメンバー管理をやってみた-①概要・利用方法編 ←イマココ
- Terraform+CSV+GitHub ActionsでGitHub Organizationのメンバー管理をやってみた-②初期構築編
- Terraform+CSV+GitHub ActionsでGitHub Organizationのメンバー管理をやってみた-③仕組み編
サンプルコード
サンプルコードは、下記のリポジトリで公開しております。
OrganizationにOrganization管理用のリポジトリを作成し、サンプルコードを展開してください。
READMEに記載しています通り、GitHub Appsトークン生成スクリプトとGitHub Actionsワークフロー上のGitHub Appsトークン生成に関するステップは下記の記事から引用しております。
GitHub Appsトークン解体新書:GitHub ActionsからPATを駆逐する技術
サンプルコードのディレクトリ/ファイル構成
.
├── .github/
│ └── workflows/ #GitHub Actionsのワークフローファイルの格納フォルダ
│ ├── apply.yml # Pull Requestマージ時に実行されるterraform apply用ワークフローファイル
│ └── plan.yml # Pull Request時に実行されるterraform plan用ワークフローファイル
├── shell/
│ └── script.sh # GitHub Appsトークン生成用シェルスクリプト
├── terraform/ #tfファイル格納用フォルダ
│ ├── module/
│ │ └── terraform-github-organization/ # Organizationのメンバー管理用モジュールフォルダ
│ │ ├── main.tf # モジュールのメインtfファイル
│ │ └── variables.tf # モジュールの変数用tfファイル
│ ├── .terraform.lock.hcl # terraform init時に自動生成されるプロバイダロックファイル
│ ├── organization.tf # モジュールに渡す引数を定義するtfファイル。チーム追加時などに更新するファイル
│ ├── README.md # organization.tfの内容を説明したREADMEファイル
│ └── versions.tf # terraform version、プロパイダー、バックエンドを指定するファイル
├── users/ #メンバー管理用のCSVファイルを格納するフォルダ
│ └── *.csv
├── .gitignore
└── README.md
概要・機能
GitHubリソースを管理するためのGitHub Providerがあります。
このGitHub Providerを利用して、Organization・チームのメンバー管理を行います。
Organization・チームのメンバー情報はCSV、チーム情報はtfファイルで管理します。
CSVにはGitHubのアカウント名と合わせてメールアドレスを記載することで、GitHubアカウントの個人を特定しやすくします。
主要なファイルの関連性は以下の通りです。
新しくチームを作成したりメンバーを追加する際に、gitのブランチを切ってファイルを更新した後Pull Requestを作成します。
GitHub ActionsによってPull Request作成時にterraform plan
、Pull Requestマージ時にterraform apply
が実行されます。
terraform plan
、terraform apply
実行時はGitHub Appsトークンの権限を利用します。
(詳細はTerraform+CSV+GitHub ActionsでGitHub Organizationのメンバー管理をやってみた-③仕組み編で説明します。)
つまり、実際のOrganization・チームのメンバー管理の処理はGitHub Appsトークンの権限を利用するので、Organization管理用のリポジトリへのwrite権限があればOwner以外のメンバーもメンバー管理作業(CSVファイル更新など)ができます。
例えば、チームリーダー用のチームを作成し、そのチームにリポジトリのwrite権限を渡すことで各チームのメンバー管理作業をチームリーダーに委任することができます。
管理者は承認作業に徹することができるので、管理者のメンバー管理の負担を軽減することができます。
この仕組みを利用することで、実現できる機能としては以下の通りです。
- Organizationのメンバー管理
- ロール管理(Onwer/Member)
- チームの新規作成
- チームのメンバー管理
- ロール管理(Memtainer/Member)
- 手動作成の既存チームのメンバー管理も可能
- Pull Requestによる承認フロー
全体の流れ
- トピックブランチを作成
# main へ switch
$ git switch main
# リモートの main ブランチをローカルに取り込み
$ git pull
# トピックブランチを作成
$ git switch -c <ブランチ名>
- TerraformコードまたはCSVファイルを編集。詳細な内容は、後述のTerraformコードまたはCSVファイルの編集箇所を参照。
- リモートへブランチをPush
# 変更をステージングに追加
$ git add .
# 変更をコミット
$ git commit -m "<Commit message>"
# ローカルブランチをリモートへ Push
$ git push origin <ブランチ名>
- GitHub上でPull Requestを作成
- (随時)Pull Requestのコメントに
terraform validate
によるエラーが出力されたら、内容を確認してterraformコードを修正 - Pull Requestのコメントに出力される
terraform plan
の実行結果を確認し意図せぬ変更がないか確認。詳細な内容は、後述のPull Request時のterraform plan出力内容を参照。 - レビュアーがGitHub上でPull Requestをレビュー&マージ
- 下記のファイルが更新されている可能性があります
- .terraform.lock.hcl
- ワークフロー上の
terraform init
による更新
- ワークフロー上の
- organization.tf
- ワークフロー上の
terraform fmt
によるフォーマット
- ワークフロー上の
- .terraform.lock.hcl
- 下記のファイルが更新されている可能性があります
- Pull Requestのコメントに出力される
terraform apply
の実行結果を確認しエラーがないか確認。詳細な内容はPull Requestマージ時のterraform apply出力内容を参照。
TerraformコードまたはCSVファイルの編集箇所
各パターンで、ファイルの更新する箇所が変わります。
更新する主要なファイルは下記の通りです。
- userフォルダ配下のCSVファイル
- 新規チーム作成時などは新規CSVファイルを作成してください
- terraformフォルダ配下のorganization.tf
- モジュールに渡す引数を定義するtfファイルです。新規チーム作成時は新規チーム用の設定を追記する必要があります。
- 詳細な利用方法はorganization.tf用のREADMEを参照してください。
Organization
Ownerロールのメンバー管理
- Owner用のCSVファイルをusersフォルダ配下に作成
- CSVファイルの名前にこだわりがなければ、サンプルコードと同じ
owners.csv
を利用してください。 - CSVファイルの1行目は必ず「username,email」としてください。
- CSVファイルの名前にこだわりがなければ、サンプルコードと同じ
username,email
owner-user,owner-user@owner.jp
- terraform/organization.tf
- 変数名・CSVファイルの名前にこだわりがなければ更新不要です。更新する場合は、下記の箇所を更新してください。
- localsブロック
- moduleブロックのownersキー
- 変数名・CSVファイルの名前にこだわりがなければ更新不要です。更新する場合は、下記の箇所を更新してください。
locals {
------更新-------
<Owner用変数> = csvdecode(file("../users/Owner用CSV名"))
----------------
}
module "organization" {
(省略)
------更新-------
owners = local.<Owner用変数>[*].username
----------------
}
Memberロールのメンバー管理
- Member用のCSVファイルをusersフォルダ配下に作成
- CSVファイルの名前にこだわりがなければ、サンプルコードと同じ
members.csv
を利用してください。 - CSVファイルの1行目は必ず「username,email」としてください。
- CSVファイルの名前にこだわりがなければ、サンプルコードと同じ
username,email
member-user,member-user@member.jp
- terraform/organization.tf
- 変数名・CSVファイルの名前にこだわりがなければ更新不要です。更新する場合は、下記の箇所を更新してください。
- localsブロック
- moduleブロックのmembersキー
- 変数名・CSVファイルの名前にこだわりがなければ更新不要です。更新する場合は、下記の箇所を更新してください。
locals {
------更新-------
<Member用変数> = csvdecode(file("../users/Member用CSV名"))
----------------
}
module "organization" {
(省略)
------更新-------
members = local.<Member用変数>[*].username
----------------
}
チーム
新規チーム作成
- 新規チーム用のCSVファイルをusersフォルダ配下に作成
- CSVファイルの1行目は必ず「username,email」としてください。
username,email
test-user,test-user@test.jp
- terraform/organization.tfの下記の箇所に既存チーム用の設定を追記
- localsブロック
- moduleブロックのteamsオブジェクト
- 新規チーム作成時のみnameキーの値に「大文字・スペース」が利用できます。(例:Test Team)
locals {
------追加-------
<新規チーム用変数> = csvdecode(file("../users/<新規チーム用CSV名>"))
----------------
}
module "organization" {
(省略)
teams = [
------追加-------
{
name = "<新規チーム名>"
members = local.<新規チーム用変数>[*].username
}
----------------
]
}
手動で作成した既存チームのメンバー管理
- 手動で作成した既存チーム用のCSVファイルをusersフォルダ配下に作成
- CSVファイルの1行目は必ず「username,email」としてください
- Teamに既に参加しているメンバーの情報をCSVを記載することで、terraformによる管理対象にすることができます
username,email
exsit-user,exsit-user@exsit.jp
- terraform/organization.tfの下記の箇所に既存チーム用の設定を追記・更新
- localsブロック
- moduleブロックのexisting_teamsキー
- 手動で作成した既存チーム情報を取得するために必ずチーム名は slug形式 で指定してください
- slug形式のチーム名は、チームのURLから確認してください
- https://github.com/orgs/<Organization名>/teams/ <slug形式のチーム名>
- moduleブロックのteamsオブジェクト
- こちらのnameキーの値も、 slug形式 のチーム名で指定してください
locals {
------追加-------
<既存チーム用変数> = csvdecode(file("../users/<既存チーム用CSV名>"))
----------------
}
module "organization" {
(省略)
------更新-------
existing_teams = ["<既存チーム名>"]
----------------
teams = [
------追加-------
{
name = "<既存チーム名>"
members = local.<既存チーム用変数>[*].username
}
----------------
]
}
メンバーの追加・削除
メンバーを追加する場合は、CSVに追加するメンバーの情報を追加してください。
メンバーを削除する場合は、CSVから削除するメンバーの情報を削除してください。
チーム削除(Terraformで作成したチームのみ)
terraform/organization.tfから削除対象のチームに関する設定を削除してください。
また、削除対象のチーム用のCSVファイルも削除してください。
手動で作成した既存チームに関しては、terraform/organization.tfから設定を削除しても、削除されません
留意事項
- GitHubアカウントの個人を特定するために、CSVにユーザー名だけでなくメールアドレスも記載するようにしております。
- terraform/organization.tfのmoduleブロックのteamsオブジェクトでは、membersキー以外にもmaintainersキーを利用することでMaintainer(チームロール)を割り当てたいユーザーを指定できます。ただし、チームメンバー管理はterraformで管理するため、基本的にはmaintainersキーは利用しなくても問題ありません。
- ただしOwner(組織ロール)権限のメンバーをmembersキーで指定しますと、チーム追加時に自動的にMaintainer(チームロール)が付与されます。チームロールの差分が発生するため、Owner(組織ロール)権限のメンバーをTeamに参加させる場合はmaintainersキーを利用してください。
Pull Request
ファイル更新後はPull Requestを作成します。
下記のキャプチャのように、GitHub Actionsのワークフローによってterraform plan
、terraform apply
が実行された際、botが出力内容をコメントします。
Pull Request時のterraform plan出力内容
Pull Requestを作成後、Pull Requestにterraform plan
の出力内容がコメントされます。
出力される内容は主に下記の通りです。
- チーム作成・削除時
- module.organization. github_team .main["チーム名"] will be created/destroyed
- チームにメンバーを追加・削除時
- module.organization. github_team_membership .main["チーム名" "アカウント名"] will be created/destroyed
出力例
- 「Test Team」作成
# module.organization.github_team.main["Test Team"] will be created
+ resource "github_team" "main" {
+ etag = (known after apply)
+ id = (known after apply)
+ name = "Test Team"
+ node_id = (known after apply)
+ privacy = "closed"
+ slug = (known after apply)
}
- 「Test Team」に「test-user」を追加
# module.organization.github_team_membership.main["Test Team test-user"] will be created
+ resource "github_team_membership" "main" {
+ etag = (known after apply)
+ id = (known after apply)
+ role = "member"
+ team_id = (known after apply)
+ username = "test-user"
}
terraform planの内容を確認し、問題がなければマージしてください。
Pull Requestマージ時のterraform apply出力内容
Pull Requestマージ後、Pull Requestにterraform apply
の出力内容がコメントされます。
コメントの最後に「Apply complete!」と出力されていることを確認してください。
出力例
Terraform will perform the following actions:
# module.organization.github_team_membership.main["Test Team test-user"] will be created
+ resource "github_team_membership" "main" {
+ etag = (known after apply)
+ id = (known after apply)
+ role = "member"
+ team_id = (known after apply)
+ username = "test-user"
}
Plan: 1 to add, 0 to change, 0 to destroy.
module.organization.github_team_membership.main["Test Team test-user"]: Creating...
module.organization.github_team_membership.main["Test Team test-user"]: Creation complete after 2s [id=12118962:test-user]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
最後に
当記事で紹介した仕組みは、私が所属する事業部のGitHub Organizationのメンバー管理の仕組みを元としており、いくつかのアップデートを加えた形となります。
元の仕組みを構築していただいた方に感謝の気持ちでいっぱいです。
記事はまだ続きますので、続きの記事も読んでいただけると嬉しいです!
以上、クラウド事業本部の吉田でした!