Getting started
Google Cloud
Dormeto's router runs in your Google Cloud project as a service account of its own, with two custom roles and a few predefined ones. Dormeto never creates them itself: the CLI does, with your own account, and prints every IAM change it makes. This page lists everything the router needs and everything the CLI changes, permission by permission. It then says how to check it and how to remove it.
14 min readManager 0.21.0
- Accepted on a real project (2026-10-30).
dormeto gcp check,install,uninstall,statusandworkloads. Also Compute Engine VMs (unmanaged and managed groups, suspended when possible) behind a global external Application Load Balancer. - Built and reviewed, its acceptance not run yet. Regional and classic load balancers, zonal network endpoint groups, schedules and pauses, IP lists. Some of their behavior was measured on Google, and no more than that.
- Written, never run against Google. Cloud SQL companions and GKE. Try them in a project you can lose. The CLI prints a warning when you use them, and goes on.
There is no public router image: you build your own and push it to your Artifact Registry. There is no dashboard or manager for Google Cloud yet, and the branded waiting page does not apply to it. Router 0.35.0 and CLI 0.8.0 carry all of this code.
What it needs
| What it is | Where | What it is for |
|---|---|---|
| The APIs | The project | Ten APIs (the list). dormeto gcp install turns them on and never turns one off. |
| Two custom roles | The project | dormetoRouter reads the load balancers, VMs and groups and manages the waker backend services. dormetoRouterBackends starts, stops, suspends and resumes the VMs and groups that carry the tag (every permission). |
| The router's service account | The project | dmtr-<region>@<project>.iam.gserviceaccount.com: the only identity the router's Cloud Run services and tasks use (its grants). |
| The secure tag | The project | dormeto=managed. The router starts and stops only the VMs and groups that carry it. You bind it when you onboard a workload. The router itself holds no permission to tag, or it could tag any VM and stop it. |
| The router's state | The router's region | A Firestore database dmtr-<region> (Native mode, delete protection off) and a Cloud Tasks queue dmtr-<region>. The database also holds the install record, which uninstall reads. |
| The router | The router's region, with --image | Two Cloud Run services, dmtr-<region>-waker and dmtr-<region>-controller, the waker's network endpoint group dmtr-<region>-waker and the Cloud Scheduler job dmtr-<region>-check (every 5 minutes). |
| Each workload | Your load balancer | A backend service dmtr-<region>-<workload> that sends the waiting page, and the tag on the workload's VMs and groups. Onboarding adds a route /_dormeto/* to that backend service for good. Offboarding restores every reference. If Terraform writes your load balancer or VMs, it needs to ignore what changes. |
| Optional access | The project, if you ask for it | Cloud SQL and GKE have their own API and roles, from router 0.35.0 (what each adds). |
The APIs
dormeto gcp install turns on these ten APIs, .googleapis.com each, in the project. uninstall turns none off: other things in the project may use them.
| API | Service |
|---|---|
compute.googleapis.com | Compute Engine |
run.googleapis.com | Cloud Run |
firestore.googleapis.com | Firestore |
cloudtasks.googleapis.com | Cloud Tasks |
cloudscheduler.googleapis.com | Cloud Scheduler |
monitoring.googleapis.com | Cloud Monitoring |
artifactregistry.googleapis.com | Artifact Registry |
iam.googleapis.com | Identity and Access Management |
cloudresourcemanager.googleapis.com | Cloud Resource Manager |
logging.googleapis.com | Cloud Logging |
The roles
Two custom roles, created in the project, and four predefined roles. Every permission below is in the manifest the router and the CLI share. The router's tests check that each Google Cloud call it makes is covered by one of them.
dormetoRouter
Dormeto router. Lets a Dormeto router read its workloads' load balancers, VMs and groups, and update their URL maps. It can create and delete their waker backend services, and turn their autoscalers off and back on. It reads their request counts.
| Resource | Permissions |
|---|---|
compute.urlMaps | compute.urlMaps.get, compute.urlMaps.list, compute.urlMaps.update |
compute.backendServices | compute.backendServices.get, compute.backendServices.use, compute.backendServices.create, compute.backendServices.delete |
compute.regionNetworkEndpointGroups | compute.regionNetworkEndpointGroups.use |
compute.globalForwardingRules | compute.globalForwardingRules.list |
compute.targetHttpProxies | compute.targetHttpProxies.list |
compute.targetHttpsProxies | compute.targetHttpsProxies.list |
compute.instances | compute.instances.get |
compute.instanceGroups | compute.instanceGroups.get |
compute.instanceGroupManagers | compute.instanceGroupManagers.get |
compute.autoscalers | compute.autoscalers.get, compute.autoscalers.update |
compute.machineTypes | compute.machineTypes.get |
compute.globalOperations | compute.globalOperations.get |
compute.zoneOperations | compute.zoneOperations.get |
compute.regionOperations | compute.regionOperations.get |
monitoring.timeSeries | monitoring.timeSeries.list |
compute.networkEndpointGroups | compute.networkEndpointGroups.get |
compute.regionUrlMaps | compute.regionUrlMaps.get, compute.regionUrlMaps.list, compute.regionUrlMaps.update |
compute.regionBackendServices | compute.regionBackendServices.get, compute.regionBackendServices.use, compute.regionBackendServices.create, compute.regionBackendServices.delete |
compute.regionTargetHttpProxies | compute.regionTargetHttpProxies.list |
compute.regionTargetHttpsProxies | compute.regionTargetHttpsProxies.list |
compute.forwardingRules | compute.forwardingRules.list |
Google marks compute.urlMaps.get, compute.urlMaps.list and compute.urlMaps.update as testing in custom roles: usable, not recommended for production by Google. No narrower predefined role holds them, so dormetoRouter keeps them. An autoscaler cannot carry a tag, so compute.autoscalers.update is here, without the tag condition.
dormetoRouterBackends
Dormeto router backends. Lets a Dormeto router start, stop, suspend and resume its workloads' VMs and managed instance groups. Granted on the condition that the resource has the tag dormeto=managed.
| Resource | Permissions |
|---|---|
compute.instances | compute.instances.start, compute.instances.stop, compute.instances.suspend, compute.instances.resume |
compute.instanceGroupManagers | compute.instanceGroupManagers.update, compute.instanceGroupManagers.use |
Granted on the condition that the resource has the tag dormeto=managed. An autoscaler's change names its group, so compute.instanceGroupManagers.update and .use are checked on the group's tag.
Predefined roles
Granted as described in the grants. Dormeto relies on these permissions of each:
| Role | Permissions |
|---|---|
roles/datastore.user | datastore.entities.get, datastore.entities.list, datastore.entities.create, datastore.entities.update, datastore.entities.delete |
roles/cloudtasks.enqueuer | cloudtasks.tasks.create |
roles/run.invoker | run.routes.invoke |
roles/iam.serviceAccountUser | iam.serviceAccounts.actAs |
The grants
The router runs as the service account dmtr-<region>@<project>.iam.gserviceaccount.com. The CLI adds exactly these bindings, and only these. It never changes or removes a binding it did not add. In a condition, {project} is the project's ID and {database} is the router's database, dmtr-<region>.
| Role | Where | Condition | What it allows |
|---|---|---|---|
projects/{project}/roles/dormetoRouter | The project | None | Reads and manages the load balancers, VMs and groups of the workloads. |
projects/{project}/roles/dormetoRouterBackends | The project | Dormeto-managed resources: resource.matchTag('{project}/dormeto', 'managed') | Starts and stops what carries the tag. |
roles/datastore.user | The project | The router's database: resource.name == "projects/{project}/databases/{database}" | Reads and writes the router's Firestore documents. |
roles/cloudtasks.enqueuer | The queue dmtr-<region> | None | Creates tasks in the router's queue. |
roles/run.invoker | The Cloud Run service dmtr-<region>-controller | None | Calls the controller. The Cloud Scheduler job and the tasks do, as the service account. |
roles/iam.serviceAccountUser | The service account itself | None | Signs the tasks' OIDC tokens as itself. |
What Google adds
Turning APIs on and creating resources makes Google add bindings of its own to the project's IAM policy. Dormeto uses none of them for its own work. The CLI prints each one as Google's, with the step it appeared after, and records it. Seen on a real project, seven were added during the install, and an eighth when the image's repository was created:
| Role | Member | Appeared after | Whose |
|---|---|---|---|
roles/cloudscheduler.serviceAgent | serviceAccount:service-<project number>@gcp-sa-cloudscheduler.iam.gserviceaccount.com | apis | Cloud Scheduler's service agent |
roles/cloudtasks.serviceAgent | serviceAccount:service-<project number>@gcp-sa-cloudtasks.iam.gserviceaccount.com | apis | Cloud Tasks' service agent |
roles/containerregistry.ServiceAgent | serviceAccount:service-<project number>@containerregistry.iam.gserviceaccount.com | apis | Container Registry's service agent |
roles/pubsub.serviceAgent | serviceAccount:service-<project number>@gcp-sa-pubsub.iam.gserviceaccount.com | apis | Pub/Sub's service agent |
roles/run.serviceAgent | serviceAccount:service-<project number>@serverless-robot-prod.iam.gserviceaccount.com | apis | Cloud Run's service agent |
roles/firestore.serviceAgent | serviceAccount:service-<project number>@gcp-sa-firestore.iam.gserviceaccount.com | database | Firestore's service agent |
roles/firebaserules.system | serviceAccount:service-<project number>@firebase-rules.iam.gserviceaccount.com | projectBindings | Firebase Rules' system account, added late, from the database |
roles/artifactregistry.serviceAgent | serviceAccount:service-<project number>@gcp-sa-artifactregistry.iam.gserviceaccount.com | Creating the image's repository, which the CLI doesn't do | Artifact Registry's service agent. The CLI's next run shows it as seen later |
The step names are those of the operator's table. The service agents are Google's to manage: leave them. uninstall leaves them too, and lists them as left in place. Compute Engine's own service agents, already there once Compute Engine is on, are Google's as well.
The default service account's Editor
Take a project outside an organization that enforces the constraint iam.automaticIamGrantsForDefaultServiceAccounts. When Compute Engine is turned on, Google gives its default service account, <project number>-compute@developer.gserviceaccount.com, the role roles/editor on the whole project. Dormeto does not use it: the router's Cloud Run services run as dmtr-<region>. dormeto gcp check reports the grant as a warning and leaves it: it is yours to remove. Before you do, check which VMs, instance templates and services run as that account, since they lose what Editor gave them:
gcloud compute instances list --format="table(name,zone.basename(),serviceAccounts[].email)"
gcloud projects remove-iam-policy-binding my-project \
--member="serviceAccount:123456789012-compute@developer.gserviceaccount.com" \
--role="roles/editor"
To keep Google from granting it again in your next projects, enforce iam.automaticIamGrantsForDefaultServiceAccounts on the organization or the folder.
The operator's permissions
You run the CLI with your gcloud account (its active configuration, or --gcloud-configuration). Each command tests the permissions of its steps before it changes anything: one missing stops it with nothing changed. roles/owner holds all of them. The tables list the steps of each command, as the manifest does.
dormeto gcp check
| Step | What for | Permissions |
|---|---|---|
read | Read the project, its IAM policy and the APIs that are on | resourcemanager.projects.get, resourcemanager.projects.getIamPolicy, serviceusage.services.list, serviceusage.services.use |
dormeto gcp install
| Step | What for | Permissions |
|---|---|---|
read | Read the project, its IAM policy and the APIs that are on | resourcemanager.projects.get, resourcemanager.projects.getIamPolicy, serviceusage.services.list, serviceusage.services.use |
apis | Turn the APIs on | serviceusage.services.enable, serviceusage.operations.get |
roles | Create or update the custom roles (a deleted role's ID cannot be reused for 37 days: the CLI undeletes it) | iam.roles.get, iam.roles.create, iam.roles.update, iam.roles.undelete |
serviceAccount | Create the router's service account and bind it | iam.serviceAccounts.get, iam.serviceAccounts.create, iam.serviceAccounts.getIamPolicy, iam.serviceAccounts.setIamPolicy, iam.serviceAccounts.actAs |
projectBindings | Read the IAM policy, add Dormeto's bindings, write it with its etag | resourcemanager.projects.getIamPolicy, resourcemanager.projects.setIamPolicy |
tag | Create the secure tag | resourcemanager.tagKeys.create, resourcemanager.tagKeys.get, resourcemanager.tagValues.create, resourcemanager.tagValues.get |
database | Create the Firestore database, write the install record | datastore.databases.create, datastore.databases.get, datastore.operations.get, datastore.entities.create, datastore.entities.get, datastore.entities.update |
queue | Create the task queue and bind it | cloudtasks.queues.create, cloudtasks.queues.get, cloudtasks.queues.update, cloudtasks.queues.getIamPolicy, cloudtasks.queues.setIamPolicy |
dormeto gcp install --image
Added to install when you give the router's image.
| Step | What for | Permissions |
|---|---|---|
image | Read the router's image in Artifact Registry | artifactregistry.repositories.get, artifactregistry.repositories.downloadArtifacts, artifactregistry.dockerimages.get |
cloudRun | Create the two Cloud Run services, turn the waker's invoker check off | run.services.create, run.services.get, run.services.update, run.services.getIamPolicy, run.services.setIamPolicy, run.operations.get, run.routes.invoke, iam.serviceAccounts.actAs |
neg | Create the waker's network endpoint group | compute.regionNetworkEndpointGroups.create, compute.regionNetworkEndpointGroups.get, compute.regionOperations.get |
job | Create the check job | cloudscheduler.jobs.create, cloudscheduler.jobs.get, cloudscheduler.jobs.update, iam.serviceAccounts.actAs |
dormeto gcp uninstall
| Step | What for | Permissions |
|---|---|---|
read | Read the project, the install record and the workloads | resourcemanager.projects.get, resourcemanager.projects.getIamPolicy, serviceusage.services.list, serviceusage.services.use, datastore.databases.list, datastore.databases.get, datastore.entities.get, datastore.entities.list, run.routes.invoke |
job | Delete the check job | cloudscheduler.jobs.get, cloudscheduler.jobs.delete |
neg | Delete the network endpoint group | compute.regionNetworkEndpointGroups.get, compute.regionNetworkEndpointGroups.delete, compute.regionOperations.get |
cloudRun | Delete the Cloud Run services | run.services.get, run.services.delete, run.operations.get |
queue | Delete the queue | cloudtasks.queues.get, cloudtasks.queues.delete |
database | Delete the database | datastore.databases.get, datastore.databases.delete, datastore.operations.get |
projectBindings | Remove the bindings the install added | resourcemanager.projects.getIamPolicy, resourcemanager.projects.setIamPolicy |
tag | Delete the tag, unless another router lists it | resourcemanager.tagKeys.get, resourcemanager.tagKeys.delete, resourcemanager.tagValues.get, resourcemanager.tagValues.delete |
serviceAccount | Delete the service account | iam.serviceAccounts.get, iam.serviceAccounts.delete |
roles | Delete the custom roles, unless another router lists them | iam.roles.get, iam.roles.delete |
dormeto gcp workloads list
Also show, nap and wake: they call the router's controller with your identity token.
| Step | What for | Permissions |
|---|---|---|
invoke | Call the router's controller | run.routes.invoke |
dormeto gcp workloads onboard
| Step | What for | Permissions |
|---|---|---|
invoke | Call the router's controller | run.routes.invoke |
tag | Bind the tag to the workload's VMs and groups | resourcemanager.tagValues.get, resourcemanager.tagValueBindings.create, resourcemanager.tagValueBindings.delete, compute.instances.listTagBindings, compute.instances.createTagBinding, compute.instances.deleteTagBinding, compute.instanceGroupManagers.listTagBindings, compute.instanceGroupManagers.createTagBinding, compute.instanceGroupManagers.deleteTagBinding |
dormeto gcp workloads offboard
| Step | What for | Permissions |
|---|---|---|
invoke | Call the router's controller | run.routes.invoke |
tag | Remove the tag bindings | resourcemanager.tagValues.get, resourcemanager.tagValueBindings.delete, compute.instances.listTagBindings, compute.instances.deleteTagBinding, compute.instanceGroupManagers.listTagBindings, compute.instanceGroupManagers.deleteTagBinding |
A custom role for a narrower operator
If roles/owner is too much, create a role with the permissions of the commands this operator runs. This one holds every permission of the tables above:
title: Dormeto operator
description: Runs dormeto gcp in this project
stage: GA
includedPermissions:
- artifactregistry.dockerimages.get
- artifactregistry.repositories.downloadArtifacts
- artifactregistry.repositories.get
- cloudscheduler.jobs.create
- cloudscheduler.jobs.delete
- cloudscheduler.jobs.get
- cloudscheduler.jobs.update
- cloudtasks.queues.create
- cloudtasks.queues.delete
- cloudtasks.queues.get
- cloudtasks.queues.getIamPolicy
- cloudtasks.queues.setIamPolicy
- cloudtasks.queues.update
- compute.instanceGroupManagers.createTagBinding
- compute.instanceGroupManagers.deleteTagBinding
- compute.instanceGroupManagers.listTagBindings
- compute.instances.createTagBinding
- compute.instances.deleteTagBinding
- compute.instances.listTagBindings
- compute.regionNetworkEndpointGroups.create
- compute.regionNetworkEndpointGroups.delete
- compute.regionNetworkEndpointGroups.get
- compute.regionOperations.get
- datastore.databases.create
- datastore.databases.delete
- datastore.databases.get
- datastore.databases.list
- datastore.entities.create
- datastore.entities.get
- datastore.entities.list
- datastore.entities.update
- datastore.operations.get
- iam.roles.create
- iam.roles.delete
- iam.roles.get
- iam.roles.undelete
- iam.roles.update
- iam.serviceAccounts.actAs
- iam.serviceAccounts.create
- iam.serviceAccounts.delete
- iam.serviceAccounts.get
- iam.serviceAccounts.getIamPolicy
- iam.serviceAccounts.setIamPolicy
- resourcemanager.projects.get
- resourcemanager.projects.getIamPolicy
- resourcemanager.projects.setIamPolicy
- resourcemanager.tagKeys.create
- resourcemanager.tagKeys.delete
- resourcemanager.tagKeys.get
- resourcemanager.tagValueBindings.create
- resourcemanager.tagValueBindings.delete
- resourcemanager.tagValues.create
- resourcemanager.tagValues.delete
- resourcemanager.tagValues.get
- run.operations.get
- run.routes.invoke
- run.services.create
- run.services.delete
- run.services.get
- run.services.getIamPolicy
- run.services.setIamPolicy
- run.services.update
- serviceusage.operations.get
- serviceusage.services.enable
- serviceusage.services.list
- serviceusage.services.use
gcloud iam roles create dormetoOperator --project=my-project --file=operator-role.yaml
gcloud projects add-iam-policy-binding my-project \
--member="user:you@example.com" --role="projects/my-project/roles/dormetoOperator"
Drop the permissions of the commands you do not give, and check the result with dormeto gcp check, which lists what is missing for each command. Note that resourcemanager.projects.setIamPolicy lets its holder grant themselves any role in the project. Give this role for the time of the install and take it back after. Or keep it for the few people who run it.
Google lists three of these permissions as TESTING in custom roles, like compute.urlMaps.*: cloudtasks.queues.getIamPolicy, cloudtasks.queues.setIamPolicy and serviceusage.operations.get. They are usable and none is refused.
Optional access
From router 0.35.0 and CLI 0.8.0. Turning on the Cloud SQL or GKE API makes Google add its own service agents. A project that uses neither should not get them. So you ask for each by name:
dormeto gcp install --with cloud-sql,gke
The install record keeps your choice. A later run with more adds to it. A run without --with keeps what is there. Only uninstall removes a feature. dormeto gcp check tests a feature only when --with names it or the record has it. The CLI's next run prints any binding Google added.
cloud-sql
Never run against Google yet. A companion database that a nap stops and a wake starts. API: sqladmin.googleapis.com.
| Role | Permissions | Where | Condition |
|---|---|---|---|
dormetoRouterDatabasesReadprojects/{project}/roles/dormetoRouterDatabasesRead | cloudsql.instances.get, cloudsql.instances.list | The project | None |
dormetoRouterDatabasesprojects/{project}/roles/dormetoRouterDatabases | cloudsql.instances.update | The project | Dormeto-managed resources: resource.matchTag('{project}/dormeto', 'managed') |
| Command | Step | Permissions |
|---|---|---|
gcp workloads onboard | tag | cloudsql.instances.get, cloudsql.instances.listTagBindings, cloudsql.instances.createTagBinding, cloudsql.instances.deleteTagBinding, datastore.entities.get |
gcp workloads offboard | tag | cloudsql.instances.get, cloudsql.instances.listTagBindings, cloudsql.instances.deleteTagBinding |
gke
Never run against Google yet. Pods behind standalone network endpoint groups, on a load balancer you own. API: container.googleapis.com.
| Role | Permissions | Where | Condition |
|---|---|---|---|
dormetoRouterKubernetesprojects/{project}/roles/dormetoRouterKubernetes | container.clusters.get, container.clusters.connect | The project | None |
The role grants nothing inside the cluster. When you onboard a workload, the CLI reads the cluster as you. It then prints, asks and applies a Role and a RoleBinding named dormeto-<workload>, in the workload's namespace, for the router's service account. Nothing is cluster-wide, and offboarding removes both. The rules:
getondeployments,statefulsets.listonreplicasets.patchondeployments/scale,statefulsets/scale.listonpods,events.list,patchonscaledobjects.
Kubernetes lets you grant only what you hold, so the operator needs container.roles.escalate and container.roles.bind. Google lists container.roles.escalate as TESTING in custom roles.
| Command | Step | Permissions |
|---|---|---|
gcp workloads onboard | cluster | container.clusters.get, container.roles.create, container.roles.update, container.roleBindings.create, container.roleBindings.update, container.services.get, container.roles.escalate, container.roles.bind, container.clusters.connect, container.replicaSets.list, container.pods.list, container.roles.get, container.roleBindings.get, container.roles.delete, container.roleBindings.delete, datastore.databases.get, datastore.entities.get, datastore.entities.update |
gcp workloads offboard | cluster | container.roles.delete, container.roleBindings.delete, container.roleBindings.update, container.roles.bind, container.clusters.connect, container.clusters.get, container.roles.get, container.roleBindings.get, datastore.databases.get, datastore.entities.get, datastore.entities.update |
IP lists
From router 0.35.0. With --ip-list name=<n>,url=<u>[,refresh=<hours>], repeatable, a visit from an address on the list never wakes a workload. An API client's POST /_dormeto/wake still does. --no-ip-lists clears them. They need no extra role. A list's URL, query string included, is printed and stored in the plan, the install record and the services' environment. Keep tokens out of it. A URL with credentials is refused.
If Terraform writes your load balancer and VMs
Terraform doesn't know what the router writes, so every plan offers to undo it. After such an apply, the router's check repairs the URL map within 5 minutes. Until then, a sleeping workload shows the load balancer's own error page and doesn't wake from a browser. Ignore these fields on the resources you wrote, with lifecycle { ignore_changes = [...] }:
| Resource | Fields | Why |
|---|---|---|
google_compute_url_map | host_rule, path_matcher | The route /_dormeto/*, the nap's custom error response policy and, when the map's own default names the service, a host rule and a path matcher. |
google_compute_instance_group_manager, google_compute_region_instance_group_manager | target_size, target_stopped_size, target_suspended_size | A nap moves the group's VMs from its target size to its stopped or suspended size. An apply would move them back, and could create new VMs. |
google_compute_autoscaler, google_compute_region_autoscaler | autoscaling_policy[0].mode | A nap turns the autoscaler off, and a wake turns it back on. |
google_compute_instance | desired_status | Only if you set it: an apply would start a napped VM. |
google_compute_region_url_map, and a classic load balancer's google_compute_url_map | default_service, default_route_action, host_rule, path_matcher | From router 0.35.0: a nap swaps the map's references to the waker. |
google_sql_database_instance | settings[0].activation_policy | From router 0.35.0, a Cloud SQL companion: a nap sets it to NEVER, a wake to ALWAYS. |
kubernetes_deployment_v1, kubernetes_stateful_set_v1 | spec[0].replicas | From router 0.35.0, GKE: a nap scales the workload to 0. |
With the path matchers ignored, Terraform stops applying your own edits to them. Remove the ignore for that apply. That also removes what the router wrote until its check writes it back. The tag's binding is not a field of these resources, so it needs nothing.
Check
dormeto gcp check is read-only. For each command it prints a tick when you hold every permission it needs, and a cross with the missing ones otherwise. It then prints the project's parent, the APIs already on, and the warnings (the default service account's Editor). It exits 1 when a command lacks a permission. With no role in the project it says so and lists every permission as missing. --json prints the report.
dormeto gcp check --project my-project --region europe-west1
dormeto gcp status shows the router's record and live state: version, services, controller health, queue, job, database and grants.
Remove
dormeto gcp uninstall removes exactly what the install added, in reverse order, from its record. It refuses while workloads are onboarded. --force offboards each one first, tag bindings included. It keeps the custom roles and the tag while another router of the project lists them. It turns no API off. It lists the APIs and Google's bindings as left in place.
dormeto gcp uninstall --project my-project --region europe-west1
dormeto gcp uninstall --project my-project --region europe-west1 --force # workloads still onboarded
Then, if nothing else in the project needs them, turn the APIs off yourself, and remove the default service account's Editor as above:
gcloud services disable \
compute.googleapis.com \
run.googleapis.com \
firestore.googleapis.com \
cloudtasks.googleapis.com \
cloudscheduler.googleapis.com \
monitoring.googleapis.com \
artifactregistry.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
logging.googleapis.com \
--project my-project
Google may refuse to turn an API off while another service depends on it, or ask for --force. Decide for each one: these APIs may serve other things in the project.
A deleted queue's name stays blocked for up to 3 days and a deleted database's ID for about 5 minutes. Installing again before then fails, and the CLI says so.