Overview
This guide covers GCP-specific integration for CrewAI Platform deployments on Google Kubernetes Engine (GKE). It focuses on configuring GCS for object storage, Artifact Registry (or registry-less Bucket Deployment) for crew image builds, Cloud SQL for PostgreSQL, and optionally Secret Manager — all authenticated via GKE Workload Identity Federation (no static keys).This guide assumes you have:
- A GKE cluster running Kubernetes 1.28+ with Workload Identity enabled
gcloudCLI andkubectlconfigured- Helm 3.10+ installed
- Basic familiarity with GCP services (Cloud SQL, GCS, Artifact Registry)
Prerequisites
Before configuring CrewAI Platform, ensure these GCP components are in place: CrewAI Platform supports AMD64 (x86_64) Kubernetes worker nodes. ARM64 (aarch64) worker nodes are not currently supported. For full platform requirements, see the Requirements Guide.Required GCP Infrastructure
Required GCP APIs
Enable the following APIs in your project before proceeding:Pre-Install Checklist
Before runninghelm install, confirm the following are complete:
- GKE cluster with Workload Identity enabled
- Gateway API enabled (
gcloud container clusters update --gateway-api=standard) - All four Cloud SQL databases created:
crewai_plus_production,crewai_plus_cable_production,crewai_plus_oauth_production,wharf - SQL privileges granted to IAM user on all four databases
- GSA IAM roles bound (roles/cloudsql.client, roles/cloudsql.instanceUser, roles/iam.workloadIdentityUser, roles/storage.objectAdmin)
-
GCS_IAM_SIGNING: "true"set inenvVars(required when using Workload Identity — omitting this causesGoogle::Cloud::Storage::SignedUrlUnavailableat runtime)
Step 1: Create the GCP Service Account
All CrewAI workloads (web, worker, buildkit) share a single GCP Service Account (GSA) that is mapped to the Kubernetes ServiceAccount via Workload Identity. This GSA needs permissions for GCS, Artifact Registry, Cloud SQL, and optionally Secret Manager.Step 2: Grant IAM Roles
Bind the required IAM roles to the service account. Each role maps to a specific CrewAI requirement:For tighter security, scope
roles/storage.objectAdmin and roles/artifactregistry.writer to specific resources using --condition flags or bucket/repo-level IAM instead of project-level bindings.The node pool GCE SA binding is separate from the GSA bindings. The platform injects a short-lived GAR token at deploy time for immediate pulls, but the node SA provides reliable fallback when crew pods are rescheduled after the token expires.Step 3: Bind Workload Identity
Create the IAM policy bindings that allow the Kubernetes ServiceAccounts to impersonate the GCP Service Account. Two bindings are needed: one for the platform namespace (web, worker, buildkit daemon) and one for the crews namespace (build pods that push images to GAR):Post-Install: Annotate the Crew Namespace
After the initial Helm install (which creates thecrewai-crews namespace automatically), annotate the default ServiceAccount in the crews namespace so build pods can authenticate to GAR via Workload Identity:
kubectl create namespace crewai-crews, then annotate immediately.
ArgoCD users: This step requires a two-Application pattern because the
crewai-crews namespace does not exist until after the first sync completes. See the ArgoCD Deployment Guide.Cloud SQL for PostgreSQL
CrewAI Platform requires PostgreSQL 16+ for production deployments.Cloud SQL Instance Sizing
Minimum recommended specifications based on CrewAI workload characteristics:Create the Cloud SQL Instance
Create Databases and User
CrewAI requires four databases — primary, cable, OAuth, and Wharf for OTLP trace storage:DB_PASSWORD is needed.
Step 1: Enable IAM authentication on the Cloud SQL instance:
postgres superuser (recommended) or an existing admin user. You can connect via gcloud sql connect or from inside a running pod:
GSA_NAME@GCP_PROJECT_ID.iam with your actual IAM user, e.g., crewai-platform@jr-testing-487713.iam):
ALTER TABLE, DROP COLUMN) require the executing user to be the owner of the table — GRANT ALL PRIVILEGES is not sufficient. If the databases were initially set up by a different user (e.g., postgres or a password-based crewai user), the IAM user will not own existing tables, and future upgrade migrations that modify table structure will fail.
The pre-upgrade migration hook automatically detects this condition and will report the affected tables with the exact SQL to fix them. To prevent this from blocking your first upgrade, transfer ownership proactively.
Connect to the database as the postgres superuser using the same host and port the application uses:
crewai-platform@your-project.iam):
Use the
postgres superuser for these commands. Only the current owner or a superuser can transfer table ownership. A non-superuser like crewai can run GRANT commands on objects it owns, but cannot run ALTER TABLE ... OWNER TO for tables it doesn’t own.Cloud SQL Auth Proxy (Recommended)
The Helm chart includes a built-in Cloud SQL Auth Proxy sidecar. When enabled, it runs alongside the web, worker, OAuth, Wharf, and job containers, authenticating via Workload Identity. The app connects to127.0.0.1 through the proxy.
autoIamAuthn: false and provide DB_PASSWORD via secrets.
Helm Database Configuration
For IAM authentication (autoIamAuthn: true):
DB_PASSWORD is needed — the Cloud SQL Auth Proxy handles authentication automatically via Workload Identity.
For password-based authentication (autoIamAuthn: false):
Google Cloud Storage for Object Storage
CrewAI Platform uses GCS for storing crew artifacts, tool outputs, and user uploads. With Workload Identity, no static credentials are needed.Create GCS Bucket
Helm Configuration for GCS
google-cloud-storage gem uses Application Default Credentials (ADC), which are automatically provided by GKE Workload Identity.
Artifact Registry for Container Images
CrewAI Platform requires Artifact Registry for storing crew automation container images. When users create and deploy crews, CrewAI builds container images and pushes them to your registry.Repository Requirements
Create Artifact Registry Repository
GCP_REGION-docker.pkg.dev. For example: us-central1-docker.pkg.dev/your-project/crewai.
Valid repository URIs (set in CREW_IMAGE_REGISTRY_OVERRIDE):
us-central1-docker.pkg.dev/your-project/crewaius-docker.pkg.dev/your-project/crewaieurope-west1-docker.pkg.dev/your-project/crewai
Helm Configuration for Artifact Registry
CREW_IMAGE_REGISTRY_OVERRIDE when it matches the *-docker.pkg.dev pattern and sets GCP_ARTIFACT_REGISTRY_HOST automatically. BuildKit pods then obtain short-lived access tokens from the GKE metadata server to authenticate pushes.
How Crew Pods Pull Images from GAR
When a crew is deployed, the platform automatically injects a fresh short-lived GAR access token into the crew namespace’s image pull secret. This ensures crew pods can immediately pull their built images from Artifact Registry without any manual credential management. How it works:- Build pods push images to GAR via Workload Identity (using the GSA’s
roles/artifactregistry.writer) - At deploy time, the platform fetches a fresh GAR access token from the GKE metadata server and merges it into the registry pull secret
- Crew pods use this enriched pull secret to pull their images from GAR
CREW_IMAGE_REGISTRY_OVERRIDE.
Enable GKE Node Image Pulls from GAR (Defense-in-Depth)
As a fallback for scenarios where a crew pod is rescheduled to a new node after the injected token has expired, the node pool’s compute service account must haveroles/artifactregistry.reader. This is configured in Step 2: Grant IAM Roles.
Verifying Artifact Registry Access
Test that the Workload Identity binding is working:Bucket Deployment — Registry-Less Image Delivery
Bucket Deployment is an alternative to Artifact Registry that eliminates the need for any container registry. Instead of pushing built crew images to a registry, the platform stores them as compressed OCI tarballs in a GCS bucket and loads them directly into the container runtime on each Kubernetes node before deployment.Bucket Deployment and Artifact Registry are mutually exclusive for crew image delivery. Choose one approach based on your requirements. Both still use BuildKit to build images — the difference is where the built image is stored and how it reaches the nodes.
When to Use Bucket Deployment
How Bucket Deployment Works
The workflow has four phases: 1. Build — When a crew is deployed, BuildKit builds the container image as usual, but instead of pushing it to a registry, it outputs an OCI tarball. The tarball is compressed withgzip and uploaded to a GCS bucket using a Workload Identity access token.
2. Preload — A temporary Kubernetes DaemonSet is created, placing one pod on every node in the cluster. Each pod downloads the tarball from GCS, decompresses it, and imports it into the node’s containerd runtime using ctr images import. This makes the image available to the kubelet as if it had been pulled from a registry.
3. Deploy — Once all nodes have the image loaded, the crew is deployed via Helm with imagePullPolicy: Never and no imagePullSecrets. The kubelet finds the image in its local store and starts the pod normally.
4. Cleanup — The preloader DaemonSet is deleted. The imported images remain in the node’s containerd store.
Prerequisites
Before enabling Bucket Deployment, ensure you have:- GCS bucket — A dedicated bucket for storing crew image tarballs
- IAM permissions — The Workload Identity GSA must have
roles/storage.objectAdminon the image bucket (for both upload and download) - Workload Identity — Already configured per Step 3
- BuildKit — Enabled in the Helm chart (
buildkit.enabled: true)
If you already configured
roles/storage.objectAdmin at the project level for GCS object storage (see Step 2), the same binding covers the image bucket. No additional IAM configuration is needed — skip to Create the Image Bucket.Create the Image Bucket
Create a dedicated GCS bucket for crew image tarballs. This bucket is separate from the general-purposeGCS_BUCKET used for crew artifacts and uploads.
roles/storage.objectAdmin to the general-purpose bucket (rather than project-level), grant access to the image bucket separately:
Lifecycle policies are not recommended for the image bucket. Image tarballs are actively referenced by running crews and must remain available for node rescheduling or cluster scaling events. If you need cleanup, delete tarballs only after the corresponding crew has been undeployed.
Helm Configuration for Bucket Deployment
Set the following environment variables in your Helm values to enable Bucket Deployment:Configuration Reference
The
CONTAINERD_SOCKET_PATH and CTR_HOST_PATH defaults are correct for standard GKE nodes (Container-Optimized OS and Ubuntu). Override them only if your cluster uses custom node images with non-standard containerd paths.What Changes from Artifact Registry Mode
When switching from Artifact Registry to Bucket Deployment, the following Helm values change:Verifying Bucket Deployment
After deploying a crew, verify the bucket deployment pipeline: 1. Check the image tarball was uploaded:imagePullPolicy: Never:
Secret Manager Integration (Optional)
GCP Secret Manager provides centralized secret management for CrewAI Platform.Which Secrets to Store
Store in Secret Manager (sensitive, need rotation):DB_PASSWORD- Database credentials (if not using IAM auth)SECRET_KEY_BASE- Rails secret keyGITHUB_TOKEN- For private repository access- Auth provider secrets (
ENTRA_ID_CLIENT_SECRET,OKTA_CLIENT_SECRET, etc.)
DB_HOST,DB_PORT,DB_USER,POSTGRES_DBGCS_PROJECT_ID,GCS_BUCKETAPPLICATION_HOST,AUTH_PROVIDER
External Secrets Operator Setup
CrewAI uses External Secrets Operator (ESO) to sync secrets from Secret Manager to Kubernetes. Install ESO (if not already installed):Helm Configuration for Secret Manager
External Access (Gateway API or Ingress)
GKE provides built-in support for the Kubernetes Gateway API, which is the recommended way to expose services externally.The NGINX Ingress Controller was retired in March 2026. For new GKE deployments, Gateway API is recommended over traditional Ingress resources. Existing Ingress configurations continue to work.
Option 1: Gateway API (Recommended)
GKE ships with built-in GatewayClass resources — no additional controller installation is needed, but Gateway API support must be enabled on the cluster.Enable Gateway API on GKE
For most single-region production deployments, the regional class reduces latency by keeping traffic within a single region and avoids the global load balancer premium. Choose global only if you require multi-region failover or Cloud CDN integration.
Merge all
web: settings under a single top-level web: key in your final values.yaml. Helm silently drops all but the last occurrence of a duplicate top-level key.Helm Configuration
pathPrefix: "/" and specify the hostname:
When using a dedicated OAuth hostname, add it to the Gateway TLS certificate (or create a separate certificate map entry) and update DNS to point to the same Gateway IP.
The Helm chart automatically creates a GKE
HealthCheckPolicy that configures the load balancer to use /health as the health check path. Without this, GKE’s health probes use the pod IP as the Host header, which Rails’ HostAuthorization middleware blocks — causing unconditional drop overload errors. This is handled automatically; no manual configuration is needed.Option 2: GCE Ingress (Native GKE)
If you prefer traditional Ingress resources:Option 3: NGINX Ingress Controller (Deprecated)
GKE does not include a pre-installed NGINX Ingress Controller. Using
className: nginx without first installing the controller will create an Ingress resource that never receives an external IP. For new GKE deployments, use Option 1 (Gateway API) or Option 2 (GCE Ingress).Complete GCP Deployment Example
If using WorkOS authentication, place
WORKOS_API_KEY under envVars: — NOT under secrets:. See the WorkOS SSO guide for the full explanation and the correct YAML placement. This is a known chart limitation.The
image.registries section is required when installing via direct Helm (helm install ... oci://registry.crewai.com/...). It provides credentials for pulling platform images (busybox, redis, buildkit, etc.) from the Replicated proxy at images.crewai.com. Use the same email and license token you used for helm registry login registry.crewai.com.When installing via Replicated KOTS, these credentials are injected automatically and image.registries is not needed.Bucket Deployment Variant
To use Bucket Deployment instead of Artifact Registry, modify theenvVars section in the example above:
When using Bucket Deployment, Artifact Registry IAM roles (
roles/artifactregistry.writer, roles/artifactregistry.reader) are not needed. The roles/storage.objectAdmin role on the image bucket handles both upload (from build pods) and download (from preloader pods). The Crews namespace Workload Identity binding is still required — build pods use it to obtain GCS access tokens for uploading image tarballs.Troubleshooting GCP-Specific Issues
Workload Identity Not Working
Symptoms: Pods get403 Forbidden or could not retrieve default credentials errors.
Verify Workload Identity is enabled on the cluster:
GCS Signed URL Errors
Symptoms: Logs showGoogle::Cloud::Storage::SignedUrlUnavailable: Service account credentials 'issuer (client_email)' is missing when deploying crews.
This happens when Workload Identity is used but IAM-based URL signing is not enabled. The google-cloud-storage gem cannot sign URLs without a private key; with Workload Identity, the IAM signBlob API must be used instead.
Fix:
- Ensure
GCS_IAM_SIGNING: "true"is set inenvVars - Grant the
roles/iam.serviceAccountTokenCreatorrole to the GSA:
- Redeploy the Helm chart
GCS Access Denied
Symptoms: Logs showGoogle::Cloud::PermissionDeniedError for storage operations.
Cloud SQL Connection Failures
Symptoms: Pods showconnection refused on 127.0.0.1:5432.
Check the Cloud SQL Proxy sidecar is running:
Cloud SQL IAM Authentication Failures
Symptoms:fe_sendauth: no password supplied or issue connecting with your username/password.
“no password supplied” — autoIamAuthn is not enabled in your Helm values:
- IAM authentication flag on the instance (most common miss — off by default):
- IAM database user exists:
- GSA has required IAM roles:
- DB_USER is in IAM format (in Helm values):
- SQL privileges granted — the IAM user must have been granted access to the databases via
GRANT ALL PRIVILEGES(see “Create Databases and User” section above)
Cloud SQL IAM: Table Ownership Errors During Upgrades
Symptoms: Rails migrations fail withPG::InsufficientPrivilege: ERROR: must be owner of table <table_name>.
Root cause: PostgreSQL DDL operations (ALTER TABLE, DROP COLUMN, ADD INDEX, etc.) require the executing user to be the owner of the table. When using IAM authentication, the IAM database user typically does not own tables that were created by the postgres superuser or a previous password-based user. GRANT ALL PRIVILEGES grants read/write access but does not transfer ownership.
Fix: Connect as the postgres superuser and transfer ownership of all tables, sequences, and views to the IAM user. See Step 5 of the IAM authentication setup for the exact SQL commands.
Prevention: Run the ownership transfer SQL during initial IAM auth setup (Step 5), before the first Helm upgrade.
Artifact Registry Push Failures
Symptoms: Crew deployments fail withunauthorized or denied during image push.
Verify the GSA has Artifact Registry write access:
Artifact Registry Pull Failures (Crew Pods)
Symptoms: Crew pods increwai-crews namespace show ImagePullBackOff or ErrImagePull with 403 Forbidden when pulling from *-docker.pkg.dev.
This can have multiple causes:
1. Wrong pull secret name: The crew pod references a pull secret that doesn’t exist or has empty credentials.
{"auths":{}} (empty), the Helm chart’s image.registries may not be configured. See the Complete Example.
2. Node pool compute SA lacks GAR read access:
Build Pod Image Pull Failures
Symptoms: Build pods in the platform namespace showErrImagePull for images from images.crewai.com.
This means the registry pull secret lacks Replicated proxy credentials. Verify:
images.crewai.com is not in the auths section, add Replicated proxy credentials to image.registries in your Helm values and redeploy (see the Complete Example).
Secret Manager Access Denied
Symptoms: ExternalSecret showsSecretSyncedError.
Bucket Deployment: Upload Failed
Symptoms: Crew deployment fails during the build phase withBucket upload failed in the build pod logs.
Check the build pod logs:
-
Missing
IMAGE_BUCKET_NAME— The environment variable is not set. Verify it appears in your Helm values underenvVars. - Bucket does not exist — Verify the bucket exists:
- Missing IAM permissions — The Workload Identity GSA needs
roles/storage.objectAdminon the image bucket:
- Metadata server unreachable — Build pods obtain access tokens from the GCE metadata server. If the logs show
Failed to get access token from metadata server, verify that Workload Identity is bound for the crews namespace (see Step 3).
Bucket Deployment: Preloader Timeout
Symptoms: Crew deployment hangs at the preload phase. The preloader DaemonSet pods are not reaching Ready state. Check the preloader DaemonSet and pod status:- Image tarball not found in bucket — The preloader downloads from the bucket. If the build phase failed silently or the object name doesn’t match:
- GCS download permission denied — The preloader pods run in the platform namespace and use the platform KSA’s Workload Identity. Verify the GSA has read access to the image bucket.
-
containerd socket not accessible — The preloader mounts the host’s containerd socket. If the node uses a non-standard socket path, set
CONTAINERD_SOCKET_PATHin your Helm values. Check the default path:
ctrbinary not found — The preloader uses the host’sctrbinary from/usr/bin. If it’s in a different location on your nodes, setCTR_HOST_PATHin your Helm values:
Bucket Deployment: ErrImageNeverPull
Symptoms: Crew pods showErrImageNeverPull status after deployment.
This means Kubernetes is set to imagePullPolicy: Never but the image is not present in the node’s containerd store. This can happen if:
- Preloader didn’t complete on this node — The node may have been added to the cluster after the preloader DaemonSet ran. Redeploy the crew to trigger a fresh preload cycle.
- containerd image was garbage collected — containerd may have cleaned up unused images. Redeploy the crew.
-
Image name mismatch — The
CREW_IMAGE_REGISTRY_OVERRIDEvalue must be consistent across build, preload, and deploy. Verify:
ctr output.