From b6d03b686afb033bae1fddd9b84e2a4fde012615 Mon Sep 17 00:00:00 2001 From: leet-c1 <264029741+leet-c1@users.noreply.github.com> Date: Fri, 14 Aug 2026 18:00:51 +0000 Subject: [PATCH 1/3] docs(google-cloud-platform): fix org-level role grant instructions The service account creation step told users to "assign the service account a role at the organization level" from the wizard's "Grant this service account access to a project" panel. That panel can only grant project-level roles, so users granted Editor on the project and the first sync failed with a 403 on resourcemanager.organizations.get. - Split the grant into its own "Grant organization-level access" section performed after the service account exists, with the resource picker set to the organization - Note that granting at the organization requires Organization Administrator, not project Owner - Add gcloud equivalents for creating the custom role, binding it at the organization, and verifying the binding - Add a troubleshooting entry for the IAM_PERMISSION_DENIED error, including the case where the configured organization ID is wrong Co-Authored-By: Claude Opus 5 --- baton/google-cloud-platform.mdx | 78 +++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/baton/google-cloud-platform.mdx b/baton/google-cloud-platform.mdx index 118159c5..5792c47c 100644 --- a/baton/google-cloud-platform.mdx +++ b/baton/google-cloud-platform.mdx @@ -126,7 +126,29 @@ Click **CREATE AND CONTINUE**. -Under **Grant this service account access to a project**, assign the service account a role at the organization level. You can use the predefined **Editor** role, or create a custom role that includes only the permissions listed below. +Under **Grant this service account access to a project**, click **CONTINUE** without selecting a role. + + +This step grants roles on the **project** only. The connector reads your organization, folders, and projects, so it needs a role granted at the **organization** level instead. Granting **Editor** here does not work. You'll grant the role at the organization in [Grant organization-level access](#grant-organization-level-access). + + + +Leave **Grant users access to this service account** blank. + + +Click **DONE**. + + + +### Grant organization-level access + +The connector calls Cloud Resource Manager against your organization, so the service account needs a role bound at the **organization** node. A role bound to the project is not enough, no matter how broad it is. + + +Granting roles at the organization level requires the **Organization Administrator** role (`roles/resourcemanager.organizationAdmin`). Project Owner is not sufficient. + + +Create a custom role that includes only the permissions the connector uses. For **READ** access (syncing access data only), the role needs these permissions: @@ -163,15 +185,45 @@ secretmanager.secrets.setIamPolicy storage.buckets.setIamPolicy ``` +Create the role and bind it to the service account at the organization: + + + +In the Google Cloud console, open the resource picker at the top of the page and select your **organization**, not a project. -Leave **Grant users access to this service account** blank. +Navigate to **IAM & Admin** > **Roles** and click **CREATE ROLE**. Add the permissions listed above, then click **CREATE**. -Click **DONE**. +Navigate to **IAM & Admin** > **IAM**, confirm the organization is still selected, and click **GRANT ACCESS**. + + +In **New principals**, enter the service account's email address. In **Role**, select the custom role you created, then click **SAVE**. +To do the same from the command line, create the role: + +```bash +gcloud iam roles create c1_gcp_connector --organization=YOUR_ORG_ID --title="C1 GCP Connector" --permissions=cloudasset.assets.analyzeIamPolicy,cloudasset.assets.searchAllIamPolicies,cloudasset.assets.searchAllResources,iam.roles.get,iam.roles.list,resourcemanager.folders.getIamPolicy,resourcemanager.folders.list,resourcemanager.organizations.get,resourcemanager.organizations.getIamPolicy,resourcemanager.projects.get,resourcemanager.projects.getIamPolicy,resourcemanager.projects.list +``` + +Then bind it at the organization: + +```bash +gcloud organizations add-iam-policy-binding YOUR_ORG_ID --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" --role="organizations/YOUR_ORG_ID/roles/c1_gcp_connector" +``` + +To confirm the binding exists: + +```bash +gcloud organizations get-iam-policy YOUR_ORG_ID --flatten="bindings[].members" --filter="bindings.members:YOUR_SERVICE_ACCOUNT_EMAIL" --format="table(bindings.role)" +``` + + +If you sync secrets or buckets, also grant `roles/cloudasset.viewer` at the organization level, as described in [Optional: Sync secrets and buckets](#optional-sync-secrets-and-buckets). + + ### Get credentials @@ -520,3 +572,23 @@ Check that the connector data uploaded correctly. In C1, click **Apps**. On the + +## Troubleshooting + +### The sync fails with a permission denied error on the organization + +**Example error:** + +`c1z-sync: failed getting metadata: google-cloud-platform: Organizations.Get('organizations/000000000000') failed: googleapi: Error 403: Permission 'resourcemanager.organizations.get' denied on resource '//cloudresourcemanager.googleapis.com/organizations/000000000000' (or it may not exist).` + +The error details report `"reason": "IAM_PERMISSION_DENIED"`. + +**Cause:** The service account's role is bound to the project rather than to the organization. Roles granted during service account creation, including **Editor**, apply only to the project and confer no access at the organization node. + +**To resolve this issue:** Grant the connector's custom role at the organization level. See [Grant organization-level access](#grant-organization-level-access). + + +Google returns this same error when the organization doesn't exist, so also confirm the organization ID the connector is configured with is correct. Run `gcloud organizations list` to see the organizations you can access. + + +The Troubleshooter URL included in the error opens Google's Policy Troubleshooter, which shows the principal, permission, and resource that failed. From ca534deefd74abeb7364ba48aa269dd3e11c0862 Mon Sep 17 00:00:00 2001 From: leet-c1 <264029741+leet-c1@users.noreply.github.com> Date: Fri, 14 Aug 2026 18:07:36 +0000 Subject: [PATCH 2/3] docs(google-cloud-platform): add gcloud commands to every setup section Mirror the Google Cloud project setup guide used by the MCP server docs, which pairs each console procedure with its gcloud equivalent. - Add gcloud commands for project creation, API enablement, service account creation, key creation, key listing, and retrieving the numeric unique ID used for domain-wide delegation - Add service ID tables for the required APIs and for the optional secrets and buckets APIs - Add the gcloud binding for roles/cloudasset.viewer at the organization - Document the service account key creation prerequisites: the iam.serviceAccountKeys.create permission, the Service Account Key Admin role, and the iam.disableServiceAccountKeyCreation policy that is enforced by default for organizations created on or after May 3, 2024 - Reformat the organization-level role commands to multi-line style - Note that domain-wide delegation, the customer ID, and the primary domain have no gcloud equivalent and must be done in the Admin console Co-Authored-By: Claude Opus 5 --- baton/google-cloud-platform.mdx | 137 ++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 7 deletions(-) diff --git a/baton/google-cloud-platform.mdx b/baton/google-cloud-platform.mdx index 5792c47c..df8cbee4 100644 --- a/baton/google-cloud-platform.mdx +++ b/baton/google-cloud-platform.mdx @@ -50,6 +50,8 @@ Configuring the connector requires credentials from both Google Cloud Platform a We recommend creating a dedicated GCP project for the C1 integration. This keeps the integration's permissions and audit logs isolated from your other projects. +Each section below gives the Google Cloud console steps and the equivalent `gcloud` commands. Use whichever you prefer. To use the CLI, [install the gcloud CLI](https://cloud.google.com/sdk/docs/install) and run `gcloud auth login` first. + As a Google Cloud Platform with Google Workspace Super Admin, sign in to [https://console.cloud.google.com](https://console.cloud.google.com/). @@ -69,8 +71,35 @@ After the project is created, make sure the correct project is selected in the d +From the command line: + +```bash +gcloud projects create YOUR_PROJECT_ID \ + --name="C1 Integration" \ + --organization=YOUR_ORG_ID +``` + +```bash +gcloud config set project YOUR_PROJECT_ID +``` + +To find your organization ID: + +```bash +gcloud organizations list +``` + ### Enable the APIs +The connector requires these four APIs. The service ID is the identifier you use with the `gcloud` CLI. + +| API | Service ID | Used for | +| :--- | :--- | :--- | +| Cloud Asset API | `cloudasset.googleapis.com` | Searching resources and IAM policies across the organization | +| Cloud Resource Manager API | `cloudresourcemanager.googleapis.com` | Reading organizations, folders, and projects | +| Identity and Access Management API | `iam.googleapis.com` | Reading roles and service accounts | +| Admin SDK API | `admin.googleapis.com` | Reading Google Workspace users, groups, and roles through domain-wide delegation | + In the navigation menu, navigate to **APIs & Services** > **Library**. @@ -86,6 +115,23 @@ Search for each of the following APIs and click **Enable**: +From the command line: + +```bash +gcloud services enable \ + cloudasset.googleapis.com \ + cloudresourcemanager.googleapis.com \ + iam.googleapis.com \ + admin.googleapis.com \ + --project=YOUR_PROJECT_ID +``` + +To confirm which APIs are enabled on the project: + +```bash +gcloud services list --enabled --project=YOUR_PROJECT_ID +``` + ### Optional: Sync secrets and buckets Complete this section only if you want the connector to sync secrets (API keys, service account keys, Secret Manager secrets) or Cloud Storage buckets. @@ -98,14 +144,33 @@ Secrets and bucket permissions are configured per project in GCP. If the connect Grant the service account the `roles/cloudasset.viewer` role at the organization level. This allows it to search resources across projects. +```bash +gcloud organizations add-iam-policy-binding YOUR_ORG_ID \ + --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" \ + --role="roles/cloudasset.viewer" +``` + **Additional APIs to enable:** Enable these APIs for each project you want to sync (or only for the projects specified in the **Project IDs** filter): -* Secrets - API Keys: **API Keys API** -* Secrets - Service account keys: **IAM API** -* Secrets - Secret Manager secrets: **Secret Manager API** -* Buckets: **Cloud Storage API** +| Resource | API | Service ID | +| :--- | :--- | :--- | +| Secrets - API keys | API Keys API | `apikeys.googleapis.com` | +| Secrets - Service account keys | IAM API | `iam.googleapis.com` | +| Secrets - Secret Manager secrets | Secret Manager API | `secretmanager.googleapis.com` | +| Buckets | Cloud Storage API | `storage.googleapis.com` | + +```bash +gcloud services enable \ + apikeys.googleapis.com \ + iam.googleapis.com \ + secretmanager.googleapis.com \ + storage.googleapis.com \ + --project=YOUR_PROJECT_ID +``` + +Repeat for each project you want to sync, changing `--project` each time. ### Create a service account @@ -140,6 +205,17 @@ Click **DONE**. +From the command line: + +```bash +gcloud iam service-accounts create c1-integration \ + --project=YOUR_PROJECT_ID \ + --display-name="C1 Integration" \ + --description="Service account for C1 Google Cloud Platform with Google Workspace Integration" +``` + +The service account's email address follows the pattern `c1-integration@YOUR_PROJECT_ID.iam.gserviceaccount.com`. Use it wherever `YOUR_SERVICE_ACCOUNT_EMAIL` appears below. + ### Grant organization-level access The connector calls Cloud Resource Manager against your organization, so the service account needs a role bound at the **organization** node. A role bound to the project is not enough, no matter how broad it is. @@ -205,19 +281,27 @@ In **New principals**, enter the service account's email address. In **Role**, s To do the same from the command line, create the role: ```bash -gcloud iam roles create c1_gcp_connector --organization=YOUR_ORG_ID --title="C1 GCP Connector" --permissions=cloudasset.assets.analyzeIamPolicy,cloudasset.assets.searchAllIamPolicies,cloudasset.assets.searchAllResources,iam.roles.get,iam.roles.list,resourcemanager.folders.getIamPolicy,resourcemanager.folders.list,resourcemanager.organizations.get,resourcemanager.organizations.getIamPolicy,resourcemanager.projects.get,resourcemanager.projects.getIamPolicy,resourcemanager.projects.list +gcloud iam roles create c1_gcp_connector \ + --organization=YOUR_ORG_ID \ + --title="C1 GCP Connector" \ + --permissions=cloudasset.assets.analyzeIamPolicy,cloudasset.assets.searchAllIamPolicies,cloudasset.assets.searchAllResources,iam.roles.get,iam.roles.list,resourcemanager.folders.getIamPolicy,resourcemanager.folders.list,resourcemanager.organizations.get,resourcemanager.organizations.getIamPolicy,resourcemanager.projects.get,resourcemanager.projects.getIamPolicy,resourcemanager.projects.list ``` Then bind it at the organization: ```bash -gcloud organizations add-iam-policy-binding YOUR_ORG_ID --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" --role="organizations/YOUR_ORG_ID/roles/c1_gcp_connector" +gcloud organizations add-iam-policy-binding YOUR_ORG_ID \ + --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" \ + --role="organizations/YOUR_ORG_ID/roles/c1_gcp_connector" ``` To confirm the binding exists: ```bash -gcloud organizations get-iam-policy YOUR_ORG_ID --flatten="bindings[].members" --filter="bindings.members:YOUR_SERVICE_ACCOUNT_EMAIL" --format="table(bindings.role)" +gcloud organizations get-iam-policy YOUR_ORG_ID \ + --flatten="bindings[].members" \ + --filter="bindings.members:YOUR_SERVICE_ACCOUNT_EMAIL" \ + --format="table(bindings.role)" ``` @@ -247,10 +331,49 @@ Keep the downloaded file safe — you'll upload it when configuring the connecto +From the command line, create the JSON key: + +```bash +gcloud iam service-accounts keys create c1-credentials.json \ + --iam-account=YOUR_SERVICE_ACCOUNT_EMAIL +``` + +Retrieve the numeric unique ID you'll use for domain-wide delegation: + +```bash +gcloud iam service-accounts describe YOUR_SERVICE_ACCOUNT_EMAIL \ + --format='value(uniqueId)' +``` + +To review the keys that exist on the service account: + +```bash +gcloud iam service-accounts keys list \ + --iam-account=YOUR_SERVICE_ACCOUNT_EMAIL +``` + + +**If key creation fails,** your organization blocks it. Creating a key requires the `iam.serviceAccountKeys.create` permission, granted by the **Service Account Key Admin** role (`roles/iam.serviceAccountKeyAdmin`), and the `constraints/iam.disableServiceAccountKeyCreation` organization policy must not be enforced on the project. Google enforces that policy by default for organizations created on or after May 3, 2024, and key creation then fails with `FAILED_PRECONDITION: Key creation is not allowed on this service account`. + +Check whether the policy applies to your project: + +```bash +gcloud org-policies describe iam.disableServiceAccountKeyCreation \ + --project=YOUR_PROJECT_ID \ + --effective +``` + +A user with the **Organization Policy Administrator** role (`roles/orgpolicy.policyAdmin`) can add a project-level exception. See Google's [organization policy constraints for service accounts](https://cloud.google.com/resource-manager/docs/organization-policy/restricting-service-accounts). + + ### Add the service account to Google Workspace Domain-wide delegation allows the GCP service account to access Google Workspace data — directory users, groups, roles, and audit logs — on behalf of your organization. You configure this in the Google Workspace Admin console at [https://admin.google.com](https://admin.google.com), which is separate from the Google Cloud console. + +The remaining steps have no `gcloud` equivalent. Domain-wide delegation, the customer ID, and the primary domain all live in Google Workspace rather than Google Cloud, so you must complete them in the Admin console. + + Go to [https://admin.google.com](https://admin.google.com) as a **SUPER ADMIN**. From 59aff944d453bd56a8ecfc49b673ab700a47dfa8 Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Fri, 14 Aug 2026 12:52:26 -0700 Subject: [PATCH 3/3] docs: apply style guide fixes Co-Authored-By: Claude Sonnet 5 --- baton/google-cloud-platform.mdx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/baton/google-cloud-platform.mdx b/baton/google-cloud-platform.mdx index df8cbee4..f1892e28 100644 --- a/baton/google-cloud-platform.mdx +++ b/baton/google-cloud-platform.mdx @@ -174,6 +174,8 @@ Repeat for each project you want to sync, changing `--project` each time. ### Create a service account +Create the service account C1 will authenticate as. + In the navigation menu, navigate to **APIs & Services** > **Credentials**. @@ -268,7 +270,10 @@ Create the role and bind it to the service account at the organization: In the Google Cloud console, open the resource picker at the top of the page and select your **organization**, not a project. -Navigate to **IAM & Admin** > **Roles** and click **CREATE ROLE**. Add the permissions listed above, then click **CREATE**. +Navigate to **IAM & Admin** > **Roles** and click **CREATE ROLE**. + + +Add the permissions listed above, then click **CREATE**. Navigate to **IAM & Admin** > **IAM**, confirm the organization is still selected, and click **GRANT ACCESS**. @@ -310,6 +315,8 @@ If you sync secrets or buckets, also grant `roles/cloudasset.viewer` at the orga ### Get credentials +Download the service account's JSON key and record its unique ID. + Navigate back to **APIs & Services** > **Credentials**. Under **Service Accounts**, locate and click the service account you just created.