Skip to main content

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

PermissionPurpose
compute.instances.listList all VM instances
compute.instances.getGet instance details and status
compute.instances.startStart stopped instances
compute.instances.stopStop running instances
compute.zones.listList available zones

Predefined Role Alternative: roles/compute.instanceAdmin.v1

Over-Permissive

The predefined role includes delete permissions. Use the custom role for least privilege.

Cloud SQL

PermissionPurpose
cloudsql.instances.listList all Cloud SQL instances
cloudsql.instances.getGet instance details and status
cloudsql.instances.updateModify activation policy (start/stop)

Predefined Role Alternative: roles/cloudsql.editor

Cloud Run

PermissionPurpose
run.services.listList all Cloud Run services
run.services.getGet service details
run.services.updateUpdate scaling configuration

Predefined Role Alternative: roles/run.developer

GKE

PermissionPurpose
container.clusters.listList all GKE clusters
container.clusters.getGet cluster details
container.nodePools.listList node pools in a cluster
container.nodePools.getGet node pool details
container.nodePools.updateUpdate node pool size
container.operations.getCheck operation status
container.operations.listList ongoing operations

Predefined Role Alternative: roles/container.clusterAdmin

Over-Permissive

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

  1. Create the NightOps service account in the hub project
  2. Grant roles/iam.serviceAccountTokenCreator on spoke service accounts
# In hub project
gcloud iam service-accounts create nightops-hub \
--display-name="NightOps Hub Service Account"

Spoke Project Setup

  1. Create a service account in each spoke project
  2. Assign the NightOps custom role
  3. 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'
Condition Support

IAM Conditions are supported for Compute Engine. Cloud SQL and GKE have limited condition support.


Permissions Summary Table

ServiceRead PermissionsWrite Permissions
Computeinstances.list, instances.get, zones.listinstances.start, instances.stop
Cloud SQLinstances.list, instances.getinstances.update
Cloud Runservices.list, services.getservices.update
GKEclusters.list/get, nodePools.list/get, operations.list/getnodePools.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

Label-Based Management

Use GCP labels (nightops-managed=true) to identify resources that NightOps should manage.

Audit Logging

Enable Cloud Audit Logs to track all NightOps actions for compliance and debugging.

Workload Identity

For GKE-based deployments, use Workload Identity instead of service account keys.

Next Steps