Skip to content

Fix Production Deployment Permissions

Problem

When deploying to production via GitHub Actions, you may see this error:

Error: Request to https://firebaserules.googleapis.com/v1/projects/***:test had HTTP Error: 403, The caller does not have permission

This means the production service account (used in PROD_VITE_PUBLIC_SERVICE_ACCOUNT GitHub secret) doesn't have the necessary permissions to deploy Firestore rules.

Solution

Grant the required permissions to the production service account using YOUR user account (not the service account).

Quick Setup (Automated)

bash
cd seedsite
./scripts/setup-prod-permissions.sh

This script will:

  1. Check you're authenticated with your personal account (not service account)
  2. Prompt for the production service account email
  3. Grant all required permissions
  4. Verify the permissions were granted

Manual Setup

If you prefer to do it manually:

Step 1: Authenticate with Your User Account

bash
# Login with your Google account
gcloud auth login

# Set the production project
gcloud config set project seedstart-world

# Verify you're using your user account (not service account)
gcloud auth list
# Should show your email, NOT something ending in @*.iam.gserviceaccount.com

Step 2: Get the Service Account Email

The service account email is in the GitHub secret PROD_VITE_PUBLIC_SERVICE_ACCOUNT:

  1. Go to GitHub repo > Settings > Secrets and variables > Actions
  2. Find PROD_VITE_PUBLIC_SERVICE_ACCOUNT
  3. Copy the JSON content
  4. Find the client_email field - that's your service account email

Or extract it from the JSON:

bash
# If you have the JSON locally
echo 'PASTE_JSON_HERE' | jq -r '.client_email'

Step 3: Grant Permissions

bash
# Set variables
SERVICE_ACCOUNT="YOUR_SERVICE_ACCOUNT_EMAIL@seedstart-world.iam.gserviceaccount.com"
PROJECT_ID="seedstart-world"

# Grant Firebase Hosting Admin (required for hosting deployment)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/firebasehosting.admin"

# Grant Firebase Rules Admin (required for Firestore rules deployment)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/firebaserules.admin"

# Grant Cloud Datastore User (for Firestore operations)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/datastore.user"

# Grant Datastore Index Admin (required for Firestore indexes deployment)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/datastore.indexAdmin"

Step 4: Verify Permissions

bash
gcloud projects get-iam-policy seedstart-world \
  --flatten="bindings[].members" \
  --filter="bindings.members:YOUR_SERVICE_ACCOUNT_EMAIL" \
  --format="table(bindings.role)"

You should see:

  • roles/firebasehosting.admin
  • roles/firebaserules.admin
  • roles/datastore.user
  • roles/datastore.indexAdmin

After Fixing Permissions

Once permissions are granted:

  1. Re-run the failed workflow in GitHub Actions, or
  2. Create a new release tag to trigger a fresh deployment:
    bash
    git tag -a v1.0.1 -m "Fix production deployment"
    git push origin v1.0.1

The deployment should now succeed for both hosting and Firestore rules.

Alternative: Use Firebase Admin Role (Simplest)

If you want to grant all Firebase permissions at once:

bash
gcloud projects add-iam-policy-binding seedstart-world \
  --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" \
  --role="roles/firebase.admin"

This grants all Firebase-related permissions, including hosting, rules, and Firestore operations.

Internal docs — access restricted via Cloudflare Zero Trust.