Your Cloud Run service boots cleanly, scales perfectly, and then smacks right into a permissions wall when trying to talk to Cloud Spanner. The logs say “Permission denied,” and your morning coffee gets cold while you hunt through IAM roles. The fix isn’t hard, but it does require understanding how Cloud Run and Spanner expect to see each other.
Cloud Run runs stateless containers that respond to HTTP requests. Cloud Spanner is Google’s fully managed relational database built for high consistency and massive scale. They speak the same API language, but they live in different trust zones. If your Cloud Run service wants to write or query Spanner, it needs an identity that Spanner trusts. This link is what many teams overlook when setting up production access.
The integration flow looks like this: You assign a service account to your Cloud Run deployment. That account carries credentials that Spanner checks through IAM before it allows queries. Cloud Run handles token rotation automatically, so you never store secrets inside the container. The Spanner client library picks up those tokens from metadata right inside the runtime environment. Once permissions align, your app can execute SQL as if it’s sitting inside Google’s backbone.
To keep it secure, follow some boring but vital steps. Give the Cloud Run service account only the minimum role needed, often spanner.databaseUser. Do not reuse general-purpose service accounts; make one per service. If you have multiple environments, map each to distinct accounts with environment-scoped permissions. Use audit logs in Cloud Spanner to confirm queries originate from expected identities. For external users or automation, tie identity providers like Okta through Cloud IAM with OIDC policies.
Quick answer: To connect Cloud Run to Cloud Spanner, deploy with a specific service account that has Spanner database access. The tokens refresh automatically, avoiding manual key rotation or hardcoded secrets.