# Connect a Google Cloud account

Authorize CISAPP read-only on a Google Cloud (GCP) environment through a service account that CISAPP impersonates, to inventory cloud resources and report security posture findings.

> **Access:** organization administrator. **Beta** feature; the connector must be enabled on your platform.

## How it works

No key is exchanged or stored. You create a **read-only service account** in one of your projects and you allow the **CISAPP platform service account** to **impersonate** it (the "Service Account Token Creator" role, on that service account only). At each synchronization, CISAPP obtains a short-lived access token (about one hour) from Google on behalf of your service account and reads your configuration. This token is never stored: it stays in CISAPP's memory and is reused for at most one hour (refreshed 5 minutes before it expires). Removing the authorization on the Google Cloud side prevents new tokens from being obtained: access ends at the latest when the current token expires (one hour at most), subject to Google IAM propagation. For an immediate stop on the CISAPP side, use **Disconnect**.

## Prerequisites

- Be an organization administrator in CISAPP.
- Have the rights in Google Cloud to create a service account, create a custom role and grant IAM roles: for example IAM Admin on the organization (or on the project), or project owner. Without a Google Cloud organization, these rights are needed on every project to analyze.
- Have the `gcloud` CLI signed in with an authorized account, or Cloud Shell.
- A service account can only be connected to **one** CISAPP organization. Several service accounts (so several connections) remain possible within one CISAPP organization.
- The service account must be **one you created** (`name@project.iam.gserviceaccount.com`). Google-managed accounts (service agents `gcp-sa-…` and legacy Google service agents, the default Compute account `…-compute@developer.gserviceaccount.com`, the App Engine account) and legacy domain-named projects (`example.com:project`) are not supported. It must not belong to CISAPP's own project.

## Set up Google Cloud

The commands below are the ones in the CISAPP setup panel. **The panel shows them already pre-filled** with your connection's verification token and the CISAPP service account address: copy them from the panel rather than using the generic values on this page (`<VERIFICATION_TOKEN>` and `<CISAPP_SERVICE_ACCOUNT>`).

1. Open **My company → Connectors**, then **Connect** on the Google Cloud card. The **Set up Google Cloud** panel shows two values to copy:
   - the **CISAPP service account (platform)**: the address to authorize;
   - the **verification token**: specific to this connection, in the form `cisapp-verify-` followed by 32 hexadecimal characters.

2. **Adapt the variables.** `PROJECT_ID` is the project that will host the service account (its "home project"), `ORG_ID` is the numeric identifier of your organization (not needed without an organization).

   ```bash
   PROJECT_ID="my-project-id"
   SA_NAME="cisapp-readonly"
   SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
   ORG_ID="123456789012"
   ```

3. **Create the service account**, with the verification token as its **description**: it proves that you control this account.

   ```bash
   gcloud iam service-accounts create "$SA_NAME" --project="$PROJECT_ID" \
     --display-name="CISAPP read-only" \
     --description="<VERIFICATION_TOKEN>"
   ```

   If the service account already exists, only update its description:

   ```bash
   gcloud iam service-accounts update "$SA_EMAIL" --project="$PROJECT_ID" \
     --description="<VERIFICATION_TOKEN>"
   ```

4. **Allow CISAPP to impersonate the service account**, **on that service account only**. **Never** grant it on the project, a folder or the organization: CISAPP refuses the connection if this role is granted more widely.

   ```bash
   gcloud iam service-accounts add-iam-policy-binding "$SA_EMAIL" \
     --project="$PROJECT_ID" \
     --member="serviceAccount:<CISAPP_SERVICE_ACCOUNT>" \
     --role="roles/iam.serviceAccountTokenCreator"
   ```

5. **Save the custom role definition** in a `role.yaml` file. It only contains metadata read permissions (see the list below): no data access.

   ```yaml
   title: CISAPP Posture Reader
   description: Read-only metadata access for CISAPP security posture scans. No data-plane access.
   stage: GA
   includedPermissions:
   - resourcemanager.projects.get
   - resourcemanager.projects.getIamPolicy
   - compute.instances.list
   - compute.firewalls.list
   - compute.networks.list
   - compute.subnetworks.list
   - compute.projects.get
   - storage.buckets.list
   - storage.buckets.getIamPolicy
   - cloudsql.instances.list
   - container.clusters.list
   - iam.serviceAccounts.get
   - iam.serviceAccounts.list
   - iam.serviceAccountKeys.list
   - cloudfunctions.functions.list
   - cloudfunctions.functions.getIamPolicy
   - run.locations.list
   - run.services.list
   - run.services.getIamPolicy
   - cloudkms.locations.list
   - cloudkms.keyRings.list
   - cloudkms.cryptoKeys.list
   - bigquery.datasets.get
   - bigquery.datasets.getIamPolicy
   - serviceusage.services.list
   ```

