Every VM, Cloud Run service and pipeline calls Google APIs as some service account; least privilege starts here.
A service account is an identity for software, not a person. Its email looks like app-sa@PROJECT_ID.iam.gserviceaccount.com. Like users, it receives IAM roles; unlike users, it has no password.
The safe way to use one is to attach it to a resource: a VM, a Cloud Run service, a function, a GKE workload, a Cloud Build trigger. Code running there gets short-lived tokens automatically from the metadata server; no secret ever touches disk.
Two separate permission questions:
- What can the service account do? Grant roles to it (e.g.
roles/pubsub.publisheron a topic). - Who may use it? To attach a service account to a resource you need
roles/iam.serviceAccountUseron that service account. This stops someone who can deploy from borrowing a powerful identity.
Google also creates default service accounts (e.g. the Compute Engine default PROJECT_NUMBER-compute@developer.gserviceaccount.com), and service agents that Google services use internally. Prefer a dedicated, minimal service account per workload over the defaults.
Service account keys (JSON files) are long-lived credentials that leak easily. Avoid them: use attached accounts inside Google Cloud, impersonation for humans, and Workload Identity Federation for workloads outside. Many organizations block key creation with an org policy.
Example
PROJECT=shop-dev-4821
gcloud iam service-accounts create orders-api --display-name="Orders API"
SA=orders-api@$PROJECT.iam.gserviceaccount.com
# What the workload may do: publish to one topic
gcloud pubsub topics add-iam-policy-binding orders \
--member="serviceAccount:$SA" --role="roles/pubsub.publisher"
# Who may deploy things that run as it
gcloud iam service-accounts add-iam-policy-binding $SA \
--member="group:orders-devs@example.com" --role="roles/iam.serviceAccountUser"
# Attach it to a Cloud Run service
gcloud run deploy orders-api --image=us-docker.pkg.dev/cloudrun/container/hello \
--region=europe-west1 --service-account=$SARemember
- Attach service accounts to resources instead of using key files
- One minimal service account per workload
- serviceAccountUser on the SA controls who can run code as it
Watch out for
- Downloading a JSON key to test locally and committing it to Git.
- Leaving workloads on the default compute service account with broad roles.