workload_deployer — version 1.0

Source: presets/workload-deployer.satz

Purpose

One deployer identity per customer team. A Google project of the team's own holds the service account its pipelines run as and the bucket its states live in, and the account holds the roles it needs to roll out folders and Google projects under the workload folder — nothing more.

A team rolls out many Google projects and folders with templates of its own, in OpenTofu or in Satz, each with its own state; it never runs as the organisation's IaC account. One entry of workload_deployers, { name = "platform" group = "gcp-project-admins@example.com" }, is one team — bound in the estate, or requested by the team as contributes_workload_deployers in a small pack of its own, checked with satz check-request and vendored by pull request. name is lowercase letters, digits and -, starting with a letter; group is the address of the group that may become the account; folder is the parent the team creates under, google_folder.workload_folder.name unless the entry names another.

PER ENTRY. The team's infrastructure project {customer_shortname}-deploy-<name> under deployer_project_folder, billed to the infrastructure billing account, with the APIs a deployer's calls need. Inside it the account svc-deploy-<name> and the state bucket {customer_shortname}-deploy-<name>-state, which the account may write; the group reads the project and may become the account — that account only.

WHAT THE ACCOUNT MAY DO. On the parent folder, deployer_folder_roles: create and manage folders and Google projects under it, set their IAM and enable their APIs. On the billing account, deployer_billing_roles: link a new project to it. On the organisation, deployer_organization_roles — roles/browser and nothing else by default: the interface looks the workload folder up by its name among the organisation's folders, and that listing needs resourcemanager.folders.list on the organisation; without it the team's plan stops at the lookup. The three lists are params, so a customer changes the set without a fork.

MORE PARENT FOLDERS. A team that creates under several folders gets one entry of workload_deployer_folders per further parent, { name = "platform-shared" deployer = "platform" folder = "google_folder.shared.name" }, which grants deployer_folder_roles on that folder to the team's account.

WHO RUNS WHAT. The team's pipeline impersonates svc-deploy-<name> and keeps its state in the team's bucket; the organisation's state is never read — a looked-up value asks the Google API for the live resource. The account's address is the pattern above; the pack exports no interface.

NO CLAIM. The teams' identities are workloads, not controls: this pack witnesses nothing.

Use it

params {
  use_workload_deployer = true

  // the pack's own defaults — copy only the lines you change
  workload_deployers = []
  workload_deployer_folders = []
  deployer_project_folder = ""
  deployer_folder_roles = [
    "roles/resourcemanager.folderAdmin",
    "roles/resourcemanager.projectCreator",
    "roles/resourcemanager.projectIamAdmin",
    "roles/serviceusage.serviceUsageAdmin",
  ]
  deployer_organization_roles = [ "roles/browser" ]
  deployer_billing_roles = [ "roles/billing.user" ]
  deployer_group_roles = [
    "roles/iam.serviceAccountTokenCreator",
    "roles/iam.serviceAccountUser",
  ]
}

use "presets/workload-deployer.satz" when use_workload_deployer

use_workload_deployer is the gate: while it is falsy the pack contributes nothing — no resources, no params, no claims. It is declared by estate_map, and the estate's own binding wins.

Needs from outside the pack:

Params

param default
workload_deployers []
workload_deployer_folders []
deployer_project_folder ""
deployer_folder_roles [ "roles/resourcemanager.folderAdmin", "roles/resourcemanager.projectCreator", "roles/resourcemanager.projectIamAdmin", "roles/serviceusage.serviceUsageAdmin" ]
deployer_organization_roles [ "roles/browser" ]
deployer_billing_roles [ "roles/billing.user" ]
deployer_group_roles [ "roles/iam.serviceAccountTokenCreator", "roles/iam.serviceAccountUser" ]

Questions

What to ask before this pack is configured, and what changing the answer costs.

asks about prompt reversal blast recommends
deployer_project_folder The folder the teams' infrastructure projects are created in — the infrastructure folder as google_folder.infra_folder.name, another folder the estate declares as google_folder.<label>.name, an existing one by its numeric id, or empty for the organisation edit low "google_folder.infra_folder.name"

deployer_project_folder — It decides the policies the teams' projects inherit. Changing it afterwards moves every live team project between parents.

An empty answer, "", is an answer: the organisation itself.

Contributes

resource type labels
google_billing_account_iam_member billing_account_id (grant map), one per entry of workload_deployers, by name
google_folder_iam_member one per entry of workload_deployers, by name, one per entry of workload_deployer_folders, by name
google_organization_iam_member one per entry of workload_deployers, by name
google_project one per entry of workload_deployers, by name

Requests

What a project may add to this pack's lists, through contributes_<param> in a file the estate uses after a reviewed pull request; satz check-request checks such a file.

list key fields description
workload_deployers name name matching [a-z][a-z0-9-]*, group matching [^@: ]+@[^@: ]+, folder A team that rolls out folders and Google projects: its name, the address of the group that may become its account, and the folder it creates under
workload_deployer_folders name name matching [a-z][a-z0-9-]*, deployer matching [a-z][a-z0-9-]*, folder A further parent folder a team creates under: the entry's name, the team's name, and the folder

Claims

None — this pack proves no control by itself.

History

version date change
1.0 2026-10-15 first version: one deployer identity per customer team — per entry of the request point workload_deployers, { name group folder }, the team's infrastructure Google project under deployer_project_folder, inside it the account svc-deploy-<name> and the state bucket, deployer_folder_roles on the entry's folder and on each entry of workload_deployer_folders, deployer_billing_roles on the billing account, deployer_organization_roles (roles/browser, for the interface's lookups) on the organisation, and deployer_group_roles for the team's group on the account alone

The whole library's history: the changelog in presets/CHANGELOG.md.

Notes

No notes yet.