GCP IAM Policy Reference
This document outlines the IAM permissions required for NightOps to manage Google Cloud Platform resources. The policy follows the principle of least privilege.
Quick Start
For a quick setup, use the custom IAM role below. For more granular control, see the Per-Service Permissions section.
Complete NightOps Custom Role
title: NightOps Resource Manager
description: Allows NightOps to manage compute resources for cost optimization
stage: GA
includedPermissions:
# Compute Engine
- compute.instances.list
- compute.instances.get
- compute.instances.start
- compute.instances.stop
- compute.zones.list
# Cloud SQL
- cloudsql.instances.list
- cloudsql.instances.get
- cloudsql.instances.update
# Cloud Run
- run.services.list
- run.services.get
- run.services.update
# GKE
- container.clusters.list
- container.clusters.get
- container.nodePools.list
- container.nodePools.get
- container.nodePools.update
- container.operations.get
- container.operations.list
Create the Custom Role
gcloud iam roles create NightOpsResourceManager \
--project=YOUR_PROJECT_ID \
--file=nightops-role.yaml
Assign to Service Account
# Create service account
gcloud iam service-accounts create nightops \
--display-name="NightOps Service Account"
# Assign custom role
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:nightops@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="projects/YOUR_PROJECT_ID/roles/NightOpsResourceManager"
Per-Service Permissions
Compute Engine
| Permission | Purpose |
|---|---|
compute.instances.list | List all VM instances |
compute.instances.get | Get instance details and status |
compute.instances.start | Start stopped instances |
compute.instances.stop | Stop running instances |
compute.zones.list | List available zones |
Predefined Role Alternative: roles/compute.instanceAdmin.v1
The predefined role includes delete permissions. Use the custom role for least privilege.
Cloud SQL
| Permission | Purpose |
|---|---|
cloudsql.instances.list | List all Cloud SQL instances |
cloudsql.instances.get | Get instance details and status |
cloudsql.instances.update | Modify activation policy (start/stop) |
Predefined Role Alternative: roles/cloudsql.editor
Cloud Run
| Permission | Purpose |
|---|---|
run.services.list | List all Cloud Run services |
run.services.get | Get service details |
run.services.update | Update scaling configuration |
Predefined Role Alternative: roles/run.developer
GKE
| Permission | Purpose |
|---|---|
container.clusters.list | List all GKE clusters |
container.clusters.get | Get cluster details |
container.nodePools.list | List node pools in a cluster |
container.nodePools.get | Get node pool details |
container.nodePools.update | Update node pool size |
container.operations.get | Check operation status |
container.operations.list | List ongoing operations |
Predefined Role Alternative: roles/container.clusterAdmin
The predefined role includes delete permissions. Use the custom role for least privilege.
Multi-Project Setup
For managing resources across multiple GCP projects, use service account impersonation.
Architecture
┌─────────────────┐ ┌─────────────────┐
│ Hub Project │ │ Spoke Project │
│ (NightOps) │────────▶│ (Customer) │
│ │Impersonate│ │
└─────────────────┘ └─────────────────┘
Hub Project Setup
- Create the NightOps service account in the hub project
- Grant
roles/iam.serviceAccountTokenCreatoron spoke service accounts
# In hub project
gcloud iam service-accounts create nightops-hub \
--display-name="NightOps Hub Service Account"
Spoke Project Setup
- Create a service account in each spoke project
- Assign the NightOps custom role
- Allow the hub service account to impersonate
# In spoke project
gcloud iam service-accounts create nightops-spoke \
--display-name="NightOps Spoke Service Account"
# Assign custom role
gcloud projects add-iam-policy-binding SPOKE_PROJECT_ID \
--member="serviceAccount:nightops-spoke@SPOKE_PROJECT_ID.iam.gserviceaccount.com" \
--role="projects/SPOKE_PROJECT_ID/roles/NightOpsResourceManager"
# Allow impersonation from hub
gcloud iam service-accounts add-iam-policy-binding \
nightops-spoke@SPOKE_PROJECT_ID.iam.gserviceaccount.com \
--member="serviceAccount:nightops-hub@HUB_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountTokenCreator"
Label-Based Access Control
GCP supports IAM Conditions for fine-grained access control based on resource labels.
Example: Restrict to Managed Resources
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:nightops@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="projects/YOUR_PROJECT_ID/roles/NightOpsResourceManager" \
--condition='expression=resource.matchLabels("nightops-managed", "true"),title=NightOpsManaged,description=Only allow access to NightOps-managed resources'
IAM Conditions are supported for Compute Engine. Cloud SQL and GKE have limited condition support.
Permissions Summary Table
| Service | Read Permissions | Write Permissions |
|---|---|---|
| Compute | instances.list, instances.get, zones.list | instances.start, instances.stop |
| Cloud SQL | instances.list, instances.get | instances.update |
| Cloud Run | services.list, services.get | services.update |
| GKE | clusters.list/get, nodePools.list/get, operations.list/get | nodePools.update |
Terraform Module
# Create custom role
resource "google_project_iam_custom_role" "nightops" {
role_id = "nightopsResourceManager"
title = "NightOps Resource Manager"
description = "Allows NightOps to manage compute resources"
permissions = [
"compute.instances.list",
"compute.instances.get",
"compute.instances.start",
"compute.instances.stop",
"compute.zones.list",
"cloudsql.instances.list",
"cloudsql.instances.get",
"cloudsql.instances.update",
"run.services.list",
"run.services.get",
"run.services.update",
"container.clusters.list",
"container.clusters.get",
"container.nodePools.list",
"container.nodePools.get",
"container.nodePools.update",
"container.operations.get",
"container.operations.list",
]
}
# Create service account
resource "google_service_account" "nightops" {
account_id = "nightops"
display_name = "NightOps Service Account"
}
# Assign custom role
resource "google_project_iam_member" "nightops" {
project = var.project_id
role = google_project_iam_custom_role.nightops.id
member = "serviceAccount:${google_service_account.nightops.email}"
}
Security Best Practices
Use GCP labels (nightops-managed=true) to identify resources that NightOps should manage.
Enable Cloud Audit Logs to track all NightOps actions for compliance and debugging.
For GKE-based deployments, use Workload Identity instead of service account keys.
Next Steps
- GCP Supported Services - Learn about supported services