Postgres on Google Cloud / Lesson 2 of 8
The design you are about to learn looks like extra work until you see what it replaces.
Here is how almost everyone connects to a database they did not put on a cloud: a hostname, a port, a username, a password, and — if someone was being careful — a firewall rule listing the IP addresses allowed to try.
That arrangement has three separate problems, and the managed-Postgres design on Google Cloud exists to solve all three at once.
A database password is a string. Whoever holds the string is the user. It
does not expire, it is not tied to a person, and it leaves no trace of who used
it. Once it is in a .env file it is also in a backup, a container
image, a terminal scrollback, a screenshot in a support ticket, and the laptop
of everyone who ever ran the app locally.
Rotating it means finding every copy. Teams do not rotate database passwords for exactly this reason.
An allowlist says traffic from this address may connect. It says nothing about who sent it. Anything sharing that egress address — another team's job, a compromised container, a NAT gateway shared by an entire cloud region — inherits the permission. And egress addresses move, so the list is either permanently stale or permanently too wide.
When something goes wrong and you ask who ran the statement, an allowlist plus a shared password can tell you an IP and a role name. That is not an answer.
Google Cloud's managed Postgres offers a different arrangement, and the whole of this course is learning to operate it:
| The familiar way | The way you are learning | |
|---|---|---|
| Who may reach the instance | Anyone at an allowed IP address | Anyone holding roles/cloudsql.client — an identity, not a
location |
| What proves identity | A long-lived password string | A short-lived OAuth 2.0 access token, minted from your Google identity and refreshed automatically |
| Transport security | TLS, if configured, with certificates someone has to manage | Mutual TLS with ephemeral client certificates, issued and rotated for you |
| Audit trail | An IP address and a role name | A named Google principal on every connection |
| Offboarding | Rotate the password, update every consumer | Remove the person from a group |
The feature that does this is called IAM database authentication. The database user is your Google identity. The password field is filled with an access token that a piece of client-side software fetches and refreshes on your behalf.
A leaked connection string is, by itself, useless. There is no secret in it. Host, port, database name and username can go in a README. Without a Google identity holding the right role, none of it connects.
Access tokens are valid for one hour (Google Cloud docs). A connection pool that lives for days would break constantly if you fetched a token once at startup. So you do not handle tokens at all. Two pieces of Google software do it for you, and choosing between them is the only decision here:
psql,
DBeaver, DataGrip, an ORM that only knows how to speak to
localhost. This is
lesson 3.Google calls this arrangement automatic IAM database authentication, to distinguish it from the manual kind where you fetch the token yourself and paste it into the password field. Manual exists. It is for one-off scripting, and it stops working after an hour.
The instinct to write your own token-refresh wrapper is strong and wrong. Token refresh, certificate rotation, instance IP discovery and connection retry are all handled, and the failure modes when they are handled badly are intermittent and awful to debug.
IAM authentication decides whether you may open a connection. It
decides nothing about what you may then do with it. Google's documentation puts
it flatly: when an IAM user is added to a database, by default the new
database user has no privileges to any database
(Google
Cloud docs).
So you will connect successfully and be unable to read a single row, and that
is the system working correctly. Table permissions are ordinary PostgreSQL
GRANTs and have nothing to do with Google.
Lesson 4 is about telling these two apart,
because every confusing error in this course comes from mistaking one for the
other.
A developer pastes a full connection string into a public issue. How bad is it?
Under IAM database authentication there is no password in the string. Host, port, database and username are configuration, not credentials. Worth tidying up; not an incident.
This only holds if the instance genuinely has no password users left on
it. A connection string containing password= is exactly as bad
as it looks.
Why does a long-running service need the proxy or a connector rather than a token it fetched at startup?
One hour. New connections after that fail, which on a pooled service looks like the database intermittently rejecting logins under load — the pool is simply opening a replacement connection with a dead token.
From memory: name the three weaknesses of "password plus IP allowlist" that this design replaces.
1. The password never expires and cannot practically be rotated. 2. The allowlist grants access to a network position rather than to anyone in particular. 3. The audit trail records an address, not a person.