9.3 Authorization
Authorization answers three questions: who may act, what may they do, and on which resources? Each Moonitoring cloud service has its own identity, so reading datasets does not require the same access as operating the infrastructure. The identities themselves, for people, services and customers, are introduced in Identity & Access; this page lists what each one may do.
Historical configuration snapshot — 29 October 2026
The service/operator tables and counts below describe infrastructure commit 32e7079, not current live access. At that revision, bootstrap and stage deployment were pending the company billing choice. The pinned source links preserve that historical evidence; do not use the old project scopes, foundation/production access or assignment counts to grant access today.
Current stage and human-group rollout — 4 November 2026
Stage infrastructure is deployed and its synthetic SQL access checks passed; see the stage acceptance record. The active foundation scope is shared/stage, production remains excluded, and application images, API callers and automatic triggers remain inactive. Jacopo retains the existing named foundation/stage-operator grants and Database-project Cloud SQL Viewer access; the latter is not SQL login or Studio access.
Six security groups exist; their Google display names have a gcp prefix, their emails do not. The selected model uses one infra-admins@moonitoring.com group, stage/prod approval groups (stage-release-admins, prod-release-admins) and stage/prod observer groups (stage-observers-admins, observers-admins), all at moonitoring.com. stage-infra-admins@moonitoring.com exists but remains unused and unchanged. No IAM grants to these groups are live, and the named grants have not been removed. See the verified and pending membership checks and the team-access runbook.
9.3.1 How access is assigned¶
The stage phase 1 provisioned four additional empty databases and ten API/migration Google identities, verified on 5 November 2026. It left the legacy platform database and four runtime identities in place and added no SQL IAM users, Cloud SQL Client/Instance User grants or PostgreSQL privileges. The new databases are not yet isolated from existing SQL users: closing default PUBLIC CONNECT/TEMPORARY access and verifying per-component grants remains phase 2. The earlier acceptance record and historical tables below do not certify these new boundaries.
Google Cloud Identity and Access Management (IAM) assigns a role (a bundle of permissions) to an identity on a resource. For example: the dataset reader receives the object-viewer role on the datasets bucket. A grant on a project or folder can also apply to resources below it. See Google's IAM overview.
We prefer Google-managed roles. Terraform declares group/service-account assignments; terraform plan shows the proposed changes, and terraform apply makes them effective in Google Cloud. The proposed stage SQL observer is a deliberate custom-role exception: instance/database/user/backup metadata reads, without login, connect, executeSql, mutation or export. The predefined Cloud SQL Viewer includes cloudsql.backupRuns.export, so it is not equivalent to this narrower role. Editing a Terraform file alone changes no permissions.
Authorized directory administrators manage human group membership outside Terraform. A group owner approves and records additions/removals; a membership change grants only the group's assigned cloud permissions. It does not create application capabilities, tenant roles or entitlements. The selected infrastructure administrator group is intended to impersonate foundation and active-environment plan/apply identities through infrastructure_admin_groups, currently empty. It must be limited to trusted infrastructure administrators. Production access requires explicit environment activation; this input does not expand access to unrelated legacy projects or transfer organization-policy delegation. Observer groups have no impersonation or state-object access. Ordinary-log access can expose information written into logs; it is not a guarantee that the content contains no application data.
Stage release approval is a planned build/deployment gate separate from PR review, not a gate on every Google Cloud operation. It blocks the configured Cloud Build execution before plan and apply; it does not approve the exact plan generated later. Cloud Build's approver role is project-wide in the shared CI project, so separate stage/prod group names do not establish separate approval scopes. Production trigger activation is rejected while stage approver groups are configured, pending a reviewed solution. Broad infrastructure impersonation permissions can bypass this pipeline path, and group membership can overlap: the process does not enforce hard author/approver separation. No approval workflow, production group IAM, PAM or Cloud Deploy is live from this rollout. See the activation guard and review rules.
These cloud identities are separate from application users, organization memberships and roles. Cloud IAM controls access to infrastructure. Application authorization determines which farm's records a user may see.
9.3.2 Application services¶
This section describes the historical 29 October configuration snapshot, including its source links and then-outstanding SQL work. It is not the current deployment record.
Each row is a dedicated Google service account. Terraform creates the identities and attaches the corresponding identity to each configured workload. The table describes grants made by this configuration; it does not audit additional inherited or manually assigned access.
| Identity | Allowed actions | Resource scope | Terraform definition |
|---|---|---|---|
platform-api |
Connect to Cloud SQL and authenticate with IAM | Platform stage project | Database access |
farm-api |
Connect/authenticate to Cloud SQL; create and read raw objects; publish ingestion requests | Farm stage project for SQL; raw bucket; ingestion-requests topic |
Database, raw, publisher |
farm-worker |
Connect/authenticate to Cloud SQL; read raw objects; receive and acknowledge ingestion messages | Farm stage project for SQL; raw bucket; ingestion-workers subscription |
Database, raw, subscriber |
dataset-builder |
Connect/authenticate to Cloud SQL; create and read dataset objects | Farm stage project for SQL; datasets bucket | Database, datasets |
ml-dataset-reader |
Read and list dataset objects | Datasets bucket only in these grants | Dataset reader |
The assigned roles are roles/cloudsql.client and roles/cloudsql.instanceUser for database access; roles/storage.objectCreator and/or roles/storage.objectViewer for objects; and roles/pubsub.publisher or roles/pubsub.subscriber for messages. Concrete project and bucket names are in the stage inputs.
Database access still needs a second layer. Cloud SQL roles are granted at project level, while IAM database users are registered on the corresponding instance. Neither grants permission to read or modify application tables: SQL (Structured Query Language) roles, GRANT statements and row-level authorization remain to be implemented. The dataset builder's intended read access must be enforced there. See the database module's boundaries.
9.3.3 Infrastructure operators and automation¶
This section describes the historical 29 October configuration snapshot, including its tables, explanatory scope statements and assignment counts. It is not the current stage-only access boundary.
Deployment needs broader permissions than an application. We separate the identity that previews changes from the identity that applies them. Authorized people and build jobs can impersonate a service account: obtain temporary credentials and act with that account's permissions. This Terraform creates no service-account key files.
| Identity | Allowed actions | Resource scope | Terraform definition |
|---|---|---|---|
sa-tf-foundation |
Administer foundation folders, project creation/IAM and policies; manage state objects; associate the selected billing account | Five new child folders, including production; all three state buckets; selected billing account | Foundation roles, billing and state |
sa-stage-tf-plan |
Inspect resources and IAM policies; read state | Stage folder and its descendants; stage state bucket | Read roles, state |
sa-stage-tf-apply |
Create/manage stage projects, network, databases, services, storage, queues and IAM; manage state and billing association | Stage folder and its descendants; stage state bucket; selected billing account | Apply roles, billing and state |
sa-cloudbuild-validate |
Write build logs | Build project; no infrastructure/state or impersonation grants | Build grants |
sa-stage-cloudbuild-plan |
Write build logs; impersonate sa-stage-tf-plan |
Build project; named plan service account | Build grants |
sa-stage-cloudbuild-apply |
Write build logs; impersonate sa-stage-tf-apply |
Build project; named apply service account | Build grants |
| Named human operators | Impersonate the identities listed in their allowlists | Currently jtedeschi@moonitoring.com: foundation, stage plan and stage apply |
Allowlists, impersonation |
sa-prod-tf |
Disabled; no operational or state grants | Reserved production identity | Disabled account |
At that historical revision, foundation was an administrative exception across environments. Disabling sa-prod-tf did not remove foundation access to production folders and state. Build jobs received no foundation impersonation grant. That historical production scope does not describe the current shared/stage-only foundation. Stage apply is a privileged deployment identity, not an application identity.
Google also needs its own service agents to operate managed services:
| Google-managed identity | Allowed actions | Resource scope | Terraform definition |
|---|---|---|---|
| Cloud Run service agents | Operate Cloud Run; inspect the shared network and use the corresponding subnet | Own application project, network host project, assigned subnet | Service roles, network access |
| Service Networking agent | Manage private service connectivity | Network host project | Service role |
| Pub/Sub service agent | Forward failed messages and acknowledge the source subscription | ingestion-dead-letter topic and ingestion-workers subscription |
Dead-letter grants |
Assignment counts at this revision
With the allowlists at that revision and assuming its missing inputs were supplied, the code declared 96 explicit role–identity–resource assignments: 71 for bootstrap, 16 for application/ML identities, and 9 for Google service agents. It used 37 distinct predefined roles and declared 12 user-managed service accounts, including the disabled production account.
These are not 96 individual API permissions. The count excludes automatic, inherited or pre-existing grants and the four SQL IAM users. Empty workload/caller inputs at that revision produced zero roles/run.invoker assignments. Changing those inputs or operator lists changes the count.
9.3.4 Changing access in practice¶
An assignment names the resource, role and identity explicitly. For example, the dataset-reader grant is:
resource "google_storage_bucket_iam_member" "ml_dataset_read" {
bucket = module.datasets.name
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.ml_reader.email}"
}
To change a group's cloud role or resource scope, edit Terraform, review the plan, and follow the current team-access runbook. To join or leave an existing approved group, follow the directory membership process; a Terraform run is not required. Verify both allowed and denied operations using the affected identity. Review inherited and direct exceptions before claiming revocation or isolation. Current acceptance records accompany current grants; the pinned tables above remain historical evidence.
Farm installations are represented by SyncClient. Their authentication, application authorization and farm-level data isolation are separate implementation work. The grants above do not give each installation a Google service account or implement those controls.
9.3.5 Rules for Application Authorization¶
Cloud IAM decides what an identity may do to infrastructure. Inside our systems, every check follows these rules:
- Deny by default. An action is allowed only when a role explicitly grants it.
- Two gates for customers. The user's role must include the capability, and the user's Organization must hold the entitlement. The system checks both itself, from the token signed by
accessand its own copy of the entitlements published byfarm(see Organizations & Access). - Capabilities are named
<system>.<resource>.<action>, for examplefarm.models.use,access.members.manageorreleases.releases.approve. The first part is the short name of the system that checks it (see System Overview). - Not authorized means not found. For something the caller may not see, a service answers exactly as if it did not exist, so nothing can be discovered by trying.
- Staff work through the same checks. The Console holds no permissions of its own; each system checks the staff member's capabilities like any other caller.
- Prod data needs a temporary grant, approved by a second person (see Access to Prod).