6. **Create the role and grant it to the service account.** The role must cover **the service account's home project** (it must be able to read itself) **and** the projects to analyze.

   - **With a Google Cloud organization**: a single grant at the organization level covers all its projects, including the home project.

     ```bash
     gcloud iam roles create cisappPostureReader --organization="$ORG_ID" \
       --file=role.yaml
     gcloud organizations add-iam-policy-binding "$ORG_ID" \
       --member="serviceAccount:$SA_EMAIL" \
       --role="organizations/$ORG_ID/roles/cisappPostureReader"
     ```

   - **Without an organization**: project by project. Replace `project-a project-b` with your projects, **without forgetting the service account's home project**. The role is created in each one.

     ```bash
     for P in project-a project-b; do
       gcloud iam roles create cisappPostureReader --project="$P" \
         --file=role.yaml
       gcloud projects add-iam-policy-binding "$P" \
         --member="serviceAccount:$SA_EMAIL" \
         --role="projects/$P/roles/cisappPostureReader"
     done
     ```

7. **Enable the APIs in the service account's home project**: its calls are counted and rate-limited there.

   ```bash
   gcloud services enable cloudresourcemanager.googleapis.com iam.googleapis.com serviceusage.googleapis.com \
     --project="$PROJECT_ID"
   ```

   Product APIs (Compute Engine, Cloud Storage, Cloud SQL…) do not have to be enabled for CISAPP: a product that is disabled in a project simply has nothing to inventory.

### Fallback predefined roles

If your organization forbids custom roles, grant these predefined roles to the service account instead, on the organization or on each project (without forgetting the home project):

- `roles/browser`
- `roles/compute.networkViewer`
- `roles/cloudsql.viewer`
- `roles/container.clusterViewer`
- `roles/iam.serviceAccountViewer`
- `roles/cloudfunctions.viewer`
- `roles/run.viewer`
- `roles/cloudkms.viewer`
- `roles/bigquery.metadataViewer`
- `roles/serviceusage.serviceUsageViewer`
- `roles/storage.bucketViewer`

> **Limit:** these roles do not allow reading bucket access policies (IAM). The **public bucket check then stays "unknown"**: it neither creates nor resolves a finding.

## Connect in CISAPP

1. In the setup panel, click **I'm done**.
2. Enter the **service account email** (for example `cisapp-readonly@my-project.iam.gserviceaccount.com`).
3. Optionally enter the **projects** to analyze, one identifier per entry (50 at most). **Empty: every active project the service account can read**, up to a cap set by the platform (100 by default); beyond it only the first ones are analyzed and the synchronization reports it.
4. **Verify access**: CISAPP checks that the service account exists, that it can impersonate it, that the token is in its description and that the projects are readable.
5. Check the displayed **service account** (its numeric identifier), then **Connect**. The connection becomes active and the **first synchronization** starts.

If you close the wizard before confirmation, the connection stays **Pending** and the setup panel is resumed from its record (the verification token stays the same). A connection left pending for more than 7 days without activity is deleted automatically.

Google IAM permissions propagate with a slight delay (a few seconds to a few minutes). If verification fails right after the commands, wait and try again. Likewise, the first synchronization may report a few partial "not granted" errors: the next one fixes them.

Once the connection is active, the list of **projects** can be changed from the connection record (**Edit scope**); the service account email cannot.

## What CISAPP collects

CISAPP only performs **reads** (`GET` requests; reading IAM policies uses the Google API `POST` method, without changing anything) and only reads **configuration**, never content. For each analyzed project:

