11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HRBrainAdvent Calendar 2024

Day 13

TerraformでGitHubのteamやmemberを管理する

Last updated at Posted at 2024-12-12

こんにちは、株式会社HRBrainのプラットフォームチームに所属している永山(@ikorihn)です。

GitHub Organization配下のチームや所属メンバーの管理をTerraformに移行しましたので、この記事ではその時の対応内容をお伝えします。

本記事はHRBrain Advent Calendar 2024の13日目の記事です。

はじめに

所属メンバーやチームの数が増えてくるに従い、以下のような課題が発生していました。

  • だれがどのチームに所属しているか把握しづらい
  • 異動の際に管理者が手動でチームメンバーを変更していて手間な上、履歴が残らない
  • 本名とGitHubアカウントとの突合がしづらい

これらの問題を解決するため、メンバーの一覧や各チームの定義をTerraformで管理することにしました。

GitHub Provider

公式に提供されているGitHub Providerを使用します。

providerの設定

GitHubの操作に必要なtokenは、GitHub Actions内で生成したアクセストークンを渡すことにします(後述)

provider.tf
terraform {
  required_providers {
    github = {
      source  = "integrations/github"
      version = "~> 6.0"
    }
  }
}

provider "github" {
  owner = "<organization name>"
  token = var.github_app_token
}

variable "github_app_token" {
  type = string
}

所属メンバー

メンバーの管理にはgithub_membershipリソースを使用します。
for_each で定義しました。

members.tf
locals {
  hrbrain_members = {
    full_name1 = { username = "<github user 1>", role = "admin" },

    full_name2 = { username = "<github user 2>", role = "member" },
    full_name3 = { username = "<github user 3>", role = "member" },
  }
}

resource "github_membership" "members" {
  for_each = local.hrbrain_members
  username = each.value.username
  role     = each.value.role
}

メンバーの一覧は、組織ownerにCSVでダウンロードしてもらったものを加工して作成しました。

login	name	saml_name_id
user1	User Name1	full_name1@ドメイン
user2	User Name2	full_name2@ドメイン

チーム

チーム自体の定義にはgithub_teamリソース、チームメンバーの管理にはgithub_team_membersリソースを使用します。

team_team1.tf
resource "github_team" "team1" {
  name           = "team1"
  parent_team_id = github_team.developer.id # 子チームとして定義する場合はこれを指定する
  privacy        = "closed"
}

resource "github_team_members" "team1" {
  team_id = github_team.team1.id
  members {
    username = github_membership.members["full_name2"].username
    role     = "maintainer"
  }
  members {
    username = github_membership.members["full_name3"].username
    # roleを指定しない場合デフォルトでmemberとなる
  }
}

このファイルをチームごとに作成しています。
ただ、既存のチームの設定すべてを手で書いていくのが大変でしたので、後述のimport blockと terraform plan -generate-config-out を用いて作成しました。

既存の設定をTerraform管理下にimportする

すでに作成済みのチームやメンバーをTerraformの管理化に追加するためにimportしていきます。
Terraform v1.5.0で追加されたImport blockを使用して移行しました。

importブロックのidにはインポート元、toにはインポート先リソースの識別子を指定します。
idのフォーマットは、resourceドキュメントのImportを見るとわかります。
たとえばgithub_membershipであれば <organization>:<username> を指定します。

メンバーのimportブロックを作る

id<organization>:<username>togithub_membership のリソース識別子を指定します。
こちらも for_each で作成できます。

members.tf
import {
  for_each = local.hrbrain_members
  id       = "<organization>:${each.value.username}"
  to       = github_membership.members[each.key]
}

チームのimportブロックを作る

GitHubのAPIでチーム一覧をJSONで取得したあと、github_team およびgithub_team_members のimportブロックに加工します。

$ gh api --paginate /orgs/<organization>/teams > teams.json

$ cat teams.json | jq -cr '.[] | "import {|  id = " + (.id | tostring) + "|  to = github_team." + .slug + "|}"' | sed 's/|/\n/g' > import_teams.tf
$ cat teams.json | jq -cr '.[] | "import {|  id = " + (.id | tostring) + "|  to = github_team_members." + .slug + "|}"' | sed 's/|/\n/g' | >> import_team_members.tf
import_teams.tf
import {
  id = 1234567
  to = github_team.team1
}
import {
  id = 1234568
  to = github_team.team2
}

import {
  id = 1234567
  to = github_team_members.team1
}
import {
  id = 1234568
  to = github_team_members.team2
}

generate-config-out オプションによって、importブロックからHCLを作成できるようになっています。

$ terraform plan -generate-config-out=generated.tf

実行すると次のようなファイルが生成されるので、これを編集して各チームのtfファイルを作成しました。

generated.tf
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "1234567"
resource "github_team" "team1" {
  name           = "team1"
  privacy        = "closed"
}

# __generated__ by Terraform from "1234568"
resource "github_team" "team2" {
  name           = "team2"
  privacy        = "closed"
}

# __generated__ by Terraform from "1234567"
resource "github_team_members" "team1" {
  team_id = jsonencode("1234567")
  members {
    username = "user1"
    role     = "maintainer"
  }
}

# __generated__ by Terraform from "1234568"
resource "github_team_members" "team2" {
  team_id = jsonencode("1234568")
  members {
    username = "user1"
    role     = "maintainer"
  }
  members {
    username = "user2"
    role     = "member"
  }
}

あとは terraform apply を実行すると、リソースがimportされます。

$ terraform apply
Terraform will perform the following actions:

  # github_team.team1 will be imported
    resource "github_team" "team1" {
....

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

ここまで来たらimportブロックは削除してOKです。

GitHub ActionsでTerraformを実行する

プルリクエストベースで terraform apply を実行するために、GitHub Actionsを設定します。
GitHubのアクセストークンは、job内でCreate GitHub App Tokenを使って生成します。

まずはGitHub Appを作成します。
権限はOrganization permissions for "Members"をつけます。
作成したGitHub AppのIDをリポジトリのvariableに、private keyをsecretに設定します。

.github/workflows/update_github.yaml
name: Update GitHub member/team
on:
  push:
    branches:
      - main
jobs:
  apply:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9
      - run: terraform init -input=false
      - name: Generate a GitHub token
        id: generate-github-token
        uses: actions/create-github-app-token@v1
        with:
          # GitHub Appsの情報を設定する
          app-id: ${{ vars.APP_ID }}
          private-key: ${{ secrets.APP_PRIVATE_KEY }}
      - run: terraform apply -input=false -auto-approve -lock=false -no-color
        env:
          TF_VAR_github_app_token: ${{ steps.generate-github-token.outputs.token }}

まとめ

これまでGitHubのチームやメンバーをWeb画面上から手動で設定していたのを、Terraform管理下に移行する手順を紹介しました。
Terraform化したことにより、次のようなメリットがありました。

  • 本名とGitHubアカウントとの突き合わせが容易になった
  • だれがどのチームに所属しているか一覧で確認しやすくなった
  • 退職時や異動時に本名でgrepできるようになったので、漏れが出にくくなった
  • プルリクベースで設定変更が行えるようになった

ここまで読んでいただきありがとうございました!参考になれば幸いです。

参考リンク

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?