Business Unit Module (terraform-platform-create-business-unit)
The business unit module orchestrates the creation of all infrastructure needed for a new business unit within the Badal Foundations platform. It provisions GCP folders across environments, a shared WIF host project, a GitHub repository pre-populated with scaffold code, and a Terraform Cloud workspace.
- Source Repository: badal-io/terraform-platform-create-business-unit
- TFC Registry:
app.terraform.io/Badal_devex/create-business-unit/platform
What It Creates
When you invoke this module, it provisions the following resources:
- GCP folders for each configured environment (e.g.,
fldr-development,fldr-non-production,fldr-production) placed under the corresponding foundation environment folders - A common folder (
{business_unit}-{suffix}) underfldr-commoncontaining a WIF host project (wif-host-{suffix}) - A GitHub repository (
bu-{name}-{suffix}) pre-populated with scaffold Terraform files - A TFC project and workspace configured with VCS integration to the new repo
Resource Relationship Diagram
create-business-unit module
├── google_folder.environment_folders (per env)
│ └── e.g., data-80r13 under fldr-development
├── google_folder.common_folder
│ └── wif-host-{suffix} (GCP project via project-factory)
├── module.repository (integrated_repository/github)
│ ├── GitHub repo: bu-{name}-{suffix}
│ ├── TFC project + workspace
│ └── WIF + cross-env service account
└── github_repository_file (scaffold files)
├── backstage-manifest.json
├── terraform/main.tf
├── terraform/variables.tf
├── terraform/outputs.tf
├── terraform/shared.tf
├── terraform/gar.tf (conditional)
└── terraform/tenants/main.tf
Naming Convention
All resources use a randomly generated 5-character alphanumeric suffix to ensure uniqueness:
| Resource | Naming Pattern | Example |
|---|---|---|
| GitHub repository | bu-{business_unit}-{suffix} | bu-data-80r13 |
| Environment folders | {business_unit}-{suffix} | data-80r13 |
| Common folder | {business_unit}-{suffix} | data-80r13 |
| WIF host project | wif-host-{suffix} | wif-host-80r13 |
| TFC workspace | bu-{business_unit}-c-{suffix} | bu-data-c-80r13 |
The suffix is generated via random_string (lowercase letters + digits, 5 characters).
Key Variables
| Variable | Type | Required | Default | Description |
|---|---|---|---|---|
business_unit | string | Yes | - | Business unit name (1-20 chars, lowercase, starts with letter) |
environments | map(object) | Yes | - | Map of environments to GCP folder configuration. Each entry requires org_id, billing_account_id, parent_folder_id, and optional vpc_subnet_project_id |
single_workspace | object | Yes | - | Configuration for the shared WIF host project: org_id, billing_account_id, parent_folder_id, service_account_roles |
gh_org | string | Yes | - | GitHub organization name |
gh_app | object | Yes | - | GitHub App credentials: id, installation_id, private_key |
tfc | object | Yes | - | Terraform Cloud config: org_id, gh_app_oauth_id, token, enable (optional, default true) |
gar | object | No | { enable = false } | Google Artifact Registry config: enable, location (default us-central1), artifact_types (DOCKER, MAVEN, NPM, PYTHON, APT, YUM, GO) |
template | object | No | { owner = "badal-io", repository = "Business-Unit-Template" } | Template repository for scaffold code |
shared_tenant_template | object | No | null | Template repository for the shared tenant created by the BU |
teams | map(object) | No | {} | GitHub teams to grant permissions (admin, write, triage, maintain, read) |
topics | list(string) | No | [] | Additional GitHub topics (merged with business-unit, backstage-catalog) |
foundations_access | object | No | { enable = false } | Access to foundation remote state: enable, bucket_name, enable_shared_vpc_subnets |
Key Outputs
| Output | Description |
|---|---|
environment_folders | GCP folders created for each environment (folder ID, display name) |
common_folder | The shared GCP folder containing the WIF host project |
repository | GitHub repository details (name, URL, default branch) |
terraform_project | TFC project details (sensitive) |
terraform_workspaces | TFC workspace details (single workspace mode) |
environments | Environment configuration including WIF provider and service account |
wif_host_project | WIF host project details (project_id, project_number, project_name) |
WIF Architecture (Cross-Environment)
Business units use a single workspace / cross-environment WIF pattern. This means:
- One WIF host project is created in the common folder
- One service account has access to all environment folders plus the common folder
- The single TFC workspace uses this SA to manage resources across all environments
- Roles specified in
single_workspace.service_account_rolesare granted on each environment folder and the common folder
This differs from tenants, which use per-environment WIF with separate service accounts.
Scaffold Files
The module pushes the following files into the newly created GitHub repository:
backstage-manifest.json
Machine-readable metadata used by Backstage to discover and catalog the business unit. Contains repository info, WIF configuration, folder IDs, environment mappings, and GAR settings.
terraform/main.tf
Pre-configured Terraform root module with the suffix, environment folder IDs, and GAR settings baked in. Used as the entry point for managing tenants.
terraform/variables.tf
Variable declarations matching the scaffolded main.tf, including environment-specific folder and org configurations.
terraform/outputs.tf
Output declarations for tenant information and optional GAR repository details.
terraform/shared.tf
Shared tenant configuration including the shared tenant template and team permissions.
terraform/gar.tf (conditional)
Only created when gar.enable = true and artifact_types is non-empty. Configures BU-level virtual repositories that aggregate tenant GAR repositories.
terraform/tenants/main.tf
Entry point for defining individual tenants within the business unit. This is where teams add create-tenant module calls.
terraform/tenants/variables.tf
Variable definitions for tenant creation, pre-populated with the BU suffix and environment configuration.
terraform/tenants/remote.tf (conditional)
Only created when foundations_access.enable = true. Provides remote state access to foundation layers for reading VPC subnets and other shared infrastructure.
GAR Configuration
When GAR is enabled, the module creates virtual repositories at the BU level that aggregate tenant-level standard repositories via upstream policies.
gar = {
enable = true
location = "us-central1"
artifact_types = ["DOCKER", "NPM"]
}
Supported artifact types: DOCKER, MAVEN, NPM, PYTHON, APT, YUM, GO.
The tiered GAR architecture works as follows:
- Tenant-level: Standard repositories per environment per artifact type (created by the tenant module)
- BU-level standard repos: In the shared tenant project, standard repositories for BU-wide artifacts
- BU-level virtual repos: Virtual repositories that aggregate all tenant + shared repos via upstream policies, providing a single pull endpoint
Usage Example
module "business_unit" {
source = "app.terraform.io/Badal_devex/create-business-unit/platform"
version = "~> 1.0"
business_unit = "data"
gh_org = "badal-io"
environments = {
development = {
org_id = "758951886862"
billing_account_id = "01DEF7-F9833E-AD765A"
parent_folder_id = "folders/123456789" # fldr-development
}
non-production = {
org_id = "758951886862"
billing_account_id = "01DEF7-F9833E-AD765A"
parent_folder_id = "folders/234567890" # fldr-non-production
}
production = {
org_id = "758951886862"
billing_account_id = "01DEF7-F9833E-AD765A"
parent_folder_id = "folders/345678901" # fldr-production
}
}
single_workspace = {
org_id = "758951886862"
billing_account_id = "01DEF7-F9833E-AD765A"
parent_folder_id = "folders/456789012" # fldr-common
service_account_roles = ["roles/resourcemanager.folderAdmin"]
}
tfc = {
org_id = "Badal_devex"
gh_app_oauth_id = "ot-xxxxxxxxxxxxx"
token = var.tfc_token
}
gh_app = {
id = "123456"
installation_id = "12345678"
private_key = var.github_app_private_key
}
gar = {
enable = true
location = "us-central1"
artifact_types = ["DOCKER", "PYTHON"]
}
}
Deployed Business Units
| Business Unit | Suffix | Repo | Environments | GAR |
|---|---|---|---|---|
| data | 80r13 | bu-data-80r13 | dev, non-prod, prod | DOCKER, PYTHON |
| devex | 9c9dl | bu-devex-9c9dl | non-prod, prod | DOCKER, NPM |
| platform | 0r4dp | bu-platform-0r4dp | dev, non-prod, prod | None |
Data BU (80r13)
The data business unit is the largest, with 346 TFC-managed resources. It has GAR enabled for Docker and Python artifacts, and hosts tenants including governance and template.
DevEx BU (9c9dl)
The developer experience business unit runs in non-production and production only (no development environment). It has GAR for Docker and NPM, supporting the Backstage portal and related tooling.
Platform BU (0r4dp)
The platform business unit manages foundational platform services including the GKE ArgoCD tenant. It does not use GAR.