GCP Terraform Seed
Overview
This Terraform code is designed to provision the foundational setup for Google Cloud Platform (GCP) project, services, and service accounts required for Terraform. It also handles the roles and permissions for the Terraform service account.
Seed Project Concept
What is a Seed Project?
A seed project is essentially a starting point for your infrastructure. It sets up the basic resources and permissions you need to build out your environments. This includes setting up IAM roles and Federation to run code.
The service account created here is used by the CICD pipeline agents through impersonation to create and manage GCP resources.
Why is it Important?
The seed project is crucial because it lays the foundation for all your future projects and configurations. It ensures that you have a secure, scalable, and maintainable infrastructure by delegating this roles to an impersonatable agent.
Key Components
- GCP Seed project
- Terraform service Account
- IAM Roles at Organization level
- IAM Roles at Seed Project level
- Workload Identity federation
Usage
- Initialization: An admin user needs to login using the CLI or manually apply the code in this file.
- State Migration: After the initial implementation, the state for the code is stored in a cloud storage bucket.
Requisites
- A Google Cloud Platform account with sufficient permissions.
- Terraform installed in the local machine.
Order of Execution
- Activation of APIs: Flatten and set the required APIs.
- Project Creation: Setup a GCP project using the "terraform-google-modules/project-factory/google" module.
- Service Account Creation: Define a service account used by Terraform.
- Roles Assignment: Set up the roles for the Terraform service account on the organization and project levels.
- Workload Identity Federation: Setup Workload Identity Federation for GitHub actions.
- Workload Identity Binding: Apply the identity binding.
Logic
- The
locals
block defines the APIs to be activated. - The
module "org_seed_project"
sets up the project. - The
resource "google_service_account"
creates the service account. - IAM roles are managed through modules
"terraform_sa_organization_iam_bindings"
and"terraform_sa_project_iam_bindings"
. - Workload Identity Federation and binding are handled with specific resources.
Notes
- Make sure to uncomment the key block if needed for initial manual bootstrapping.
- The repository paths and roles can be adjusted as needed.
Info
From this point on the document is autogenerated, don't modify it directly
Code
Local Variables
The Seed project needs to have all the APIs defined in var.activate_apis enabled not only for the project itself but for every child project
- add all APIs
- remove duplicates
Module: Org Seed Project
This Terraform module, org_seed_project
, is used to create a Google Cloud Project with specific configurations using the Project Factory module, without creating a random project ID, a default service account, or a network, but activating certain APIs.
module "org_seed_project" {
source = "terraform-google-modules/project-factory/google"
version = "14.2.0"
random_project_id = "false"
default_service_account = "delete"
create_project_sa = false
name = "${var.owner}-seed-prj"
org_id = var.org_id
billing_account = var.billing_account
auto_create_network = false
activate_apis = local.activate_apis_all
labels = {
terraform_managed = true
}
}
Resource: Google Service Account
This Terraform code creates a Google Cloud Service Account named Terraform Service Account
with the account ID tf_seed_sa
in the project created by the org_seed_project
module.
resource "google_service_account" "tf_seed_sa" {
account_id = "tf_seed_sa"
display_name = "Terraform Service Account"
project = module.org_seed_project.project_id
}
Resource: Google Service Account Key
This Terraform code generates a new private key for the tf_seed_sa
Google Cloud Service Account and stores it in google_service_account_key
named account_key
.
resource "google_service_account_key" "account_key" {
service_account_id = google_service_account.service_account.name
}
Module: Terraform Service Account Org IAM Bindings
-
"roles/resourcemanager.organizationAdmin"
: necessary for the service account to manage organization-wide resources effectively. -
"roles/resourcemanager.projectCreator"
: allows the service account to create new projects within the organization. -
"roles/resourcemanager.folderAdmin"
: grants administrative access to manage folders within the organization. -
"roles/compute.xpnAdmin"
: allows the service account to manage network resources across projects. -
"roles/serviceusage.serviceUsageAdmin"
: allows enabling or disabling various Google Cloud services across projects. -
"roles/billing.user"
: allows the service account to view and manage billing information. -
"roles/iam.serviceAccountAdmin"
: grants administrative access to manage service accounts.
module "tf_seed_sa_organization_iam_bindings" {
source = "terraform-google-modules/iam/google//modules/organizations_iam"
version = "7.6.0"
organizations = [var.org_id]
mode = "additive"
bindings = {
"roles/resourcemanager.organizationAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/resourcemanager.projectCreator" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/resourcemanager.folderAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/compute.xpnAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/serviceusage.serviceUsageAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/billing.user" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.serviceAccountAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
}
}
Module: Terraform Service Account Project IAM Bindings
-
"roles/serviceusage.serviceUsageAdmin"
: relevant for enabling or disabling specific Google Cloud services within the project. -
"roles/iam.serviceAccountKeyAdmin"
: The service account might need to manage its own keys. -
"roles/iam.serviceAccountAdmin"
: If the service account needs to manage other service accounts at the project level, is necessary. -
"roles/iam.serviceAccountTokenCreator"
: service account needs to create tokens for other service accounts. -
"roles/iam.workloadIdentityUser"
: allows the service account to act as a workload identity user. -
"roles/iam.workloadIdentityPoolAdmin"
: allows the service account to manage id pools. -
"roles/storage.objectCreator"
: Permission to create objects in Cloud Storage. -
"roles/storage.objectViewer"
: provides read access to objects in Cloud Storage. -
"roles/storage.admin"
: It includes permissions to create, delete, and modify storage buckets and objects.
module "tf_seed_sa_project_iam_bindings" {
source = "terraform-google-modules/iam/google//modules/projects_iam"
version = "7.6.0"
projects = [module.org_seed_project.project_id]
mode = "additive"
bindings = {
"roles/serviceusage.serviceUsageAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.serviceAccountKeyAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.serviceAccountAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.serviceAccountTokenCreator" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.workloadIdentityUser" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/iam.workloadIdentityPoolAdmin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/storage.objectCreator" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/storage.objectViewer" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
"roles/storage.admin" = ["serviceAccount:${google_service_account.tf_seed_sa.email}"],
}
}
Identity Pool
This Terraform code creates a new Google Cloud IAM Workload Identity Pool with the ID github-terraformer
in the specified project, and stores it in google_iam_workload_identity_pool
named idp_pool
.
resource "google_iam_workload_identity_pool" "idp_pool" {
workload_identity_pool_id = "github-terraformer"
project = module.org_seed_project.project_id
}
Resource: Google IAM Workload Identity Pool Provider
This Terraform code creates a new Google Cloud IAM Workload Identity Pool Provider for the identity pool github-terraformer
, and configures it with an empty list of allowed audiences, an Github issuer URI, and attribute mappings for OIDC (OpenID Connect).
resource "google_iam_workload_identity_pool_provider" "gh_provider" {
workload_identity_pool_id = "github-terraformer"
workload_identity_pool_provider_id = "gh-actions"
display_name = "gh-actions"
oidc {
allowed_audiences = []
issuer_uri = "https://token.actions.githubusercontent.com"
}
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.actor" = "assertion.actor"
"attribute.repository" = "assertion.repository"
}
}
Google Service Account IAM Binding
Member repos can impersonate the terraform SA via github actions. When possible add one repo at a time, or:
- Uncomment A to allow all client repos to impersonate the terraform SA
- Uncomment B to use Use Workload Identity with Google Kubernetes Engine, once for each namespace
resource "google_service_account_iam_binding" "workload_identity_binding" {
service_account_id = google_service_account.service_account.id
role = "roles/iam.workloadIdentityUser"
members = [
"principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository/${var.owner}/${var.owner}-slz",
"principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository/${var.owner}/${var.owner}-shared-infra",
"principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository/${var.owner}/${var.owner}-projecta-infra",
"principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository/${var.owner}/${var.owner}-projectc-infra",
"principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository/${var.owner}/${var.owner}-projectb-infra",
# A: "principalSet://iam.googleapis.com/projects/${module.org_seed_project.project_number}/locations/global/workloadIdentityPools/github-terraformer/attribute.repository_${var.owner}/${var.owner}-Power",
# B: "serviceAccount:${module.org_seed_project.project_id}.svc.id.goog[${NAMESPACE}/${var.service_account}]",
]
}