TerraformPilot

DevOps

Fix Terraform Error - GCP Error 403 Forbidden Insufficient Permissions

Learn how to fix Google Cloud 403 Forbidden and insufficient permissions errors in Terraform. Covers IAM roles, service account setup, and API enablement.

LLuca Berton3 min read

Quick Answer

#

The GCP 403 Forbidden error means the service account or user running Terraform lacks the IAM permissions or API enablement required for the requested operation. Grant the correct IAM roles, enable the required APIs, or authenticate with a properly-configured service account.

The Error

#

When running terraform plan or terraform apply against Google Cloud, you encounter one of these errors:

Error: googleapi: Error 403: Required permissions not available
Error: googleapi: Error 403: Caller does not have permission
Error: googleapi: Error 403: Access Not Configured.
  [service] has not been used in project [PROJECT_ID] before
  or it is disabled. Enable it by visiting
  https://console.developers.google.com/apis/api/...
Error: Error creating Instance: googleapi: Error 403:
  Required 'compute.instances.create' permission for
  'projects/my-project/zones/us-central1-a/instances/web-server'

What Causes This Error

#

1. Required API Not Enabled

#

Google Cloud requires each service API to be explicitly enabled per project. If you try to create Compute Engine resources without enabling compute.googleapis.com, GCP returns 403.

2. Service Account Missing IAM Roles

#

The Terraform service account doesn't have the IAM role needed for the operation. For example, creating a GKE cluster requires roles/container.admin, not just roles/viewer.

3. Wrong Project Context

#

Terraform is authenticating against project A but the resources belong to project B. The service account may have permissions in one project but not the other.

4. Organization Policy Restrictions

#

An organization-level policy may block certain operations (e.g., external IP creation, specific regions) regardless of IAM permissions.

5. Credential Issues

#

The GOOGLE_APPLICATION_CREDENTIALS environment variable points to an expired or incorrect key file, or you're using Application Default Credentials from the wrong account.

How to Fix It

#

Solution 1: Enable Required APIs

#

Each GCP service requires its API to be enabled. Enable the most common ones:

# Compute Engine
gcloud services enable compute.googleapis.com --project=PROJECT_ID
 
# Kubernetes Engine
gcloud services enable container.googleapis.com --project=PROJECT_ID
 
# Cloud SQL
gcloud services enable sqladmin.googleapis.com --project=PROJECT_ID
 
# Cloud Storage
gcloud services enable storage.googleapis.com --project=PROJECT_ID
 
# IAM
gcloud services enable iam.googleapis.com --project=PROJECT_ID
 
# Cloud Resource Manager
gcloud services enable cloudresourcemanager.googleapis.com --project=PROJECT_ID

You can also enable APIs in Terraform itself:

resource "google_project_service" "compute" {
  project = var.project_id
  service = "compute.googleapis.com"
 
  disable_on_destroy = false
}
 
resource "google_compute_instance" "web" {
  depends_on = [google_project_service.compute]
  # ...
}

Solution 2: Grant the Correct IAM Roles

#

Identify what role the operation needs and grant it:

# Check current roles
gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:terraform@PROJECT_ID.iam.gserviceaccount.com" \
  --format="table(bindings.role)"
 
# Grant Compute Admin
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/compute.admin"
 
# Grant Storage Admin
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/storage.admin"
 
# Grant Kubernetes Admin
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/container.admin"

Common role mappings:

Resource TypeRequired IAM Role
Compute instancesroles/compute.admin
GKE clustersroles/container.admin
Cloud SQLroles/cloudsql.admin
Cloud Storageroles/storage.admin
VPC networksroles/compute.networkAdmin
IAM managementroles/iam.admin
DNS recordsroles/dns.admin
Pub/Subroles/pubsub.admin

Solution 3: Create and Configure a Service Account

#
# Create dedicated Terraform service account
gcloud iam service-accounts create terraform \
  --display-name="Terraform Service Account" \
  --project=PROJECT_ID
 
# Grant Editor role (broad — use specific roles in production)
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/editor"
 
# Create and download key
gcloud iam service-accounts keys create terraform-key.json \
  --iam-account=terraform@PROJECT_ID.iam.gserviceaccount.com
 
# Set credential in environment
export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/terraform-key.json"

Or reference it in the provider block:

provider "google" {
  project     = "my-project-id"
  region      = "us-central1"
  credentials = file("terraform-key.json")
}

Solution 4: Verify Project Context

#

Make sure Terraform is targeting the right project:

provider "google" {
  project = "correct-project-id"  # Verify this matches
  region  = "us-central1"
}

Check which account is active:

# Check active gcloud account
gcloud auth list
 
# Check active project
gcloud config get-value project
 
# Verify service account identity
gcloud auth activate-service-account --key-file=terraform-key.json
gcloud projects get-iam-policy PROJECT_ID

Solution 5: Handle Organization Policy Constraints

#

If an org policy blocks the operation:

# List active org policies
gcloud org-policies list --project=PROJECT_ID
 
# Check specific constraint
gcloud org-policies describe compute.vmExternalIpAccess \
  --project=PROJECT_ID

Work within the constraint or request an exception from your org admin.

Debugging Permission Issues

#

Enable detailed logging to see the exact permission being checked:

export TF_LOG=DEBUG
terraform plan 2>&1 | grep -i "403\|permission\|forbidden"

Use the IAM Policy Troubleshooter in the GCP Console to check whether a specific principal has a specific permission on a specific resource.

Troubleshooting Checklist

#
  1. ✅ Is the required API enabled? (gcloud services list --enabled)
  2. ✅ Does the service account have the right role? (gcloud projects get-iam-policy)
  3. ✅ Is GOOGLE_APPLICATION_CREDENTIALS set to a valid key file?
  4. ✅ Is the provider targeting the correct project?
  5. ✅ Are there organization policy constraints blocking the operation?
  6. ✅ Has the service account key expired? (Keys don't expire, but they can be disabled)
  7. ✅ Are you using Workload Identity Federation? Check the token exchange.

Prevention Tips

#
  • Use least-privilege roles — grant specific roles like roles/compute.instanceAdmin rather than broad roles/editor
  • Enable APIs in Terraform — use google_project_service with depends_on to avoid race conditions
  • Use Workload Identity Federation — avoid long-lived service account keys
  • Document required roles — add a README.md listing what IAM roles the Terraform config needs
  • Test in a sandbox project — validate permissions before applying to production
#

Conclusion

#

The GCP 403 error in Terraform almost always comes down to missing IAM roles or disabled APIs. Check the error message carefully — it usually tells you exactly which permission or API is needed. Enable the API, grant the role, verify your credentials, and re-run terraform plan.

#Terraform#Troubleshooting#DevOps#Error Fix#Infrastructure as Code

Share this article