# Workload Identity Federation: GitHub Actions pushes images without long-lived keys. resource "google_iam_workload_identity_pool" "github" { workload_identity_pool_id = "github" } 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 = "github" attribute_mapping = { "google.subject" = "assertion.sub" "attribute.repository" = "assertion.repository" } attribute_condition = "assertion.repository == \"${var.github_repo}\"" oidc { issuer_uri = "https://token.actions.githubusercontent.com" } } resource "google_service_account" "ci" { account_id = "rarelens-ci" } resource "google_service_account_iam_member" "ci_wif" { service_account_id = google_service_account.ci.name role = "roles/iam.workloadIdentityUser" member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${var.github_repo}" } resource "google_artifact_registry_repository_iam_member" "ci_push" { repository = google_artifact_registry_repository.images.name location = var.region role = "roles/artifactregistry.writer" member = "serviceAccount:${google_service_account.ci.email}" } # Runtime identities (bound to k8s ServiceAccounts via GKE Workload Identity) resource "google_service_account" "api" { account_id = "rarelens-api" } resource "google_service_account" "pipeline" { account_id = "rarelens-pipeline" } resource "google_project_iam_member" "api_sql" { project = var.project role = "roles/cloudsql.client" member = "serviceAccount:${google_service_account.api.email}" } resource "google_project_iam_member" "api_pubsub" { project = var.project role = "roles/pubsub.publisher" member = "serviceAccount:${google_service_account.api.email}" } resource "google_storage_bucket_iam_member" "pipeline_data" { bucket = google_storage_bucket.data.name role = "roles/storage.objectAdmin" member = "serviceAccount:${google_service_account.pipeline.email}" }