概要 #
GitHub ActionsからGoogle Cloudへ認証する際、Service Account KeyをGitHub Secretsへ置く方法は漏洩の経路になります。長期間有効なJSON Keyは外部システムへ置きたくありません。
そこでWorkload Identity Federation(WIF)を使います。GitHub ActionsのOIDC TokenをGoogle Cloudが直接受け入れる仕組みです。Service AccountをImpersonateでき、鍵ファイル自体を作りません。
Terraformの基本操作とGitHub Actionsのworkflow構文は前提としています。
Service Account Keyの発行は扱いません。Branch/Environment単位の細かいCondition設計や、Private Repositoryでの追加設定も対象外です。
検証すること #
- GitHub Actions向けWorkload Identity PoolとProviderを作成できること
- OIDC ClaimとIAMの両方でRepositoryを限定できること
- Service Account KeyなしでWorkflowからGoogle Cloudへ認証できること
- Demo Bucketの読取で権限を確認できること
前提環境 #
- Google Cloud CLIとApplication Default Credentials(ADC)、Terraform
- GitHub Actionsを実行できるGitHub Repository
- IAM、Service Account、Cloud Storageを操作できるGoogle Cloud Project
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
今回の構成 #
Workload Identity Poolは、外部のIDをGoogle Cloudへ受け入れる入口です。Projectの直下に置かれ、Regionには属しません。
flowchart TB
subgraph GH["GitHub"]
Wf["Actions Workflow"]
OIDC["OIDC Token 発行"]
Wf --- OIDC
end
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
subgraph WIF["Workload Identity Federation"]
Pool["Pool"]
Prov["Provider
リポジトリで制限"]
Pool --- Prov
end
SA["Service Account
(鍵は発行しない)"]
Bucket["Demo Bucket"]
end
end
OIDC -->|"トークンを提示"| Prov
Prov -.->|"権限借用を許可"| SA
SA -->|"読み取り"| Bucket
Service Account Keyを作らないのが要点です。鍵ファイルをGitHubのSecretsへ置く必要がなく、漏洩の経路が減ります。
認証の流れは次のとおりです。
sequenceDiagram
participant Wf as Actions Workflow
participant Prov as WIF Provider
participant STS as Security Token Service
participant SA as Service Account
participant GCS as Cloud Storage
Wf->>Prov: OIDC Token を提示
Note over Prov: リポジトリ名などの条件を検証
Prov->>STS: 条件を満たせば交換
STS-->>Wf: 一時的なアクセストークン
Wf->>SA: 権限を借用
SA->>GCS: gcloud storage ls
GCS-->>Wf: 一覧を返す
受け取るのは一時的なトークンなので、有効期限が切れれば使えなくなります。
使用するTerraformコード #
GitHubのClaimをGoogle Cloudへ渡す #
resource "google_iam_workload_identity_pool_provider" "github" {
workload_identity_pool_id = google_iam_workload_identity_pool.github.workload_identity_pool_id
workload_identity_pool_provider_id = var.provider_id
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.repository" = "assertion.repository"
}
attribute_condition = "assertion.repository == '${var.github_repository}'"
oidc { issuer_uri = "https://token.actions.githubusercontent.com" }
}
ProviderのConditionとService Account IAMのprincipalSetの両方でOWNER/REPOSITORYを限定します。これにより同じGitHub OIDC Issuerを利用する無関係なRepositoryからの認証を拒否します。
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${var.github_repository}"
role = "roles/iam.workloadIdentityUser"
TerraformとWorkflow #
cd Advanced-Examples/05-wif-github-actions
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform fmt -check
terraform validate
terraform apply
Pool、Provider、Service Account、Demo Bucketが作成されます。合わせて12リソースです。
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
Outputs:
demo_bucket_name = "tf-adv-wif-demo-YOUR_PROJECT_ID"
github_repository = "tech-0222/terraform-gcp-examples"
service_account_email = "tf-adv-github-actions@YOUR_PROJECT_ID.iam.gserviceaccount.com"
workload_identity_provider_name = "projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/tf-adv-github-pool/providers/tf-adv-github-provider"
WorkflowにはOIDC Token発行権限を与えます。Terraform OutputのProvider名とService Accountを指定します。
permissions:
contents: read
id-token: write
steps:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL/providers/PROVIDER
service_account: github-actions@PROJECT_ID.iam.gserviceaccount.com
- run: gcloud storage ls gs://DEMO_BUCKET
GCP側で確認する #
Pool / Providerが有効になっているか確認します。
gcloud iam workload-identity-pools describe "$(terraform output -raw workload_identity_pool_id)"
gcloud iam workload-identity-pools providers describe \
"$(terraform output -raw workload_identity_provider_name)"
state: ACTIVE
両方ともACTIVEでした。Demo Bucketの内容も確認します。
gcloud storage cat "gs://$(terraform output -raw demo_bucket_name)/hello-wif.txt"
hello-from-wif-demo
ここまではローカルのgcloud(自分の認証)での確認です。実際にGitHub Actionsから鍵なしで認証できるかは別に確認します。Workflowを実行し、Service Account KeyなしでBucketを一覧できるかを見ます。確認する対象はGitHub Actionsのログに出るgcloud storage lsの結果です。
後片付けと注意点 #
terraform destroy
Destroy complete! Resources: 12 destroyed.
destroyしたPool / Providerは30日間ソフトデリート状態で残ります。 同じIDで再度applyすると409 Requested entity already existsで失敗します。再検証する場合はgcloud iam workload-identity-pools undeleteで復元し、terraform importでstateへ取り込んでから続けます。
Repositoryだけでなく、必要に応じてBranch、Environment、WorkflowなどのClaimもConditionへ加えます。GitHub Actions側のpermissionsはJobごとに最小化します。Google Cloud側の権限も、検証用BucketのViewerなど必要最小限に絞ります。
まとめ #
- GitHub SecretsへService Account Keyを保存せず認証できる
- Attribute ConditionとprincipalSetでRepositoryを限定できる
- 短時間Credentialを使い、Key Rotationの運用を減らせる
- Demo Bucketへのアクセスで権限をEnd-to-End確認できる
参考資料 #
次回 #
次回はCloud RunからCloud SQL for PostgreSQLへ接続する構成を作ります。