# Cloud permissions

> The minimum IAM permissions ZopNight needs on AWS, GCP, and Azure to pull metrics and act on resources.

Source: https://zop.dev/docs/zopnight/cloud-setup/permissions

---

ZopNight runs in **read-only** mode by default; discovery, recommendations, cost tracking, and metrics all work with the minimum permissions on this page. Read-write features (start/stop, auto-remediation, autoscaler write mode) need additional permissions you grant explicitly per cloud account.

This page covers the minimum policy each cloud needs. Per-service add-ons are linked from each section.

## AWS. IAM policy for the aggregator

The aggregator pulls CloudWatch metrics and EBS/EC2 resource shapes. Attach this policy to the IAM user or role you give ZopNight.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CloudWatchRead",
      "Effect": "Allow",
      "Action": [
        "cloudwatch:GetMetricStatistics",
        "cloudwatch:GetMetricData",
        "cloudwatch:ListMetrics"
      ],
      "Resource": "*"
    },
    {
      "Sid": "EC2DescribeForResourceShape",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeVolumes",
        "ec2:DescribeInstances",
        "ec2:DescribeRegions"
      ],
      "Resource": "*"
    }
  ]
}
```

**Note**

`cloudwatch:GetMetricStatistics` requires `Resource: "*"` because CloudWatch does not support resource-level ARNs for that action. This is an AWS limitation, not a ZopNight design choice.

### Namespaces ZopNight queries

The CloudWatch policy lets ZopNight read metrics in these namespaces:

`AWS/EC2`, `AWS/EBS`, `AWS/RDS`, `AWS/Lambda`, `AWS/ElastiCache`, `AWS/MemoryDB`, `AWS/Redshift`, `AWS/OpenSearchService`, `AWS/DynamoDB`, `AWS/DocDB`, `AWS/Neptune`, `AWS/SQS`, `AWS/SNS`, `AWS/CloudFront`, `AWS/NATGateway`, `AWS/TransitGateway`, `AWS/Kafka`, `AWS/Kinesis`, `AWS/SageMaker`, `AWS/Bedrock`, `AWS/ElasticMapReduce`, `AWS/AppStream`, `AWS/WorkSpaces`, `AWS/ApiGateway`, `AWS/EFS`, `AWS/ApplicationELB`, `AWS/NetworkELB`, `AWS/EC2/Spot`, `AWS/S3-RequestMetrics`.

### Discovery permissions

The policy above covers metrics. **Discovery uses Resource Explorer 2 plus per-service describe calls**: for the full discoverer permission set, the simplest path is to attach the AWS-managed `ReadOnlyAccess` policy on top of the metrics policy above.

**Note**

`ReadOnlyAccess` grants more than ZopNight strictly needs. If your security policy requires least-privilege, contact support for the per-service describe-only list (one statement per resource type), which is narrower than `ReadOnlyAccess` but verbose to maintain by hand.

### Billing data (for actual cost in Reports)

To replace rack-rate calculation with real billing cost in Reports, ZopNight needs AWS Cost Explorer access. Attach this policy in addition to the above:

```json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "ce:GetCostAndUsage",
      "ce:GetCostAndUsageWithResources",
      "ce:GetTags"
    ],
    "Resource": "*"
  }]
}
```

Without this, the org falls back to rack rate. With it on every account in the org, Reports shows real billing cost.

### Start / Stop (opt-in)

For ZopNight to actually stop and start resources via schedules, autoscaler, or auto-remediation, you need the corresponding action permissions per service. For EC2 start/stop, attach this policy in addition to the read policies above:

```json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "ec2:StartInstances",
      "ec2:StopInstances"
    ],
    "Resource": "*"
  }]
}
```

**Note**

`ec2:StartInstances` and `ec2:StopInstances` support resource-level ARNs and condition keys. In production, scope `Resource` to the instance ARNs (or a ZopNight-managed tag condition) you want ZopNight to control rather than granting `*`.

Other services follow the same shape (`rds:StopDBInstance`, `rds:StartDBInstance`, and so on). Contact support for the full per-service write policy template.

## Azure. Service Principal role assignments

When using the Service Principal method, ZopNight authenticates with clientId / clientSecret / tenantId / subscriptionId; Workload Identity Federation is also supported. Whichever Azure auth method you pick, the minimum role assignment is:

```
Role:    Monitoring Reader
Scope:   /subscriptions/{subscriptionId}
```

`Monitoring Reader` includes `Microsoft.Insights/metrics/read` on every resource in the subscription; that's what the disk metrics fetcher needs to read OS Disk / Data Disk queue depth and latency gauges.

**Tip**

If you grant `Reader` (the broader built-in role) instead of `Monitoring Reader`, it also includes `Microsoft.Insights/metrics/read`. Either works. `Reader` is simpler to grant if your subscription policies push back on creating bespoke role assignments.

### Billing data

Azure billing data uses the `Cost Management Reader` role on the billing scope, plus the **amortized cost** export type so reservation and savings-plan purchases attribute correctly per resource per day. With actual-cost mode at subscription scope, reserved VMs show $0; amortized fixes this.

### Start / Stop / deallocate (opt-in)

For VM lifecycle actions, ZopNight needs `Microsoft.Compute/virtualMachines/start/action`, `/restart/action`, `/deallocate/action`. The `Virtual Machine Contributor` built-in covers these. For AKS scaling, add `Azure Kubernetes Service Cluster User Role` and `Azure Kubernetes Service Contributor Role`.

## GCP. Service Account roles

For the Service Account Key method, ZopNight authenticates with a service-account JSON; One-Click Connect uses a managed service account instead. Whichever auth method you pick, the minimum role is:

```
Role:    roles/monitoring.viewer
Scope:   project (the GCP project that owns the resources)
```

This includes `monitoring.timeSeries.list`; used by the disk fetcher to read `compute.googleapis.com/instance/disk/read_latencies`, write latencies, and throttled read/write op counts. The same role covers the GCS access-rate fetcher, Pub/Sub topic fetcher, GCP load-balancer fetcher, and Cloud SQL fetcher.

### Cloud Asset Inventory (for discovery)

Add `roles/cloudasset.viewer` for resource discovery. This is what powers the Cloud Asset Inventory sweep that finds 80+ resource types per GCP project.

### Billing data

For real billing cost in Reports, ZopNight reads from BigQuery billing exports. Add `roles/bigquery.dataViewer` and `roles/bigquery.jobUser` on the billing project, plus the billing export configured at the GCP organisation level. Contact support for the BigQuery dataset configuration.

### Start / Stop (opt-in)

For Compute Engine lifecycle, `roles/compute.instanceAdmin.v1`. For GKE, `roles/container.developer` (or `container.admin` for namespace operations).

### IAM Import (optional)

To pull GCP IAM members and bindings for the Cloud IAM Import wizard, `roles/iam.securityReviewer`. To also pull Google Group members, `roles/cloudidentity.groups.reader` at the **organisation** level (not project level).

## Per-account discovery health

After connecting an account, the per-resource-type discovery success or failure is recorded in ZopNight. From **Settings → Cloud accounts → View Permissions**, you'll see a drawer grouped by category (Compute, Database, Storage, Kubernetes, etc.) with per-resource-type status:

**Granted**

    The resource type was discovered successfully on the last sweep.

**Denied**

    The cloud API returned AccessDenied / 403 / AuthorizationFailed. Click the row to see the exact error and which permission to grant.

**Unknown**

    No determination yet. Either the discovery hasn't run, or the resource type isn't relevant to this account.

Denied entries auto-skip in the periodic 6-hour discovery cron for 24 hours, so a permission gap doesn't cost you repeated failed API calls. **Manual refresh always retries everything**: use it after granting the missing role to pick up the newly-allowed resource types immediately.

## Metric coverage check

After you've granted permissions and run a fresh metrics sync, verify that the recommender is getting the metrics it expects. From **Settings → Cloud accounts → View Permissions**, a resource type whose metrics are flowing shows as **Granted**; the goal is for every relevant resource type to reach **Granted** after a manual refresh.

Any resource type still missing metrics points at either a permission gap or a discoverer enrichment issue. Grant the missing role and run a **Manual refresh**; if misses persist, contact support.

## Validation summary

| Path | Validated against |
|---|---|
| AWS EBS in-use volume | Real CloudWatch data returned for `VolumeQueueLength`, `VolumeTotalReadTime`, `VolumeTotalWriteTime`, `VolumeReadOps`, `VolumeWriteOps` over 90-day window |
| AWS EBS idle volume | Empty result returned (correct behaviour; idle volumes have no metrics) |
| Azure disk path | Wired and dispatched; live fetch needs the discoverer to enrich `attachedTo` metadata on the managed disk |
| GCP disk path | Wired and dispatched; resolves disk → instance via `attachedTo` metadata + `instanceId` on the parent VM |