- Google Cloud projects (identifier, state) and the **project IAM policy**, summarized as counters (no member address is kept);
- Compute Engine: instances, VPC firewall rules, networks and subnets;
- Cloud Storage: buckets (configuration and IAM access rules, not the objects);
- Cloud SQL: instances;
- Google Kubernetes Engine (GKE): clusters;
- service accounts and their user-managed keys (metadata: age, state);
- Cloud Functions and Cloud Run services (configuration and who may invoke them);
- Cloud KMS: encryption keys (rotation metadata);
- BigQuery: datasets (configuration and public access);
- the list of APIs enabled in each project.

Resources appear in the **Operational Safety → Cloud inventory** menu entry and its **Map** view, with their region and location. A product that the service account cannot read is reported as **not granted** in the synchronization result.

## What CISAPP never reads

CISAPP changes nothing in your environment. The role includes no write permission and no data read permission. CISAPP **never** reads, and therefore never stores:

- bucket content (objects), BigQuery tables, rows and queries;
- service account **key material** (no key is created, downloaded or used), secrets (Secret Manager), KMS keys themselves (no encryption, decryption or signing);
- environment variables and secrets of Cloud Functions and Cloud Run services, container images and arguments;
- GKE cluster credentials (certificates, tokens), passwords, certificates and flag values of Cloud SQL instances;
- disk encryption keys, labels, serial port output, screenshots and guest attributes;
- public IP addresses themselves (only the existence of a public address is kept) and the addresses of IAM policy members.

Compute instance and project metadata (for example startup scripts, SSH keys) is read for **three flags only**: `enable-oslogin`, `block-project-ssh-keys` and `serial-port-enable`. Google does not allow requesting a single key: the items are therefore requested as key/value pairs and their values pass through memory while the response is read; only these three flags are kept and nothing else is converted, stored or logged.

## Posture findings

Findings appear in security findings with the **Google Cloud posture** source. A rule only triggers when the information is certain: an unknown state (product not granted, unreadable value, value missing from the response) neither creates nor resolves a finding. 20 rules are evaluated.

| Finding title | Severity |
| --- | --- |
| Basic Owner or Editor role granted in the project | High; medium if only users hold the role |
| Project IAM policy open to allUsers or allAuthenticatedUsers | Critical |
| User-managed service account key older than 90 days | Medium |
| Compute instance exposed with a public IP address | Medium |
| Instance using the default service account with full API access | High |
| OS Login disabled on the instance | Medium |
| Serial console access enabled on the instance | Medium |
| Firewall rule open to the Internet on an administration port | High |
| Firewall rule open to the Internet on a database port | High |
| Firewall rule allowing all traffic from the Internet | Critical |
| Publicly accessible storage bucket | Critical; high if only read roles are public |
| Uniform bucket-level access disabled | Medium |
| Cloud SQL instance reachable from the Internet | Critical |
| Cloud SQL instance not enforcing TLS encryption | High; medium if the instance has no public address |
| Automated backups disabled on the Cloud SQL instance | Medium |
| Legacy ABAC authorization enabled on the GKE cluster | High |
| GKE control plane endpoint open to the Internet | High |
| Publicly invocable serverless function or service | Medium; high if ingress is open to all and the default Compute account runs it |
| KMS encryption key without automatic rotation | Medium |
| Publicly accessible BigQuery dataset | Critical |

Details:

- **Firewall**: only classic VPC ingress rules that are enabled are evaluated. Administration = ports 22 and 3389; databases = 1433, 1521, 3306, 5432, 6379, 9200, 9300, 11211 and 27017. A rule that opens every port is reported once, by the "all traffic" rule.
- **Serverless functions and services**: public access is often intended (public API); the finding is advisory. An ingress limited to the internal network is considered compliant.
- **Buckets**: only the IAM policy is evaluated. Legacy object or bucket ACLs are not read.
- **KMS**: only symmetric keys that can be rotated are concerned; a rotation period longer than 365 days is also reported.

## Limits

- **Organization policies** (for example `compute.requireOsLogin`, `compute.disableSerialPortAccess`, the ban on public bucket access) and **hierarchical or network firewall policies** are **not evaluated**: a finding may be neutralized at your organization level, and a deny rule is not taken into account. Findings describe each resource's own configuration.
- Audit policies inherited from a folder or the organization are not visible for a project attached to an organization.
- Google IAM permissions are **eventually consistent**: a role granted or removed may take a few minutes to take effect.
- Two CISAPP organizations can see the same projects through two different service accounts: the connection is exclusive per service account, not per project.
- An empty scope is capped; an inaccessible project is reported and its resources are not removed from the inventory.
- If the service account sees more projects than the cap (100 by default) in "all projects" mode, only the first ones are analyzed and **automatic finding resolution is paused for the whole connection**: findings are still created and updated, but none is resolved, and the synchronization reports it. List the projects to analyze explicitly to restore it.

