1"use strict";(globalThis.webpackChunkorbisid_docs=globalThis.webpackChunkorbisid_docs||[]).push([[4135],{12(e,r,n){n.r(r),n.d(r,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>d,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"target-systems/google-cloud-platform","title":"Google Cloud Platform (GCP)","description":"Description","source":"@site/docs/target-systems/google-cloud-platform.md","sourceDirName":"target-systems","slug":"/target-systems/google-cloud-platform","permalink":"/docs/target-systems/google-cloud-platform","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":20,"frontMatter":{"sidebar_position":20,"title":"Google Cloud Platform (GCP)"},"sidebar":"mainSidebar","previous":{"title":"GitHub Enterprise Server","permalink":"/docs/target-systems/github-enterprise"},"next":{"title":"Google Workspace","permalink":"/docs/target-systems/google-workspace"}}');var s=n(4848),t=n(8453);const d={sidebar_position:20,title:"Google Cloud Platform (GCP)"},l="Google Cloud Platform (GCP)",c={},o=[{value:"Description",id:"description",level:2},{value:"System Type Classification",id:"system-type-classification",level:2},{value:"Version Support",id:"version-support",level:2},{value:"Supported Protocol",id:"supported-protocol",level:2},{value:"What OrbisID Discovers",id:"what-orbisid-discovers",level:2},{value:"Privileged Roles Detected",id:"privileged-roles-detected",level:3},{value:"Connection Requirements",id:"connection-requirements",level:2},{value:"GCP Service Account",id:"gcp-service-account",level:3},{value:"Credential Mapping",id:"credential-mapping",level:3},{value:"System Attributes",id:"system-attributes",level:3},{value:"Network Requirements",id:"network-requirements",level:3},{value:"Configuration Steps",id:"configuration-steps",level:2},{value:"Real-Time Account & Entitlement Events",id:"real-time-account--entitlement-events",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2}];function a(e){const r={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(r.header,{children:(0,s.jsx)(r.h1,{id:"google-cloud-platform-gcp",children:"Google Cloud Platform (GCP)"})}),"\n",(0,s.jsx)(r.h2,{id:"description",children:"Description"}),"\n",(0,s.jsxs)(r.p,{children:["The Google Cloud Platform connector recursively discovers and scans IAM policy bindings across an ",(0,s.jsx)(r.strong,{children:"entire Google Cloud organization"})," \u2014 the organization itself, every folder and sub-folder beneath it, and every project under any of those folders (or directly under the org) \u2014 plus the IAM service accounts within each discovered project. It authenticates using a ",(0,s.jsx)(r.strong,{children:"service account"})," with a private key via the OAuth 2.0 JWT bearer flow \u2014 no GCP SDK installation is required on the OrbisID server."]}),"\n",(0,s.jsx)(r.p,{children:'This connector replaces the earlier separate "GCP" (single-project) and "Google Cloud IAM" (org-level only, no project drill-down) connectors, which left a gap: neither one alone gave full visibility into an organization\'s access without manually adding a system per project.'}),"\n",(0,s.jsx)(r.h2,{id:"system-type-classification",children:"System Type Classification"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Field"}),(0,s.jsx)(r.th,{children:"Value"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"System Type"})}),(0,s.jsx)(r.td,{children:"Infrastructure"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"Default Scan Priority"})}),(0,s.jsx)(r.td,{children:"500"})]})]})]}),"\n",(0,s.jsx)(r.h2,{id:"version-support",children:"Version Support"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"OrbisID Edition"}),(0,s.jsx)(r.th,{style:{textAlign:"center"},children:"Supported"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Community"}),(0,s.jsx)(r.td,{style:{textAlign:"center"},children:"No"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Pro"}),(0,s.jsx)(r.td,{style:{textAlign:"center"},children:"Yes"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Enterprise"}),(0,s.jsx)(r.td,{style:{textAlign:"center"},children:"Yes"})]})]})]}),"\n",(0,s.jsxs)(r.p,{children:["Google Cloud Platform scanning requires a ",(0,s.jsx)(r.strong,{children:"Pro"})," or ",(0,s.jsx)(r.strong,{children:"Enterprise"})," licence."]}),"\n",(0,s.jsx)(r.h2,{id:"supported-protocol",children:"Supported Protocol"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Protocol"}),(0,s.jsx)(r.th,{style:{textAlign:"center"},children:"Port"}),(0,s.jsx)(r.th,{children:"Notes"})]})}),(0,s.jsx)(r.tbody,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Google Cloud REST API (HTTPS + OAuth 2.0 JWT)"}),(0,s.jsx)(r.td,{style:{textAlign:"center"},children:"443 TCP"}),(0,s.jsx)(r.td,{children:"Cloud Resource Manager and IAM endpoints"})]})})]}),"\n",(0,s.jsx)(r.h2,{id:"what-orbisid-discovers",children:"What OrbisID Discovers"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Data"}),(0,s.jsx)(r.th,{children:"Source"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Organization IAM policy bindings"}),(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"POST /v3/organizations/{orgId}:getIamPolicy"})})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Every folder and sub-folder under the organization"}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"GET /v3/folders?parent=organizations/{orgId}"})," (recursive)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Folder IAM policy bindings"}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"POST /v3/folders/{folderId}:getIamPolicy"})," (per folder)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Every project under the org or any folder"}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"GET /v3/projects?parent=..."})," (recursive)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Project IAM policy bindings"}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"POST /v1/projects/{projectId}:getIamPolicy"})," (per project)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Service accounts per project"}),(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"GET /v1/projects/{projectId}/serviceAccounts"})})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"IAM members by type"}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"user:"}),", ",(0,s.jsx)(r.code,{children:"serviceAccount:"}),", ",(0,s.jsx)(r.code,{children:"group:"}),", ",(0,s.jsx)(r.code,{children:"domain:"})," prefixes extracted from bindings at every level"]})]})]})]}),"\n",(0,s.jsx)(r.h3,{id:"privileged-roles-detected",children:"Privileged Roles Detected"}),"\n",(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.code,{children:"roles/owner"}),", ",(0,s.jsx)(r.code,{children:"roles/editor"}),", ",(0,s.jsx)(r.code,{children:"roles/iam.securityAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/iam.roleAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/resourcemanager.organizationAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/resourcemanager.folderAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/resourcemanager.projectIamAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/iam.serviceAccountAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/iam.serviceAccountTokenCreator"}),", ",(0,s.jsx)(r.code,{children:"roles/iam.serviceAccountKeyAdmin"}),", ",(0,s.jsx)(r.code,{children:"roles/billing.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/compute.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/storage.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/bigquery.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/cloudsql.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/container.admin"}),", ",(0,s.jsx)(r.code,{children:"roles/orgpolicy.policyAdmin"})]}),"\n",(0,s.jsx)(r.h2,{id:"connection-requirements",children:"Connection Requirements"}),"\n",(0,s.jsx)(r.h3,{id:"gcp-service-account",children:"GCP Service Account"}),"\n",(0,s.jsxs)(r.p,{children:["Create a dedicated service account and grant it ",(0,s.jsx)(r.strong,{children:"organization-level"})," IAM read access \u2014 this single grant covers discovery at every level (org, folders, projects) since IAM read permissions granted at the organization are inherited down the resource hierarchy."]}),"\n",(0,s.jsx)(r.p,{children:(0,s.jsx)(r.strong,{children:"Required IAM permissions at the organization level:"})}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Permission"}),(0,s.jsx)(r.th,{children:"Purpose"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"resourcemanager.organizations.getIamPolicy"})}),(0,s.jsx)(r.td,{children:"Read the organization IAM policy"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"resourcemanager.folders.list"})}),(0,s.jsx)(r.td,{children:"Enumerate folders and sub-folders"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"resourcemanager.folders.getIamPolicy"})}),(0,s.jsx)(r.td,{children:"Read IAM policies on folders"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"resourcemanager.projects.list"})}),(0,s.jsx)(r.td,{children:"Enumerate projects under the org and each folder"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"resourcemanager.projects.getIamPolicy"})}),(0,s.jsx)(r.td,{children:"Read IAM policies on projects"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"iam.serviceAccounts.list"})}),(0,s.jsx)(r.td,{children:"List service accounts within each project"})]})]})]}),"\n",(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.strong,{children:"Recommended role:"})," ",(0,s.jsx)(r.code,{children:"roles/iam.securityReviewer"})," at the organization level \u2014 it includes all of the permissions above."]}),"\n",(0,s.jsx)(r.p,{children:(0,s.jsx)(r.strong,{children:"Steps to create the service account:"})}),"\n",(0,s.jsxs)(r.ol,{children:["\n",(0,s.jsxs)(r.li,{children:["In the ",(0,s.jsx)(r.strong,{children:"GCP Console"}),", navigate to ",(0,s.jsx)(r.strong,{children:"APIs & Services \u2192 Library"})," on the service account's own project, and ",(0,s.jsx)(r.strong,{children:"Enable"})," both the ",(0,s.jsx)(r.strong,{children:"Cloud Resource Manager API"})," and the ",(0,s.jsx)(r.strong,{children:"IAM API"}),". This is required independently of the organization-level role grant below \u2014 without it, every call (including folder/project discovery) fails with ",(0,s.jsx)(r.code,{children:"403: ... API has not been used in project ... or it is disabled"}),"."]}),"\n",(0,s.jsxs)(r.li,{children:["Navigate to ",(0,s.jsx)(r.strong,{children:"IAM & Admin \u2192 Service Accounts"})]}),"\n",(0,s.jsxs)(r.li,{children:["Click ",(0,s.jsx)(r.strong,{children:"Create Service Account"})," \u2014 name it (e.g., ",(0,s.jsx)(r.code,{children:"orbisid-org-scanner"}),")"]}),"\n",(0,s.jsxs)(r.li,{children:["At the ",(0,s.jsx)(r.strong,{children:"Organization"})," level in IAM (not the project level), grant this service account the ",(0,s.jsx)(r.code,{children:"Security Reviewer"})," role"]}),"\n",(0,s.jsxs)(r.li,{children:["Under the service account, click ",(0,s.jsx)(r.strong,{children:"Manage Keys \u2192 Add Key \u2192 Create new key \u2192 JSON"})]}),"\n",(0,s.jsxs)(r.li,{children:["Download the JSON key file \u2014 extract the ",(0,s.jsx)(r.code,{children:"private_key"})," and ",(0,s.jsx)(r.code,{children:"private_key_id"})," fields"]}),"\n"]}),"\n",(0,s.jsx)(r.h3,{id:"credential-mapping",children:"Credential Mapping"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"OrbisID Field"}),(0,s.jsx)(r.th,{children:"GCP Value"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"credential.username"})}),(0,s.jsxs)(r.td,{children:["Service account email (e.g., ",(0,s.jsx)(r.code,{children:"[email protected]"}),")"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"credential.privateKey"})}),(0,s.jsxs)(r.td,{children:["Service account private key (PEM format \u2014 the ",(0,s.jsx)(r.code,{children:"private_key"})," field from the JSON key file)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"credential.domain"})}),(0,s.jsxs)(r.td,{children:["Private key ID (the ",(0,s.jsx)(r.code,{children:"private_key_id"})," field from the JSON key file, optional)"]})]})]})]}),"\n",(0,s.jsx)(r.admonition,{title:"Use the Private Key field, not Password",type:"info",children:(0,s.jsxs)(r.p,{children:["The PEM key goes in the Credential form's ",(0,s.jsx)(r.strong,{children:"Private Key"})," field (a multi-line box \u2014 the same\none used for Linux SSH keys), not ",(0,s.jsx)(r.strong,{children:"Password"}
1),". Password renders as a single-line masked input,\nwhich silently strips line breaks out of anything multi-line pasted into it; Private Key is a\nplain multi-line textarea, so the key's line structure survives."]})}),"\n",(0,s.jsxs)(r.admonition,{title:"Pasting the private_key value from the JSON file",type:"tip",children:[(0,s.jsxs)(r.p,{children:["Opened as plain text, the downloaded JSON key file's ",(0,s.jsx)(r.code,{children:"private_key"})," value looks like this:"]}),(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{children:'"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQ...\\n-----END PRIVATE KEY-----\\n"\n'})}),(0,s.jsxs)(r.p,{children:["Those ",(0,s.jsx)(r.code,{children:"\\n"})," are ",(0,s.jsx)(r.strong,{children:"literal backslash-n characters"})," \u2014 how JSON encodes a line break in a string \u2014\nnot actual line breaks. Pasting that text as-is into the Private Key field used to fail with an\nopaque ",(0,s.jsx)(r.code,{children:"Illegal base64 character 5c"})," error; OrbisID now ",(0,s.jsxs)(r.strong,{children:["automatically converts those literal\n",(0,s.jsx)(r.code,{children:"\\n"})," sequences into real line breaks when the credential is saved"]}),", so pasting the JSON value\nverbatim works either way. If you're instead typing the key out from a JSON-aware viewer/editor\n(which usually renders ",(0,s.jsx)(r.code,{children:"\\n"})," as real line breaks already), that also works unchanged."]})]}),"\n",(0,s.jsx)(r.h3,{id:"system-attributes",children:"System Attributes"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Attribute"}),(0,s.jsx)(r.th,{children:"Required"}),(0,s.jsx)(r.th,{children:"Description"})]})}),(0,s.jsx)(r.tbody,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"googleCloudOrgId"})}),(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"Yes"})}),(0,s.jsxs)(r.td,{children:["The numeric Google Cloud organization ID to scan (e.g., ",(0,s.jsx)(r.code,{children:"123456789012"}),"), found in ",(0,s.jsx)(r.strong,{children:"IAM & Admin \u2192 Settings"})," or via ",(0,s.jsx)(r.code,{children:"gcloud organizations list"})]})]})})]}),"\n",(0,s.jsx)(r.h3,{id:"network-requirements",children:"Network Requirements"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Requirement"}),(0,s.jsx)(r.th,{children:"Detail"})]})}),(0,s.jsx)(r.tbody,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Outbound HTTPS"}),(0,s.jsxs)(r.td,{children:["OrbisID server (or On-Premise Agent) must reach ",(0,s.jsx)(r.code,{children:"oauth2.googleapis.com"}),", ",(0,s.jsx)(r.code,{children:"cloudresourcemanager.googleapis.com"}),", and ",(0,s.jsx)(r.code,{children:"iam.googleapis.com"})," on port 443"]})]})})]}),"\n",(0,s.jsx)(r.h2,{id:"configuration-steps",children:"Configuration Steps"}),"\n",(0,s.jsxs)(r.ol,{children:["\n",(0,s.jsxs)(r.li,{children:["Create the GCP service account and grant ",(0,s.jsx)(r.strong,{children:"Security Reviewer"})," at the ",(0,s.jsx)(r.strong,{children:"organization"})," level"]}),"\n",(0,s.jsxs)(r.li,{children:["Download the JSON key file and extract the ",(0,s.jsx)(r.code,{children:"private_key"})," (PEM) and ",(0,s.jsx)(r.code,{children:"private_key_id"})]}),"\n",(0,s.jsxs)(r.li,{children:["Create a ",(0,s.jsx)(r.strong,{children:"Credential"})," in OrbisID:","\n",(0,s.jsxs)(r.ul,{children:["\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Username:"})," Service account email"]}),"\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Private Key:"})," Private key PEM, including the full ",(0,s.jsx)(r.code,{children:"-----BEGIN PRIVATE KEY-----"})," block\n(paste the JSON file's ",(0,s.jsx)(r.code,{children:"private_key"})," value as-is \u2014 see the tip above)"]}),"\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Domain:"})," Private key ID (optional)"]}),"\n",(0,s.jsxs)(r.li,{children:["Leave ",(0,s.jsx)(r.strong,{children:"Password"})," blank"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(r.li,{children:["Navigate to ",(0,s.jsx)(r.strong,{children:"Systems \u2192 Add System"})]}),"\n",(0,s.jsx)(r.li,{children:"Fill in the fields:"}),"\n"]}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Field"}),(0,s.jsx)(r.th,{children:"Value"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"Name"})}),(0,s.jsxs)(r.td,{children:["Descriptive name (e.g., ",(0,s.jsx)(r.code,{children:"GCP \u2013 my-org"}),")"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"Hostname"})}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"cloudresourcemanager.googleapis.com"})," (used for reference)"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"OS Type"})}),(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"Google Cloud Platform (GCP)"})})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"System Type"})}),(0,s.jsx)(r.td,{children:(0,s.jsx)(r.code,{children:"Infrastru
1cture"})})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:(0,s.jsx)(r.strong,{children:"Credential"})}),(0,s.jsx)(r.td,{children:"The GCP service account credential"})]})]})]}),"\n",(0,s.jsxs)(r.ol,{start:"6",children:["\n",(0,s.jsxs)(r.li,{children:["Set the ",(0,s.jsx)(r.strong,{children:"Google Cloud Organization ID"})," attribute to the numeric organization ID"]}),"\n",(0,s.jsxs)(r.li,{children:["Click ",(0,s.jsx)(r.strong,{children:"Test Connection"})," to verify the service account can obtain a token"]}),"\n",(0,s.jsxs)(r.li,{children:["Click ",(0,s.jsx)(r.strong,{children:"Save"})]}),"\n"]}),"\n",(0,s.jsx)(r.admonition,{title:"Recursive by design",type:"tip",children:(0,s.jsx)(r.p,{children:"One system covers the whole organization \u2014 there is no need to add a separate system per project. The scanner walks every folder and project under the org automatically on each scan."})}),"\n",(0,s.jsx)(r.h2,{id:"real-time-account--entitlement-events",children:"Real-Time Account & Entitlement Events"}),"\n",(0,s.jsxs)(r.p,{children:["Beyond periodic full scans, OrbisID can pull a Pub/Sub subscription (fed by a Cloud Logging sink on Admin Activity audit logs you configure) to detect service account create/delete/enable/disable events near-real-time. See ",(0,s.jsx)(r.a,{href:"../user-guide/realtime-events",children:"Real-Time Events"})," \u2014 Pro/Enterprise only. IAM policy binding (role grant/revoke) changes are not detected this way."]}),"\n",(0,s.jsx)(r.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,s.jsxs)(r.table,{children:[(0,s.jsx)(r.thead,{children:(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.th,{children:"Symptom"}),(0,s.jsx)(r.th,{children:"Likely Cause"}),(0,s.jsx)(r.th,{children:"Resolution"})]})}),(0,s.jsxs)(r.tbody,{children:[(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:'Scan fails: "Google Cloud organization ID is required"'}),(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"googleCloudOrgId"})," attribute not set"]}),(0,s.jsxs)(r.td,{children:["Set the ",(0,s.jsx)(r.strong,{children:"Google Cloud Organization ID"})," attribute on the system"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"401 Unauthorized"})," / token error"]}),(0,s.jsx)(r.td,{children:"Invalid private key PEM or service account email"}),(0,s.jsx)(r.td,{children:"Verify the PEM includes the full key block; ensure the service account email is correct"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:'Scan fails: "private key PEM (credential\'s Private Key field) is required"'}),(0,s.jsxs)(r.td,{children:["The key was pasted into ",(0,s.jsx)(r.strong,{children:"Password"})," instead of ",(0,s.jsx)(r.strong,{children:"Private Key"}),", or left empty"]}),(0,s.jsxs)(r.td,{children:["Move the PEM into the credential's ",(0,s.jsx)(r.strong,{children:"Private Key"})," field"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"Illegal base64 character 5c"})," / \"Private key contains literal '\\n' characters instead of real line breaks\""]}),(0,s.jsxs)(r.td,{children:["A credential saved before this connector auto-normalized the key still has the literal ",(0,s.jsx)(r.code,{children:"\\n"})," escapes baked into its stored value"]}),(0,s.jsxs)(r.td,{children:["Open the credential and click ",(0,s.jsx)(r.strong,{children:"Save"})," again (no changes needed) \u2014 this re-applies the fix. New credentials are normalized automatically on first save"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:'"Private key is not valid Base64..." / "Private key data does not decode as a valid PKCS#8 RSA key"'}),(0,s.jsx)(r.td,{children:"The pasted key was truncated, re-wrapped, or edited"}),(0,s.jsxs)(r.td,{children:["Re-download the JSON key file and paste the ",(0,s.jsx)(r.code,{children:"private_key"})," value again, unmodified, including the full ",(0,s.jsx)(r.code,{children:"-----BEGIN"}),"/",(0,s.jsx)(r.code,{children:"-----END"})," block, into the ",(0,s.jsx)(r.strong,{children:"Private Key"})," field"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"403 PERMISSION_DENIED"})," on org/folder/project policy"]}),(0,s.jsx)(r.td,{children:"Missing IAM permissions at the organization level"}),(0,s.jsxs)(r.td,{children:["Grant ",(0,s.jsx)(r.code,{children:"roles/iam.securityReviewer"})," (or the individual permissions listed above) at the ",(0,s.jsx)(r.strong,{children:"organization"}),", not project, level"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"403"}),' \u2014 "Cloud Resource Manager API has not been used in project ... or it is disabled"']}),(0,s.jsx)(r.td,{children:"Cloud Resource Manager API not enabled on the service account's own GCP project"}),(0,s.jsxs)(r.td,{children:["Visit the URL in the error message (or ",(0,s.jsx)(r.strong,{children:"APIs & Services \u2192 Library"})," in the GCP Console) and click ",(0,s.jsx)(r.strong,{children:"Enable"}),"; wait a minute or two, then retest"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"403"}),' \u2014 "IAM API has not been used in project ... or it is disabled"']}),(0,s.jsx)(r.td,{children:"IAM API not enabled on the service account's own GCP project (blocks service account enumeration)"}),(0,s.jsxs)(r.td,{children:["Enable the ",(0,s.jsx)(r.strong,{children:"IAM API"})," on the same project via ",(0,s.jsx)(r.strong,{children:"APIs & Services \u2192 Library"})]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:['"Service account enumeration skipped" \u2014 ',(0,s.jsx)(r.code,{children:"403 Request had insufficient authentication scopes"})," / ",(0,s.jsx)(r.code,{children:"ACCESS_TOKEN_SCOPE_INSUFFICIENT"})]}),(0,s.jsxs)(r.td,{children:["Fixed in this connector \u2014 earlier versions requested only the ",(0,s.jsx)(r.code,{children:"cloud-platform.read-only"})," OAuth scope, which the IAM API does not accept for ",(0,s.jsx)(r.code,{children:"serviceAccounts.list"})," (unlike the Cloud Resource Manager API)"]}),(0,s.jsxs)(r.td,{children:["Upgrade to the current connector version, which also requests the ",(0,s.jsx)(r.code,{children:"iam"})," scope; no GCP-side configuration change needed"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsxs)(r.td,{children:[(0,s.jsx)(r.code,{children:"invalid_grant"})," error"]}),(0,s.jsx)(r.td,{children:"Private key ID mismatch or key revoked"}),(0,s.jsx)(r.td,{children:"Re-download the JSON key file; verify the key is active in the GCP Console"})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Some projects missing from results"}),(0,s.jsx)(r.td,{children:"Service account lacks org-level inheritance, or a project denies inherited IAM policies"}),(0,s.jsxs)(r.td,{children:["Confirm the role was granted at the ",(0,s.jsx)(r.strong,{children:"organization"})," level; check for IAM deny policies on the affected project"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:"Connection timeout"}),(0,s.jsx)(r.td,{children:"GCP API endpoints blocked"}),(0,s.jsxs)(r.td,{children:["Ensure outbound HTTPS access to ",(0,s.jsx)(r.code,{children:"*.googleapis.com"})," on port 443"]})]}),(0,s.jsxs)(r.tr,{children:[(0,s.jsx)(r.td,{children:'System was migrated from an old "GCP" connector and now fails immediately'}),(0,s.jsx)(r.td,{children:"The old project-only connector never stored an organization ID"}),(0,s.jsxs)(r.td,{children:["Set the ",(0,s.jsx)(r.strong,{children:"Google Cloud Organization ID"})," attribute \u2014 this is a one-time manual step after upgrading"]})]})]})]})]})}function h(e={}){const{wrapper:r}={...(0,t.R)(),...e.components};return r?(0,s.jsx)(r,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453(e,r,n){n.d(r,{R:()=>d,x:()=>l});var i=n(6540);const s={},t=i.createContext(s);function d(e){const r=i.useContext(t);return i.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function l(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:d(e.components),i.createElement(t.Provider,{value:r},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.