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 resourcesroles/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 |
| 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 |
|
OAuth Scope | API access permission for a VM | Compute Engine VM instance |
|
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:
- Set during VM creation
You define scopes when creating the instance using--scopesor through the Cloud Console under Access Scopes. - 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. - 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-platformscope - 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
EditororOwnerroles. - Use the
cloud-platformscope 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.