GitHub の管理を GitHub Actions から Terraform でやってみた
クラウドエースの北野です。
GitHub リポジトリ, Team などのリソースを GitHub Actions から Terraform を使って管理する方法を紹介します。
概要
本記事では、以下の GitHub リポジトリ、Team と Team のアクセス権限を設定する Terraform コードを GitHub Actions から実行する方法を紹介します。
resource "github_repository" "main" {
name = <Repository Name>
visibility = "private"
}
resource "github_team" "main" {
name = <Team Name>
create_default_maintainer = true
privacy = "closed"
}
resource "github_team_repository" "main" {
team_id = github_team.main.id
repository = github_repository.main.name
permission = <Permission>
}
この記事では、以下の環境から Terraform を実行して GitHub のリソースを管理する方法紹介します。
- ローカル環境から Terraform の実行
- GitHub Actions から Terraform の実行
また、GitHub Actions での認証に個人用アクセストークンを使います。
はじめに
サービスの新しい機能拡張による GitHub リポジトリの作成、新しい開発メンバーの参画による組織への追加や、リポジトリへの権限追加など GitHub の運用作業は非常に多いです。しかし、作業の特性上、その頻度は非常に少なく、手動で運用していると作業ミスが起こりやすいです。この作業ミスには、人への権限の付け間違いやリポジトリの公開設定のミスなどがあり、設定ミスをすると情報漏洩の可能性が高いです。
そのため、GitHub の管理をコード化して作業を自動化するメリットは非常に高いです。また、CD ツールを使ってコードの実行を自動化すると、運用が作業者に依存しなくなるため運用作業のリードタイムを減らせます。
この記事では、Terraform で GitHub の管理をコード化して、その実行を GitHub Actions で実施する方法を紹介します。
まず、Terraform による GitHub リソースのコード化をおこない、そのコードをローカル環境から実行する方法を紹介します。続いて、コード化した内容を GitHub Actions から実行する方法を紹介します。
記事の内容を試す場合、紹介する Terraform コードの <>
の部分は、実環境に沿う様に書き替えてください。
GitHub リソースの Terraform によるコード化
Terraform による GitHub のリソースのコード化に、integrations/github のプロバイダーを使います。プロバイダーは以下の様に定義します。
このとき管理する GitHub の組織は provider の owner
変数に定義します。
terraform {
required_providers {
github = {
source = "integrations/github"
}
}
}
provider "github" {
owner = <GitHub Organization>
}
本記事で Terraform で作成する GitHub リソースとそのコード
Terraform で以下のリソースを作成します。
- GitHub リポジトリ
- Team
- Team のリポジトリへのアクセス権限
上記の内容の Terraform コードは以下の通りです。
resource "github_repository" "main" {
name = <Repository Name>
visibility = "private"
}
resource "github_team" "main" {
name = <Team Name>
create_default_maintainer = true
privacy = "closed"
}
resource "github_team_repository" "main" {
team_id = github_team.main.id
repository = github_repository.main.name
permission = <Permission>
}
GitHub の認証方法
上記のコードを実行させるためには、実行環境を GitHub に認証させる必要があります。
GitHub の認証には、以下の 3つの方法があります。
- GitHub CLI
- OAuth/Personal Access Token (以降 PAT)
- GitHub App Installation
本記事では、ローカル環境での認証に GitHub CLI を使い、GitHub Actions の認証に OAuth/Personal Access Token を使います。
ローカル環境からの実行
GitHub CLI でローカル環境を認証させて、Terraform コードを実行させてみます。
GitHub CLI での認証
GitHub CLI はリポジトリの作成・削除や Pull Request の作成・クローズなどの GitHub 上の操作をターミナルから行う gh
コマンドです。GitHub CLI のインストールは公式ページを参考にしてください。
GitHub CLI の認証は gh auth login
コマンドでおこないます。
gh auth login
を実行すると、認証方法などを対話的に入力して認証に進みます。以下の条件を対話的に入力すると、ワンタイムコードが出力され Web ブラウザが起動します。
- GitHubの起動先: GitHub.com
- git 操作をおこなうプロトコル: HTTPS
- GitHub クレデンシャルで Git 認証許可する: Yes
- GitHub CLI の認証方法: Web ブラウザでのログイン
Web ブラウザ上で認証させるアカウントを選択すると、ワンタイムコードを入力する画面に遷移します。
コンソールの ! First copy your one-time code:
の行に表示されているコードを入力します。
認証を許可すると、認証が完了します。
認証に成功すると、Congratulations, you're all set
と表示され、カーソルがコンソールに戻り標準出力に Logged in as <GitHub Account ID>
が表示されます。
最後に gh repo list
コマンドを実行して、ユーザーのリポジトリの一覧を表示させてみます。
❯ gh repo list
Showing of repositories in @<GitHub Account ID>
NAME DESCRIPTION INFO UPDATED
Repository Infomation
実行結果
ローカル環境から Terraform を実行すると、以下のようになります。
❯ terraform apply
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:
# github_repository.main will be created
+ resource "github_repository" "main" {
+ allow_auto_merge = false
+ allow_merge_commit = true
+ allow_rebase_merge = true
+ allow_squash_merge = true
+ archived = false
+ default_branch = (known after apply)
+ delete_branch_on_merge = false
+ etag = (known after apply)
+ full_name = (known after apply)
+ git_clone_url = (known after apply)
+ html_url = (known after apply)
+ http_clone_url = (known after apply)
+ id = (known after apply)
+ merge_commit_message = "PR_TITLE"
+ merge_commit_title = "MERGE_MESSAGE"
+ name = <Repository Name>
+ node_id = (known after apply)
+ primary_language = (known after apply)
+ private = (known after apply)
+ repo_id = (known after apply)
+ squash_merge_commit_message = "COMMIT_MESSAGES"
+ squash_merge_commit_title = "COMMIT_OR_PR_TITLE"
+ ssh_clone_url = (known after apply)
+ svn_url = (known after apply)
+ topics = (known after apply)
+ visibility = "private"
+ web_commit_signoff_required = false
+ security_and_analysis (known after apply)
}
# github_team.main will be created
+ resource "github_team" "main" {
+ create_default_maintainer = true
+ etag = (known after apply)
+ id = (known after apply)
+ members_count = (known after apply)
+ name = <Team Name>
+ node_id = (known after apply)
+ parent_team_read_id = (known after apply)
+ parent_team_read_slug = (known after apply)
+ privacy = "closed"
+ slug = (known after apply)
}
# github_team_repository.main will be created
+ resource "github_team_repository" "main" {
+ etag = (known after apply)
+ id = (known after apply)
+ permission = <Permission>
+ repository = <Repository Name>
+ team_id = (known after apply)
}
Plan: 3 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
github_team.main: Creating...
github_repository.main: Creating...
github_team.main: Creation complete after 4s [id=<Team ID>]
github_repository.main: Creation complete after 8s [id=<Repository Name>]
github_team_repository.main: Creating...
github_team_repository.main: Creation complete after 2s [id=<Team ID>:<Repository Name>]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
GitHub Actions からの実行
PAT を GitHub Actions の環境を認証させ、そこから Terraform を実行する方法を紹介します。
PAT の管理に Google Cloud の Secret Manager を使い、Terraform のステートファイルの管理に Google Cloud の Cloud Storage を使います。また、GitHub Actions から、Google Cloud への認証に Google Cloud の Workload Identity を使います。
Workload Identity を使って GitHub Actions の環境を Google Cloud に認証させる方法の詳細は、この記事を参考にしてください。
Google Cloud 側の設定
Google Cloud に以下のリソースを作成します。
Google Cloud リソースの種類 | 目的 |
---|---|
Workload Identity | GitHub Actions の認証 |
Service Account | Workload Identity により GitHub Actions の環境に利用させるサービスアカウント |
Secret Manager | PAT の管理 |
Cloud Storage | Terraform のステートファイルの管理 |
サービスアカウントに付与する権限は、以下の通りです。
付与する権限 | アクセス制御するリソース |
---|---|
roles/storage.objectAdmin | Terraform のステートファイルを管理する Cloud Storage バケット |
roles/secretmanager.secretAccessor | PAT を管理する Secret Manager |
roles/secretmanager.viewer | PAT を管理する Secret Manager |
上記の作成は以下の Terraform コードで作成します。
variable "project" {}
resource "google_iam_workload_identity_pool" "main" {
workload_identity_pool_id = <Workload Identity Pool Name>
project = var.project
}
resource "google_iam_workload_identity_pool_provider" "main" {
workload_identity_pool_provider_id = <Workload Identity Pool Provider ID>
workload_identity_pool_id = google_iam_workload_identity_pool.main.workload_identity_pool_id
project = var.project
attribute_condition = <CONDITION>
attribute_mapping = {
"google.subject" = "assertion.repository"
}
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
}
}
resource "google_service_account" "main" {
account_id = <Service Account ID>
project = var.project
}
resource "google_secret_manager_secret" "main" {
secret_id = <Secret Manager ID>
project = var.project
replication {
user_managed {
replicas {
location = "asia-northeast1"
}
}
}
}
resource "google_storage_bucket" "main" {
name = <Bucket Name>
project = var.project
location = "asia-northeast1"
storage_class = "STANDARD"
}
resource "google_service_account_iam_member" "main" {
service_account_id = google_service_account.main.name
role = "roles/iam.workloadIdentityUser"
member = format("principal://iam.googleapis.com/%s/subject/%s", data.google_iam_workload_identity_pool.main.name, "<GitHub Organization>/<GitHub Repository Name>")
}
resource "google_storage_bucket_iam_member" "main" {
bucket = google_storage_bucket.main.name
role = "roles/storage.objectAdmin"
member = google_service_account.main.member
}
resource "google_secret_manager_secret_iam_member" "accessor" {
secret_id = google_secret_manager_secret.main.secret_id
project = var.project
role = "roles/secretmanager.secretAccessor"
member = google_service_account.main.member
}
resource "google_secret_manager_secret_iam_member" "viewer" {
secret_id = google_secret_manager_secret.main.secret_id
project = var.project
role = "roles/secretmanager.viewer"
member = google_service_account.main.member
}
PAT による認証
github
プロバイダーに token
変数を設定すると、Terraform 実行時にトークンで GitHub に認証されされます。このトークンには、PAT を指定します。PAT はパスワードの代わりに使われる認証情報で、GitHub リソースへのアクセスを自動化する目的で利用されます。
PAT には personal access token (fine-grained personal access token)
と personal access token (personal access token (classic))
の2種類があります。各トークンの違いなどは、公式ドキュメントを参考にしてください。
まだ、personal access token (fine-grained personal access token)
はベータ版のため、この記事では personal access token (personal access token (classic))
を使います。
続いて personal access token (personal access token (classic))
の作成方法を説明します。
GitHub アカウントの Settings ページにアクセスし、Developer settings
を選択し Personal access tokens の Tokens(classic) クリックして PAT (classic) の一覧ページにアクセスします。
画面上の Generate new token
の Generate new token (classic)
をクリックします。
Note、Expiration、Select scopes に必要な情報を入力し、ページ下の Create token
のボタンをクリックすると、PAT が作成されます。作成されると以下の PAT 部分に PAT 情報が表示されます。この情報を github provider の token に入力すると、PAT の内容で認証・認可され Terraform が実行されます。
本記事では、PAT を先に作った Secret Manager で管理します。Cloud Console から Secret Manager にアクセスし、作成した Secret Manager を選択して、新しいバージョン
をクリックして PAT をシークレットの値に入力して追加します。
実行結果
Secret Manager に保存された PAT から provider の token への代入は以下の様にします。
terraform {
backend "gcs" {
bucket = "<Bucket Name>"
}
required_providers {
github = {
source = "integrations/github"
}
google = {
source = "hashicorp/google"
}
}
}
provider "github" {
token = data.google_secret_manager_secret_version.main.secret_data
owner = "<GitHub Organization>"
}
data "google_secret_manager_secret_version" "main" {
secret = <Secret Manager ID>
project = var.project
}
variable "project" {}
Terraform を実行する GitHub Actions の Workflow は以下の様に定義します。
name: Manage GitHub Resources
on:
workflow_dispatch:
jobs:
manage_gethub_group:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: <Working Directory>
steps:
- uses: actions/checkout@v2
- name: Authenticate to Google Cloud
id: authorizaation-googlecloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: projects/<Project Number>/locations/global/workloadIdentityPools/<Workload Identity Pool Name>/providers/<Workload Identity Pool Provider ID>
service_account: <Service Account ID>@<Project ID>.iam.gserviceaccount.com
- name: setup terraform
id: terraform-setup
uses: hashicorp/setup-terraform@v3.1.2
- name: terraform apply
id: terraform-apply
run: |
terraform init
terraform apply --auto-approve
env:
TF_VAR_project: <Project ID>
上記の内容を実行すると、以下の様になります。
まとめ
GitHub リソースを Terraform で管理する方法を紹介しました。リポジトリのルールや Team の管理などをコード化でき、運用ミスを減らすことができます。
また、GitHub Actions の Variables や Secrets も Terraform で設定できます。そのため、本記事の Workflow に定義している workflow_identity_provider や service_account の値も、 Terraform で Variables に設定し、 Variables を参照するように Workflow を定義すると再利用可能になり運用ミスを減らすことができます。
みなさまも GitHub のリソースを Terraform で管理して、素早くかつミスなく GitHub を運用してみてください。
Discussion