Terraform による GitHub の構成変数・シークレットの管理
クラウドエースの北野です。
要約
Terraform を使って GitHub の構成変数、シークレットを管理して、ワークフローファイルから環境固有の情報を削除する方法を紹介します。
本記事では Google Cloud のプロジェクト ID、Workload Identity プールのプロバイダー、サービスアカウントをリポジトリの構成変数で管理して、以下の様に Google Cloud の情報を直接代入しないワークフローで GitHub Actions を実行させます。
- name: Authenticate to Google Cloud
id: authorizaation-googlecloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: ${{ vars.GOOGLE_CLOUD_WORKLOADIDENTITYPROVIDER_ID }}
service_account: ${{ vars.GOOGLE_CLOUD_SERVICEACCOUNT_EMAIL }}
はじめに
GitHub Actions を使うと、ワークフローファイルを GitHub リポジトリにプッシュするとワークフローを実行できるため、簡単に CI/CD のパイプラインの構築ができます。そのため、GitHub Actions で CI/CD を実行されている方も多いと思います。
例えば、Terraform を Google Cloud に対して実行する場合、認証を行い terraform apply
を実行されていると思います。
name: Terraform Apply
on:
workflow_dispatch:
jobs:
terraform_apply:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
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
uses: hashicorp/setup-terraform@v2
- name: terraform apply
run: |
terraform init
terraform apply --auto-approve
このとき、ワークフローファイルは上記の様に Workload Identity プールのプロバイダーとサービスアカウントの情報を記載しなければなりません。これらの情報は、Google Cloud のプロジェクト番号、プロジェクト ID などの情報が含まれ、書き間違いなどによるオペレーションミスが起こりやすいです。
そこで、本記事では、Terraform がクラウドなどの実行環境に依存する情報を参照して、GitHub の構成変数を作成する方法を紹介します。本記事の内容を採用すると、環境に依存する情報を直接代入しないワークフローファイルの作成ができるようになります。
実現方法
環境に依存する情報を以下の様に管理して、ワークフローファイルから環境に依存する情報を削除します。
- 環境に依存する情報の GitHub の構成変数・シークレットで管理
- GitHub の構成変数・シークレットの Terraform で作成
- ワークフローファイルで構成変数・シークレットの参照
GitHub Actions の構成変数およびシークレット
GitHub には構成変数とシークレットが存在し、組織、リポジトリや環境でこれらを定義すると、ワークフローのジョブからこれらの情報を参照できます。
構成変数とシークレットの主な違いは、ログに値が出力されるか否かになります。そのため、パスワードなどのセキュアな情報を扱う場合、シークレットを活用してください。
また、構成変数とシークレットの重要なポイントは、以下があげられます。
- 同一変数名は、環境 > リポジトリ > 組織 の順で値が優先される
-
GITHUB_
で始まる変数名は定義できない
構成変数とシークレットへのアクセスはそれぞれ以下の通りです。
- 構成変数:
${{ vars.<VARIABLE_NAME> }}
- シークレット:
${{ secrets.<SECRET_NAME> }}
構成変数、シークレットの作成は、CLI およびブラウザの両方から作成が可能です。それぞれの作成方法は以下の公式ページをご確認ください。
- 構成変数の作成方法
- シークレットの作成方法
Terraform による GitHub の構成変数の管理
ここから、Terraform を使いリポジトリの構成変数を作成する方法を紹介します。
ここで紹介する構成変数は、Google Cloud のプロジェクト ID、Workload Identity のプロバイダープールとサービスアカウントを管理します。そして、作成した構成変数を使って terraform apply
を実行する GitHub Actions のワークフローファイルを作成します。最後に構成変数を管理する Terraform コードの運用・管理方法について考えてみたいと思います。
以下の Terraform コードを試す場合、紹介するコードの <>
の部分は、実環境に沿うように書き替えてください。
Workload Identity プールプロバイダーおよびサービスアカウントの作成
GitHub Actions が Google Cloud の認証に使う Workload Identity プロバイダープールとサービスアカウントを作成します。ここで作成する Workload Identity プロバイダーの属性条件は GitHub リポジトリとします。Workload Identity の使い方などについては、こちらの記事をご確認ください。
- Workload Identity の作成
resource "google_iam_workload_identity_pool" "main" {
workload_identity_pool_id = <WORKLOADIDENTITY_POOL>
project = var.project
}
resource "google_iam_workload_identity_pool_provider" "main" {
workload_identity_pool_provider_id = <WORKLOADIDENTITY_POOL_PROVIDER>
workload_identity_pool_id = google_iam_workload_identity_pool.main.workload_identity_pool_id
project = var.project
attribute_condition = format("assertion.repository == \"<REPOSITORY_OWNER>/<REPOSITORY_NAME>\"", )
attribute_mapping = {
"google.subject" = "assertion.repository"
}
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
}
}
サービスアカウントへの権限の設定と、サービスアカウントが有する権限を設定します。Terraform で Google Cloud の変更をするため、サービスアカウントはプロジェクトに編集者権限を有するように設定します。
- サービスアカウントの作成
resource "google_service_account" "main" {
account_id = <SERVICEACCOUNT_ID>
project = var.project
}
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/<REPOSITORY_OWNER>/<REPOSITORY_NAME>", google_iam_workload_identity_pool.main.name)
}
resource "google_project_iam_member" "main" {
project = var.project
role = "roles/editor"
member = google_service_account.main.member
}
GitHub Actions の変数およびシークレットの作成
Google Cloud プロジェクトの ID、Workload Identity プライベートプールのプロバイダー、サービスアカウントの情報を管理する構成変数を作成します。GitHub のリソースを Terraform で管理する方法は、こちらの記事をご確認ください。
locals {
envs = [
{
name = "GOOGLE_CLOUD_PROJECT_ID"
value = var.project
},
{
name = "GOOGLE_CLOUD_WORKLOADIDENTITYPROVIDER_ID"
value = google_iam_workload_identity_pool_provider.main.name
},
{
name = "GOOGLE_CLOUD_SERVICEACCOUNT_EMAIL"
value = google_service_account.main.email
}
]
}
resource "github_actions_variable" "main" {
for_each = { for v in local.envs : v.name => v }
variable_name = each.value.name
value = each.value.value
repository = data.github_repository.main.name
}
data "github_repository" "main" {
full_name = "<REPOSITORY_OWNER>/<REPOSITORY_NAME>"
}
作成に成功すると、リポジトリの Settings
の Secrets and variables
から作成した構成変数の内容を確認できます。
作成した構成変数を参照するワークフローファイルを作成して、terraform apply
を実行できるか確認します。
name: Terraform Apply
on:
workflow_dispatch:
defaults:
run:
working-directory: src
jobs:
terraform_apply:
runs-on: ubuntu-latest
timeout-minutes: 3000
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v3
- name: Authenticate to google cloud
id: authorization-googlecloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.GOOGLE_CLOUD_WORKLOADIDENTITYPROVIDER_ID }}
service_account: ${{ vars.GOOGLE_CLOUD_SERVICEACCOUNT_EMAIL }}
- name: setup terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: "1.10.3"
- name: terraform apply
run: |
terraform init
terraform apply --auto-approve
env:
TF_VAR_project: ${{ vars.GOOGLE_CLOUD_PROJECT_ID }}
上記の内容を実行すると、terraform apply
が実行されます。
コードの管理・運用方法
Google Cloud の Workload Identity と サービスアカウント、GitHub リポジトリの構成変数の作成を一括で実施する方法を紹介しました。
しかし、各部署の権限管理のため、Google Cloud のリソースを管理する Terraform コードのリポジトリとアプリケーションのコードのリポジトリが異なるなることがあると思います。そのため、アプリケーション開発の部署のリポジトリに紹介した Terraform コードを作成しても、アプリケーションの開発部署のメンバーでは作成できないことがあるかと思います。
そこで、この問題を解消するコードの管理・運用方法を最後に提案したいと思います。提案の内容としては以下の通りです。(前提条件として、クラウド管理部署は Google Cloud のリソースを作成する権限を持っており、アプリケーション開発部門は作成されたリソース情報を閲覧する権限を持っているものとします。)
- Workload Identity とサービスアカウントの作成を Google Cloud のリソースを管理する Terraform リポジトリで作成しクラウド管理部署が実行
- 構成変数の作成をアプリケーションのリポジトリで管理し、Workload Identity とサービスアカウントは data ブロックで閲覧する様にコードを書き、アプリケーション部署が実行
アプリケーション部署が管理するリポジトリの構造を以下の様な GitHub リポジトリの設定を行なうディレクトリ(以下では repository_config としています)を作成し、そこに構成変数を作成する Terraform コードを作成します。
.
├── .github
│ └── workflows
├── repository_config
│ ├── data.tf
│ ├── github_actions_variables.tf
│ └── versions.tf
└── src
Workload Identity や サービスアカウントの data ブロックによるリソースの閲覧は以下の様にします。
data "google_iam_workload_identity_pool_provider" "main" {
provider = google-beta
workload_identity_pool_provider_id = "<WORKLOADIDENTITY_POOL_PROVIDER_ID>"
workload_identity_pool_id = "<WORKLOADIDENTITY_POOL_ID>"
project = var.project
}
data "google_service_account" "main" {
account_id = "<SERVICEACCOUNT_ID>"
project = var.project
}
そして、構成変数の作成では以下の様に data ブロックの返り値を代入させます。
locals {
envs = [
{
name = "GOOGLE_CLOUD_PROJECT_ID"
value = var.project
},
{
name = "GOOGLE_CLOUD_WORKLOADIDENTITYPROVIDER_ID"
value = data.google_iam_workload_identity_pool_provider.main.name
},
{
name = "GOOGLE_CLOUD_SERVICEACCOUNT_EMAIL"
value = data.google_service_account.main.email
}
]
}
resource "github_actions_variable" "main" {
provider = github.aquamarinearia
for_each = { for v in local.envs : v.name => v }
variable_name = each.value.name
value = each.value.value
repository = github_repository.main.name
}
この様にコードを作成すると、クラウドに作成の権限を持たない部署のメンバーでも Terraform を使って GitHub の構成変数を作成できます。
さいごに
Terraform を使って、GitHub の構成変数を作成する方法を紹介しました。
最後に紹介した様にリポジトリごとの設定を Terraform で管理するような構成にすれば、権限分離が可能になりセキュアにリソース管理が可能になります。また、リポジトリごとにリポジトリの設定を管理する Terraform コードを作成するとアクセス権限、リポジトリのルールも定義できるようになり運用ミスが減るかと思います。
Discussion