> For the complete documentation index, see [llms.txt](https://docs.sec1.io/user-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sec1.io/user-docs/11-cspm/2-permissions.md).

# CSPM Required Permissions

All access Sec1 CSPM requires is **read-only**. Grant the scanning identity the roles below per cloud. Cloud posture and Kubernetes use the **same identity** per account — you add the Kubernetes roles only when you onboard clusters.

## Summary

| Cloud                            | Identity                         | Minimum roles                                   |
| -------------------------------- | -------------------------------- | ----------------------------------------------- |
| **GCP**                          | Service account                  | `roles/viewer` + `roles/iam.securityReviewer`   |
| **Azure**                        | Service principal                | `Reader` + `Security Reader`                    |
| **AWS**                          | IAM role (assumed cross-account) | `SecurityAudit` + `ViewOnlyAccess`              |
| **Kubernetes** (GKE / AKS / EKS) | Same cloud identity above        | Cluster read access + read-only in-cluster RBAC |

{% hint style="info" %}
The minimums above get you posture and compliance scanning quickly. Add the per-cloud roles listed below for full identity and Kubernetes depth.
{% endhint %}

***

## GCP (cloud + GKE / Kubernetes)

Grant the Sec1 scanning **service account** the following roles at project, folder, or org level:

* **`roles/viewer`** (Project Viewer)
* **`roles/iam.securityReviewer`**
* **`roles/monitoring.viewer`**
* **`roles/serviceusage.serviceUsageViewer`**

For scanning **GKE / Kubernetes** (same service account), additionally:

* **`roles/container.viewer`**
* **`roles/compute.viewer`**
* A read-only in-cluster RBAC binding for **Secret metadata** (one-time per cluster):

  ```bash
  kubectl create clusterrole sec1-cspm-secrets-metadata-reader --verb=get,list --resource=secrets
  kubectl create clusterrolebinding sec1-cspm-secrets-metadata-reader \
    --clusterrole=sec1-cspm-secrets-metadata-reader --user=<service-account-email>
  ```
* The cluster API server (control plane) must be reachable by the scanner. For a private cluster, authorise the scanner on the cluster's **Control Plane Authorized Networks**, or use **Connect Gateway**.

{% hint style="success" %}
**Minimum if you prefer the broadest single role:** Project Viewer (`roles/viewer`) + `roles/iam.securityReviewer` covers most of the posture checks.
{% endhint %}

### GCP organization-scope (recommended for many projects)

If you want to onboard many projects at once, grant the **same read-only roles** at a **higher node** — the **organization** or a **folder** — instead of repeating them project by project. Because GCP IAM is hierarchical, every child project **inherits** the roles automatically, including projects created later.

Grant the scanning service account, at the **organization** (or **folder**) node:

* The posture roles above — **`roles/viewer`**, **`roles/iam.securityReviewer`**, **`roles/monitoring.viewer`**, **`roles/serviceusage.serviceUsageViewer`** (and **`roles/container.viewer`** + **`roles/compute.viewer`** for GKE).
* **`roles/browser`** (or, more narrowly, the `resourcemanager.projects.list` permission via a custom role) — so Sec1 can **enumerate the projects** under the node and present them for selection.
* **`roles/cloudasset.viewer`** *(recommended)* — enables **Cloud Asset Inventory** for fast, complete **org-wide discovery**. This is what lets Sec1 find every project and **Shared-VPC host projects** (whose networks/firewalls a service project only *uses* but cannot list), so cross-project exposure and attack paths are complete. It is a **separate grant** — not part of `roles/viewer` or `roles/iam.securityReviewer` — and also requires enabling the **Cloud Asset API** (`cloudasset.googleapis.com`).

```bash
# Grant a read-only posture role at the organization node (repeat per role).
gcloud organizations add-iam-policy-binding ORG_ID \
  --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
  --role="roles/viewer"

# Allow Sec1 to enumerate the projects under the org (project listing).
gcloud organizations add-iam-policy-binding ORG_ID \
  --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
  --role="roles/browser"

# Recommended: org-wide discovery via Cloud Asset Inventory (finds Shared-VPC host
# projects). Also enable the API once: gcloud services enable cloudasset.googleapis.com
gcloud organizations add-iam-policy-binding ORG_ID \
  --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
  --role="roles/cloudasset.viewer"

# Or scope the grant to a single folder instead of the whole org.
gcloud resource-manager folders add-iam-policy-binding FOLDER_ID \
  --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
  --role="roles/viewer"
```

{% hint style="info" %}
**Per-project still works.** Granting the roles at the project node (the list above) remains fully supported — use it when you do not want to grant org-wide. Org-scope and per-project onboarding can be mixed.
{% endhint %}

***

## Azure (cloud + AKS / Kubernetes)

Grant the Sec1 **service principal** the following roles at the **subscription** scope:

* **`Reader`**
* **`Security Reader`**
* **`Monitoring Reader`**
* **`Key Vault Reader`** (with data-plane read for key/secret metadata)
* **Microsoft Graph** application permissions (admin-consented), for identity/MFA/RBAC checks: `Directory.Read.All`, `Policy.Read.All`, `UserAuthenticationMethod.Read.All`, `RoleManagement.Read.Directory`

For scanning **AKS / Kubernetes** (same service principal), additionally:

* **`Reader`** on the AKS cluster + **`Azure Kubernetes Service Cluster User Role`** (to read cluster credentials)
* **`Azure Kubernetes Service RBAC Reader`** (in-cluster read) — or a read-only Kubernetes ClusterRole bound to the service principal
* **`Reader`** on the AKS node resource group (`MC_*`)
* API server reachable by the scanner (for a private cluster, add the scanner to the cluster's authorized IP ranges)

{% hint style="success" %}
**Minimum:** `Reader` + `Security Reader`; add the rest for full depth.
{% endhint %}

### Azure organization-scope (recommended for many subscriptions)

To onboard many subscriptions at once, assign the **same read-only roles** at a **management group** (or the **tenant root** management group) instead of per subscription. Azure RBAC inherits **downward**, so every subscription under the management group — including subscriptions moved or created later — inherits the roles automatically. Sec1 then enumerates the subscriptions via the **management-group hierarchy**.

Assign the scanning service principal, at the **management group** scope:

* **`Reader`** + **`Security Reader`** (and **`Monitoring Reader`**, **`Key Vault Reader`** for full depth) — these flow down to all child subscriptions.
* The admin-consented **Microsoft Graph** application permissions are tenant-wide already, so they are consented **once** regardless of how many subscriptions you onboard.

```bash
# Assign a read-only role at a management group (repeat per role).
az role assignment create \
  --assignee "SERVICE_PRINCIPAL_OBJECT_ID" \
  --role "Reader" \
  --scope "/providers/Microsoft.Management/managementGroups/MANAGEMENT_GROUP_ID"

az role assignment create \
  --assignee "SERVICE_PRINCIPAL_OBJECT_ID" \
  --role "Security Reader" \
  --scope "/providers/Microsoft.Management/managementGroups/MANAGEMENT_GROUP_ID"
```

{% hint style="info" %}
**Per-subscription still works.** Assigning the roles at the subscription scope (the list above) remains fully supported — use it when you do not want to grant across a management group. The two approaches can be mixed.
{% endhint %}

***

## AWS (cloud + EKS / Kubernetes)

{% hint style="info" %}
Grant the read-only roles below to connect AWS accounts and EKS clusters.
{% endhint %}

Create a read-only IAM **role** for Sec1 to assume cross-account (with an external ID), attaching the AWS-managed policies:

* **`SecurityAudit`** (posture, IAM, exposure checks)
* **`ViewOnlyAccess`** (resource inventory)

For scanning **EKS / Kubernetes**, additionally:

* `eks:DescribeCluster`, `eks:ListClusters` (and related `eks:Describe*` / `eks:List*` read actions)
* A read-only Kubernetes RBAC binding mapped to the role via the cluster `aws-auth` ConfigMap (or EKS Access Entries)
* The cluster API server endpoint reachable by the scanner

{% hint style="success" %}
**Minimum:** `SecurityAudit` + `ViewOnlyAccess`; add the EKS describe + RBAC read for cluster scanning.
{% endhint %}

### AWS organization-scope

AWS organization onboarding follows the **AWS Organizations management-account model** so you can cover many member accounts without per-account setup:

* Sec1 assumes a read-only role (e.g. **`SecurityAudit`** as a **delegated** administrator, or a role **assumable across member accounts**) provisioned once from the **management account** — typically via an organization-wide CloudFormation **StackSet** or a delegated security account.
* Sec1 **enumerates member accounts** through AWS Organizations and lets you select which to onboard, each becoming an independent account in Sec1.

Per-account role assumption (with an external ID) is also supported for customers who do not want to grant at the organization level.

***

## Kubernetes on each cloud (GKE / EKS / AKS)

In-cluster posture — RBAC over-permission, privileged pods, exposed dashboards, missing network/pod security policies, and CIS Kubernetes Benchmark checks — is read through a **read-only ClusterRole** bound to the scanning identity. The cloud-specific binding details are in the sections above; in all cases:

* The binding is **read-only** (`get`, `list`, `watch`).
* One binding per cluster, applied once at onboarding.
* Secret **metadata** only — Sec1 reads names and types, never secret values.
* The cluster **API server (control plane) must be reachable** by the scanner. For private control planes, authorise the scanner on the cluster's control-plane authorized networks / authorized IP ranges (or use Connect Gateway on GKE), or run Sec1 in a hybrid deployment that reaches the private endpoint directly.

| Cloud   | Cluster read access                                                            | In-cluster read-only RBAC                                                       | Control-plane reachability             |
| ------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | -------------------------------------- |
| **GKE** | `roles/container.viewer` + `roles/compute.viewer`                              | ClusterRole/binding for Secret metadata (command above)                         | Authorized Networks or Connect Gateway |
| **AKS** | `Azure Kubernetes Service Cluster User Role` + `Reader` on cluster & `MC_*` RG | `Azure Kubernetes Service RBAC Reader` or read-only ClusterRole bound to the SP | Authorized IP ranges                   |
| **EKS** | `eks:DescribeCluster`, `eks:ListClusters`                                      | Read-only RBAC via `aws-auth` / EKS Access Entries                              | Cluster API endpoint reachable         |

### The read-only ClusterRole

Apply this once per cluster and bind it to the scanning identity (the GCP service account, Azure service principal, or AWS role that connects). It grants `get` / `list` / `watch` only — no create/update/delete, no `exec`, no `port-forward`:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: sec1-cspm-reader
rules:
  - apiGroups: [""]            # core
    resources: [pods, services, endpoints, configmaps, namespaces, nodes,
                persistentvolumes, persistentvolumeclaims, serviceaccounts,
                resourcequotas, limitranges]
    verbs: [get, list, watch]
  - apiGroups: ["apps"]
    resources: [deployments, replicasets, daemonsets, statefulsets]
    verbs: [get, list, watch]
  - apiGroups: ["batch"]
    resources: [jobs, cronjobs]
    verbs: [get, list, watch]
  - apiGroups: ["networking.k8s.io"]
    resources: [networkpolicies, ingresses]
    verbs: [get, list, watch]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: [roles, rolebindings, clusterroles, clusterrolebindings]
    verbs: [get, list, watch]
  - apiGroups: ["storage.k8s.io"]
    resources: [storageclasses]
    verbs: [get, list, watch]
```

Bind it to the scanning identity:

```bash
kubectl create clusterrolebinding sec1-cspm-reader \
  --clusterrole=sec1-cspm-reader \
  --user=<scanning-identity>   # GCP service-account email / Azure SP object id / EKS-mapped principal
```

{% hint style="info" %}
**Secrets:** the ClusterRole above intentionally omits `secrets`. You can instead bind the built-in **`view`** ClusterRole — it is read-only and **excludes Secrets** entirely. Add a narrow Secret-metadata rule (`get`, `list` on `secrets`) only if you want secret-hygiene findings; Sec1 inspects secret **metadata** (names, types, age), never values.
{% endhint %}
