Dynamic Secrets Explained: Why Rotation Isn't Enough

Static database credentials get copied everywhere and never expire. See how centralizing secrets makes automated rotation possible, and why dynamic secrets that mint a short-lived account for each consumer are the stronger fix.

Dynamic Secrets Explained: Why Rotation Isn't Enough
Most production Postgres instances have an application role whose password was set when the database was initialized. That password often has no expiry at all, and it stays the same for years. This is the default mode for database access almost everywhere, and it is worth asking what it costs.
A credential is anything you present to prove who you are, whether you are a person or a machine, and what you are allowed to access. When one long-lived credential is shared by everything that touches the database, four problems follow. Automated secret rotation solves some of them. Dynamic secrets solve the rest.
The default: one static credential, shared everywhere
Picture a typical setup. An API serves requests. A batch worker runs jobs. Several developers connect from their laptops. Every one of them has an environment variable holding the database URL, a username, and a password. When any of them connects, it presents the same username and the same password, Postgres checks the hash, and it hands back full access.
From the database's point of view, the API, the worker, CI, and every developer are the same user. That single fact is the root of everything that goes wrong next.
Four problems with static credentials
Copies. The same value lives in the API's environment, the worker's environment, every developer laptop, CI, and Kubernetes. Onboarding a new developer means handing them another copy. This is secret sprawl, and once a credential has spread this far nobody can say with confidence where every copy lives.
Identity. Because everything shares one username and password, you cannot tell who is accessing the database. If an attacker shows up in the logs as the application role, you have no way to narrow it down to a developer, a pipeline, or the API itself. Revoking access means revoking it everywhere at once.
No expiry. A credential that leaked a year ago is still valid today. There is no built-in point at which the exposure ends.
Offboarding. Someone who leaves the team has seen the password, and the password still works. Rotation would fix that, but rotation is painful precisely because of the sprawl problem: you have to update every copy, and you do not know where all of them are.
Step one: centralize the source of truth
You cannot rotate a credential you cannot find. So the first move is to solve sprawl, and the way to do that is to change how consumers get the value.
Today each consumer holds its own copy as its own source of truth. Instead, move the credential into a secrets manager and turn the API, the worker, CI, and the developers into consumers of that central store. When the value changes in one place, it propagates everywhere it needs to be: into Kubernetes, into CI pipelines, and onto developer machines through the Infisical CLI.
Centralizing does not shorten the life of the credential on its own. What it does is make rotation possible, because now there is exactly one place to update. For a deeper look at how this pattern plays out across clusters, the Kubernetes secrets architecture video walks through it end to end.
Step two: automated secret rotation
With every consumer reading from the secrets manager, automated secret rotation becomes straightforward. Give the secrets manager a connection to Postgres with permission to change passwords, then create two database users for it to manage.
The secrets manager alternates between the two users. Every 30 days, or whatever interval you set, it changes the password on one user and marks it active while the other stays valid for consumers still picking up the change. Everything downstream reads whichever username and password are current. The PostgreSQL credentials rotation doc covers the exact setup.
What rotation fixes, and what it does not
Rotation shrinks the window. A leaked credential is now good for at most one rotation period rather than forever, and sprawl is solved because no consumer holds a long-lived copy.
But the paradigm has not changed. Every consumer still authenticates as the same user, so the identity problem is still there. And 30 days is a long time. You have made the static credential shorter-lived, but it is still a static credential that a lot of things share.
Step three: dynamic secrets
Dynamic secrets are fundamentally different. Instead of a long-lived credential that is copied out to consumers, each consumer asks for a credential and the secrets manager creates one for it on the spot, scoped to that consumer and valid for a short, fixed window. An hour or two is typical. The credential is spun up when it is needed and torn down when the time is up.
The flow looks like this. When the worker pod starts, it authenticates to the secrets manager using its own machine identity, in this case through Kubernetes auth. It proves who it is and requests a lease. The secrets manager creates a brand-new PostgreSQL user, hands back the username and password, and sets the time to live. The worker uses that account to reach the database. The API does the same thing with its own identity. Developers do the same from their laptops, requesting a lease from the CLI.
One account per consumer, time-bound, minted on the fly. Ephemeral and dynamic.
How dynamic secrets dissolve the original problems
Go back to the four problems. The shared copy is gone, because there is nothing long-lived to copy. Revocation stops being a project, because no consumer holds a standing account. When access is needed, an account is created, and shortly afterward it is destroyed.
Identity is solved too. Every lease is tied to the identity that requested it, so the audit log shows exactly which workload or person asked for database access and when.
Offboarding becomes a single action. Remove the person's access to the secrets manager and they can no longer be brokered an account. Even if they remember a password from a previous lease, it stopped working when that lease expired.
Two things to be honest about
First, the shared credential did not vanish. The secrets manager still holds a username and password for Postgres so that it can create and drop accounts. What has changed is the trust boundary: instead of that credential living in a dozen places, it lives in one place, encrypted at rest, and you are trusting your secrets manager to protect it. That is a much better position than sprawl, but it is a decision worth making with eyes open.
Second, dynamic secrets change how applications handle connections. If your service opens a connection pool and holds it for hours, something has to handle renewing the lease before it expires. When the lease ends, the role is dropped. A pool that tries to reconnect with the old username and password will fail. Either the application code renews leases, or a sidecar or agent does it on the application's behalf.
From static to dynamic, in three moves
The starting point was one shared application credential spread across an API, a worker, CI, and every developer laptop. Rotation and revocation were hard, and knowing who had access was close to impossible.
Centralizing secrets in a secrets manager solved sprawl and made every consumer a reader of a single source of truth. Automated rotation then removed the long-lived credential from those consumers by cycling two managed database users on a schedule. Dynamic secrets went one step further: consumers request short-lived accounts minted for them alone, and those accounts disappear on their own.
The result is a much smaller blast radius, credentials that are useless minutes after they stop being needed, and a clear answer to the question of who touched the database. For a broader tour of where dynamic secrets sit in the platform, see What is Infisical.
Starting with Infisical is simple, fast, and free.