Google Cloud — folder canon, IAM, and operational rules¶
Org: ucca.edu.au (org ID 731589017464, customer ID C02dhi61x)
Last updated: 2026-05-07 (post GCP-FOLDER-CANON-01)
Brief in archive: docs/briefs/archive/gcp-folder-canon-01.md v1.2
Folder hierarchy¶
ucca.edu.au
├── rtopacks/ → admin@rtopacks.com.au
├── ucca-online/ → admin@ucca.online
├── ucca-edu-au/ → tim@ucca.edu.au
├── tooling/ → tim@ucca.edu.au
├── archive/ → tim@ucca.edu.au only
└── personal-or-experimental/ → tim@ucca.edu.au only (sub-folder owners get Editor)
├── hunter-richards/ → Dom Hunter + Antony Richards (Editor)
├── arrowaccountants/ → Kevin Singh (Editor)
└── tim-personal/ → tim@ucca.edu.au
| Folder | ID |
|---|---|
rtopacks/ |
648604026052 |
ucca-online/ |
321449398372 |
ucca-edu-au/ |
600535416745 |
tooling/ |
756590331639 |
archive/ |
205278468367 |
personal-or-experimental/ |
911973651944 |
personal-or-experimental/hunter-richards/ |
756755166908 |
personal-or-experimental/arrowaccountants/ |
638641471978 |
personal-or-experimental/tim-personal/ |
6914142780 |
tim@ucca.edu.au retains Organization Administrator at org level as the org-wide recovery backstop, inherited everywhere.
Principle¶
| Concern | Mechanism |
|---|---|
| Entity ownership (RTOpacks, UCCA Online, etc.) | Folders |
| Environment scope (shared, prod, dev) | Naming convention + labels |
Folders are entity-scoped only. Environment information never goes into folder hierarchy.
Project naming + labels¶
Project ID patterns:
- <entity>-<purpose> — serves both prod and dev (e.g. rtopacks-maps)
- <entity>-<purpose>-<env> — environment-scoped (e.g. rtopacks-billing-prod)
- <scope>-<purpose> — tooling/meta (e.g. gcp-canon-tooling)
Project IDs are immutable post-creation. To rename: create-new with canonical ID, migrate, delete old.
Mandatory labels per project: entity (rtopacks/ucca-online/ucca-education/tooling/archive/personal), environment (shared/prod/dev), and consumer (free-text, optional). Firebase auto-labels (firebase=enabled) coexist via merge-not-replace. Label updates require the v3 Cloud Resource Manager REST API — gcloud projects update does not support --update-labels.
Containment for personal-or-experimental/¶
Org-policy billing constraints are unavailable on this org (v1 deprecated, v2 missing the constraint). The brief's containment intent is satisfied by IAM state — no contained user holds any role on any org billing account, so they cannot link org billing regardless of project Owner status. This is structural, not a gap.
Trigger condition that would activate the gap: granting any role on any org-owned billing account to a principal whose primary GCP access is under personal-or-experimental/. If that ever happens, BILLING-CONSTRAINT-GAP-01 must be revisited before the grant lands.
Soft-delete restore prerequisites¶
If you are about to restore a soft-deleted project from this org, check this table first.
| Project | SA | Key ID | Created | Required pre-restore action |
|---|---|---|---|---|
still-vim-413000 |
ucca-learnworlds@still-vim-413000.iam.gserviceaccount.com |
dc96863ecf3558d00c1254afc614d5795cb806ce |
2024-02-01 | Delete key, disable SA, before any production use |
ucca-drive-proxy |
drive-proxy@ucca-drive-proxy.iam.gserviceaccount.com |
unknown (cannot query post-soft-delete) | unknown | Verify SA key inventory; if any USER_MANAGED keys exist, delete + disable SA before any production use |
mobile-ucca-college |
firebase-adminsdk-9ofdn@mobile-ucca-college.iam.gserviceaccount.com |
unknown (cannot query post-soft-delete) | unknown | Vendor (LearnWorlds) had Editor on this Firebase-tagged mobile project; standard Firebase Admin SDK pattern requires JSON key export to vendor backend; likely a USER_MANAGED key exists. Verify and delete + disable before any production use. |
Omitted from table: seven other soft-deleted projects host firebase-adminsdk SAs that could in principle have USER_MANAGED keys exported, but share the same low-likelihood pattern (Firebase-tagged at creation, no surfaced active consumer in Stage 1 audit, no other custom SAs, no API key activity, no vendor IAM grants): groupon-usa, ucca-education-aa0ee, dlongglobal-com, dlongglobal-net, dlongglobal-org, jimmykuo-com-au-ec206, ttca-edu-au. Realistic likelihood of a backend service holding their JSON key: essentially zero. Caveat: if you're restoring one of these seven, verify SA key inventory before any production use, treating the project as if it were on this table.
SA roles inventory¶
gcp-canon-01-agent@gcp-canon-tooling.iam.gserviceaccount.com is the persistent bounded-access SA for org-wide GCP operational work. Hosted in gcp-canon-tooling. Key vaulted in 1Password as item "GCP — gcp-canon-01-agent SA key" — retrieve via op CLI for SA auth setup; no persistent local copy.
11 current roles at org level:
- Read-only (4):
roles/viewer,roles/iam.securityReviewer,roles/billing.viewer,roles/resourcemanager.organizationViewer - Resource management (5):
roles/resourcemanager.folderAdmin,roles/resourcemanager.projectMover,roles/resourcemanager.projectDeleter,roles/resourcemanager.projectIamAdmin,roles/orgpolicy.policyAdmin - IAM management (2):
roles/iam.securityAdmin,roles/iam.serviceAccountKeyAdmin
Future briefs may add or trim roles based on task scope. AGENT-ROLES-AUDIT-01 (queued) is a short review to identify any genuinely audit-only roles that could be trimmed without affecting ongoing operational use.
Three lessons (for future GCP briefs)¶
- API enablement is per-quota-project. SAs hosted in tooling projects need every used Google API enabled on that project, not the org.
SERVICE_DISABLEDerrors quote the quota project's number — easy to misread as a permission error. - Org policy v2 catalog can lack constraints documented in v1. Reads via v1 may show a constraint with empty etag; writes only work via v2. Verify in the v2 catalog before designing org policies —
billing.allowedBillingAccountsListis a known gap. - gcloud syntax for in-project SA operations requires explicit
--project=even when the SA email contains the project ID. Without it, gcloud reports "Failed to find attribute [project]" rather than parsing from the email.