## Revoke access

- **On the Google Cloud side**: remove the "Service Account Token Creator" role granted to CISAPP on your service account. CISAPP can no longer obtain a new token; the token already issued stays usable until it expires (one hour at most), subject to Google IAM propagation.

  ```bash
  gcloud iam service-accounts remove-iam-policy-binding "$SA_EMAIL" \
    --project="$PROJECT_ID" \
    --member="serviceAccount:<CISAPP_SERVICE_ACCOUNT>" \
    --role="roles/iam.serviceAccountTokenCreator"
  ```

- **On the CISAPP side**, **Disconnect** deletes the connection and its cloud inventory, marks its posture findings as resolved and drops the token kept in memory: this is the immediate stop on the CISAPP side. There is nothing to revoke at Google: no credential is stored. Then remove the impersonation role, and delete the service account and the custom role if they are no longer needed.

## Common issues

| Message | What to do |
| --- | --- |
| The Google Cloud connector is unavailable on this instance | The platform service account is not configured on your platform yet: contact support. |
| Google Cloud refused access | See the detailed causes below. |
| This service account is already connected by another CISAPP organization, or does not match this connection's account | A service account has a single connection: disconnect it from the other CISAPP organization first. Otherwise the account was deleted then recreated (new identifier: it is no longer the service account connected earlier): check the email you entered, disconnect the connection and reconnect it. The same message appears if the connection was changed while it was being verified: reload the page. |
| Unable to confirm: this service account changed since the verification | Start the verification again. |
| Too many attempts | Too many connection attempts in a short time (10 per minute at most): wait a minute. |
| The email is not valid (message under the field) | Enter a service account you created (`name@project.iam.gserviceaccount.com`). Google-managed accounts, including the legacy Google service agents, are refused. This is an input error, not a refusal from Google Cloud. |

When Google Cloud refuses access, verification stops at the first cause it meets, in this order:

| Cause | What to do |
| --- | --- |
| The service account belongs to CISAPP's project | Create it in one of **your** projects. |
| CISAPP cannot impersonate this service account | Check the email and that CISAPP's service account holds `roles/iam.serviceAccountTokenCreator` **on this service account**. Google does not distinguish a missing account from a missing permission. Wait for IAM propagation. |
| The service account cannot read itself | Grant it the custom role on **its home project**. |
| Enable an API in the home project | Enable `cloudresourcemanager`, `iam` and `serviceusage` in the home project (step 7). |
| A VPC Service Controls perimeter blocks the service account | Allow the service account in the perimeter. |
| The service account is not found, does not match the email, does not belong to its project or is disabled | Check the email and re-enable the service account. |
| The verification token was not found in the service account description | Update the description with the **exact** value from the panel (no extra text). The token is only checked while the connection is not active. |
| `roles/iam.serviceAccountTokenCreator` is granted on the project, a folder or the organization | Remove these wide grants and grant the role on the service account only. |
| The service account sees no project, or a project is not readable | Grant the custom role on the projects to analyze (or on the organization) and check that each project is active. |

After connecting, in synchronizations:

| Symptom | Likely cause |
| --- | --- |
| Product "not granted" in the result | A permission of the role is missing on that project: grant it on that project or on the organization. |
| `SERVICE_DISABLED` error in the result | An API of the service account's home project is disabled (step 7). |
| Connection in error "credentials refused" | Impersonation is refused (role removed, account deleted or disabled): restore it, then start the verification again from the record. |
| Connection in error "the service account was replaced" | The service account was recreated: disconnect, then reconnect the account. |
| Project limit reached | Explicitly select the projects to analyze (while the list is empty, no finding is resolved automatically). |

## Expected result

The connection is active, the cloud inventory is populated and Google Cloud posture findings appear in CISAPP.

See also: [Configure connectors](https://docs.cisapp.eu/en/organization/connectors).
