Documentation
Google Cloud setup
Enable these products and roles before you paste a service account key. Agents, apps, and MCP servers deploy with Cloud Run in your project.
Paste a Google Cloud service account JSON key under Organization or Project Cloud accounts. Agents, apps, and MCP servers then run in your project on Cloud Run. Saving the key only proves it can sign in — APIs and roles must already be in place.
What gets deployed
All three workloads use Cloud Run. Agents also call Vertex AI at runtime.
| Workload | Service | Google products used |
|---|---|---|
| Agent | gcp-cloud-run | Cloud Storage, Cloud Build, Artifact Registry, Cloud Run, Vertex AI (runtime) |
| App | gcp-cloud-run | Cloud Storage, Cloud Build, Artifact Registry, Cloud Run |
| MCP | gcp-cloud-run | Same as app |
Three Google accounts, not one key
The JSON you paste is only the deployer. Cloud Build and Cloud Run still run as other accounts in the same project. Missing grants on those accounts is the usual “key works, deploy fails” case.
| Who | Looks like | Job |
|---|---|---|
| 1. Deployer (your JSON key) | deployer@PROJECT.iam.gserviceaccount.com | Submit builds, create bucket/repo, create Cloud Run, set IAM |
| 2. Cloud Build worker | PROJECT_NUMBER@cloudbuild.gserviceaccount.com | Build the image and push to Artifact Registry |
| 3. Cloud Run runtime | PROJECT_NUMBER-compute@developer.gserviceaccount.com | Runs the container. Agents need Vertex AI on this account |
1. Turn on these APIs
Console → APIs & Services → Enable APIs, on the same project as project_id in the JSON. These are not enabled when you save the key.
| Name in Google Cloud | API | Why |
|---|---|---|
| Cloud Run | run.googleapis.com | Create, update, delete, and scale the service |
| Cloud Build | cloudbuild.googleapis.com | Build the Docker image from uploaded source |
| Artifact Registry | artifactregistry.googleapis.com | Store the image (repo is created if missing) |
| Cloud Storage | storage.googleapis.com | Staging bucket YOUR_PROJECT_cloudbuild |
| Cloud Logging | logging.googleapis.com | Build logs and runtime logs |
| IAM | iam.googleapis.com | actAs on the runtime account; set invoker |
| IAM Credentials | iamcredentials.googleapis.com | Mint identity tokens to call a private service |
| Cloud Resource Manager | cloudresourcemanager.googleapis.com | Project-level IAM bindings |
| Service Usage | serviceusage.googleapis.com | Needed so you can enable the other APIs |
| Compute Engine | compute.googleapis.com | Default Cloud Run runtime account |
| Vertex AI | aiplatform.googleapis.com | Agents (Gemini). Not required for a plain app or MCP |
| Cloud Monitoring | monitoring.googleapis.com | Optional. Metrics in the console |
Copy-paste (replace YOUR_PROJECT_ID):
gcloud services enable \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
storage.googleapis.com \
logging.googleapis.com \
iam.googleapis.com \
iamcredentials.googleapis.com \
cloudresourcemanager.googleapis.com \
serviceusage.googleapis.com \
compute.googleapis.com \
aiplatform.googleapis.com \
monitoring.googleapis.com \
--project=YOUR_PROJECT_ID2. Roles on the key you paste
Use Artifact Registry Admin, not Writer — Writer cannot create the repository on first deploy. Include both roles/run.invoker (call the service) and roles/aiplatform.user (Vertex / Gemini). Invoker on the project lets the key call every Cloud Run service; you still bind it on each service for allUsers or other callers (step 5).
| Role | Purpose | If omitted |
|---|---|---|
| roles/run.admin | Create, update, delete Cloud Run; set IAM including invoker on the service | run.services.create denied |
| roles/run.invoker | Call Cloud Run (HTTPS). Needed on the key and on whoever hits the URL | 403 when opening or invoking the service |
| roles/cloudbuild.builds.editor | Start Cloud Build jobs | create_build 403 |
| roles/artifactregistry.admin | Get and create the Docker repo | Repository not found |
| roles/storage.admin | Create the staging bucket and upload source | Permission denied on GCS bucket |
| roles/iam.serviceAccountUser | Let Cloud Run use the Compute default account (actAs) | actAs denied |
| roles/logging.viewer | Read build and runtime logs | Logs empty / 403 |
| roles/monitoring.viewer | Cloud Run metrics | Metrics page fails; deploy still works |
| roles/aiplatform.user | Vertex AI / Gemini. On the JSON key for Vertex APIs; also required on the runtime account (step 4) | Agent cannot call Gemini (403 on aiplatform) |
gcloud iam service-accounts create deployer \
--display-name="Deployer" \
--project=YOUR_PROJECT_ID
SA=deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com
PROJECT=YOUR_PROJECT_ID
for ROLE in \
roles/run.admin \
roles/run.invoker \
roles/cloudbuild.builds.editor \
roles/artifactregistry.admin \
roles/storage.admin \
roles/iam.serviceAccountUser \
roles/logging.viewer \
roles/monitoring.viewer \
roles/aiplatform.user
do
gcloud projects add-iam-policy-binding $PROJECT \
--member="serviceAccount:$SA" \
--role="$ROLE"
done3. Cloud Build worker (not your JSON key)
Granting Artifact Registry only on the JSON key does not let Cloud Build push. Grant these on PROJECT_NUMBER@cloudbuild.gserviceaccount.com.
| Role on Cloud Build account | Purpose |
|---|---|
| roles/artifactregistry.writer | Push the image to Artifact Registry |
| roles/storage.admin (or objectAdmin on the staging bucket) | Read the uploaded source tarball |
| roles/logging.logWriter | Write build logs (CLOUD_LOGGING_ONLY) |
PROJECT_NUMBER=$(gcloud projects describe YOUR_PROJECT_ID --format="value(projectNumber)")
CB=$PROJECT_NUMBER@cloudbuild.gserviceaccount.com
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:$CB" --role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:$CB" --role="roles/storage.admin"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:$CB" --role="roles/logging.logWriter"4. Cloud Run runtime account (agents)
Unless you set a custom runtime account, Cloud Run uses the Compute default. The deployer needs Service Account User on it. Agents call Vertex from inside the container, so the runtime account must have roles/aiplatform.user — granting it only on the JSON key is not enough.
| Role | On whom | Purpose |
|---|---|---|
| roles/iam.serviceAccountUser | Deployer, on the Compute default account | Required to create the Cloud Run service (actAs) |
| roles/aiplatform.user | Compute default (runtime) | Gemini / Vertex from inside the agent container |
PROJECT_NUMBER=$(gcloud projects describe YOUR_PROJECT_ID --format="value(projectNumber)")
COMPUTE=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:$COMPUTE" --role="roles/aiplatform.user"
gcloud iam service-accounts add-iam-policy-binding $COMPUTE \
--member="serviceAccount:deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser" \
--project=YOUR_PROJECT_ID5. Who can call Cloud Run (roles/run.invoker)
Cloud Run is private by default. roles/run.admin creates the service; roles/run.invoker is who may send HTTP requests. Bind invoker on the service (or at project level on the JSON key, as in step 2).
| Member | Role | When |
|---|---|---|
| allUsers | roles/run.invoker on the Cloud Run service | Public URL (no auth). Blocked if Domain Restricted Sharing is on |
| serviceAccount:deployer@PROJECT… | roles/run.invoker on the service and/or the project | Private service: the key (or another caller) must be an invoker |
Public (anyone on the internet):
gcloud run services add-iam-policy-binding SERVICE_NAME \
--region=YOUR_REGION \
--member="allUsers" \
--role="roles/run.invoker" \
--project=YOUR_PROJECT_IDPrivate (only the deployer service account):
gcloud run services add-iam-policy-binding SERVICE_NAME \
--region=YOUR_REGION \
--member="serviceAccount:deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/run.invoker" \
--project=YOUR_PROJECT_ID6. Download the JSON and paste it
Organization settings → Cloud accounts → Add credential → GCP service account. Paste the whole file. The key type must be service_account.
gcloud iam service-accounts keys create gcp-key.json \
--iam-account=deployer@YOUR_PROJECT_ID.iam.gserviceaccount.comIf something still fails
| What you see | Cause | Fix |
|---|---|---|
| Verified is green, deploy 403 | Verification only mints a token. It does not check APIs or roles | Enable the APIs and grant all three identities above |
| actAs denied on …-compute@… | run.admin does not include using the default Compute account | Service Account User on that account (step 4) |
| Artifact Registry repository not found | Writer cannot create the repo | artifactregistry.admin + API enabled |
| Build succeeded, image missing | Cloud Build worker cannot push | artifactregistry.writer on the Cloud Build account |
| Cannot make the service public / allUsers | Org policy Domain Restricted Sharing | Keep the service private and grant roles/run.invoker to the caller SA, or relax that org policy |
| 403 on the Cloud Run URL | Caller is not an invoker | roles/run.invoker on the service (step 5) and on the JSON key (step 2) |
| Agent 403 on Vertex / Gemini | aiplatform.user missing on the runtime account | Grant roles/aiplatform.user on PROJECT_NUMBER-compute@… (step 4), not only on the JSON key |