GCP Permissions and Scopes for Compute Engine VMs

Table of Contents

Why adding IAM roles isn’t always enough

If you’ve ever granted a service account a role in Google Cloud Platform (GCP) but your VM still can’t access a resource — you’re not alone.

This is one of those “GCP gotchas” that almost every cloud engineer faces at some point. You add the role, double-check the permissions, and still get 403 Permission Denied.

So what’s missing?

The answer lies in a second, lesser-known layer of control: OAuth scopes.

In this post, we’ll break down how IAM permissions and OAuth scopes work together in GCP — specifically for Compute Engine (VMs) — and how to configure both correctly.

What Are GCP Permissions?

Permissions in GCP determine what actions an identity can perform on a resource.
They’re the foundation of GCP’s Identity and Access Management (IAM) system.

Every permission belongs to a role. For example:

  • roles/compute.admin → manage Compute Engine resources
  • roles/storage.objectViewer → view objects in Cloud Storage

When you assign a role to a service account, you’re telling GCP:

“This account is allowed to perform these actions within this project.”

This part is usually clear — but it’s only one piece of the access puzzle.

The Scope of IAM Permissions

GCP organizes everything under a resource hierarchy:

Organization → Folder → Project → Resource

Roles can be assigned at any of these levels, and they inherit downward.
That means a role at the organization level applies to all projects and resources underneath it.

Scope Level

Example

Inheritance

Organization

All GCP resources in your company

Inherited by all folders and projects

Folder

“Development” folder

Inherited by all projects inside

Project

my-app-prod

Applies to all resources (VMs, buckets, etc.)

Resource

One specific VM

Applies only to that instance

So, assigning a role at the project level usually covers everything inside that project — including your Compute Engine VMs.

But here’s the twist: VMs have their own access layer called scopes.


IAM Permissions vs OAuth Scopes

IAM defines what a service account can do.
Scopes define which APIs the VM is allowed to call.

Think of it like this:

  • IAM = the building access card
  • Scopes = the door keypad code

Even if you have the card, you still need the correct code to open the door.

Feature

Controls

Applies To

Example

IAM Role

Actions allowed on GCP resources

Organization, Folder, Project, or Resource

roles/storage.objectViewer

OAuth Scope

API access permission for a VM

Compute Engine VM instance

https://www.googleapis.com/auth/devstorage.read_only

If either IAM or scopes are misconfigured, the VM won’t have access — no matter what roles you assign.

Example: Accessing Cloud Storage from a VM

Let’s see how this plays out in practice.

You have a VM with a service account my-vm-sa@project.iam.gserviceaccount.com.
You want it to read files from a Cloud Storage bucket.

Step 1: Grant IAM role

Give the service account the required permission:

gcloud projects add-iam-policy-binding my-project \
  --member="serviceAccount:my-vm-sa@project.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

This gives the service account the permission to read GCS objects.

Step 2: Set VM Scopes

Now, when you create the VM, add the Storage read-only scope:

gcloud compute instances create my-vm \
  --service-account=my-vm-sa@project.iam.gserviceaccount.com \
  --scopes=https://www.googleapis.com/auth/devstorage.read_only

Result: The VM can now call the GCS API and read objects.

If you skip the scope, you’ll get “Insufficient Permission” errors — even though IAM looks correct.

That’s because the VM’s metadata server filters API requests based on scopes, adding another layer of control.


Managing Scopes in Compute Engine

There are a few key things to know about scopes:

  1. Set during VM creation
    You define scopes when creating the instance using --scopes or through the Cloud Console under Access Scopes.
  2. Can’t change after creation
    Once the VM is up, you can’t modify its scopes. You’d need to recreate it to apply new ones.
  3. Avoid “Allow full access to all Cloud APIs”
    It’s tempting but dangerous. This gives the VM access to every API that IAM permits — breaking the principle of least privilege.

The Modern Approach: IAM + cloud-platform Scope

In the early days, you had to manually align IAM roles and specific scopes for each API.
Now, Google recommends a simpler, modern approach:

Use the cloud-platform scope.

--scopes=https://www.googleapis.com/auth/cloud-platform

This single scope lets the VM access any Google API — but IAM still enforces the permissions.
It’s like saying, “Let IAM decide what this VM can actually do.”

This approach simplifies management while still keeping your environment secure.

So, in most modern setups:

  • Assign fine-grained IAM roles
  • Use the cloud-platform scope
  • Let IAM do the heavy lifting

Common Pitfalls and Fixes

Even experienced teams run into small issues. Here are a few to watch for:

Problem

Root Cause

Solution

“403 Permission denied” from VM

Missing or restrictive scope

Recreate VM with proper scope

Works locally but not on VM

VM’s default scope doesn’t allow API access

Verify scopes via metadata server

Using legacy API clients

Old libraries depend on explicit scopes

Use updated SDKs that respect IAM roles

Quick check:

You can verify a VM’s scopes using this command:

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes" \
  -H "Metadata-Flavor: Google"

If the expected API scope isn’t listed — that’s your problem.


Best Practices for Permissions and Scopes

Here’s how to stay out of trouble (and 403 errors):

  • Grant least privilege IAM roles — avoid Editor or Owner roles.
  • Use the cloud-platform scope and manage access through IAM.
  • Document scopes used in Terraform or Deployment Manager templates.
  • Audit your service accounts periodically — remove unused roles or accounts.
  • Avoid reusing service accounts across unrelated workloads.

Following these practices keeps your infrastructure secure, predictable, and easy to debug.

Conclusion

IAM defines what your service account can do.
Scopes define what your VM is allowed to access.

If your VM isn’t behaving as expected, don’t just check IAM — check the scopes too.

Understanding both layers gives you complete control over how your VMs interact with Google Cloud services. And once you get this right, those frustrating 403 errors become a thing of the past.