Amazon RDS for PostgreSQL
Plain RDS has no clone. A branch here is a snapshot restore: RDS provisions a new instance and hydrates a new volume from a DB snapshot, and the volume is every byte of the database. So branch time grows with the size of the data, this provider declares that it does not branch copy on write, and its branch time is minutes rather than seconds.
That is said first on purpose. RDS for PostgreSQL is where most enterprise
Postgres on AWS lives, so this is the row a buyer is most likely to be reading
about themselves. If your production runs on Aurora PostgreSQL, the
aurora provider clones instead of copying, and
this provider refuses to be pointed at an Aurora cluster rather than quietly
becoming the slow way to do the fast thing.
This provider is in the enterprise edition. Reaching a production RDS instance needs an IAM role somebody with an organization grants, which is the line the editions are drawn on.
database: provider: rds project: acme-production api_key_env: AF_RDS_BRANCH_KEYproject is the RDS for PostgreSQL DB instance identifier that goldens are
built from. It is not a cluster identifier and not an endpoint hostname.
Nothing connects to production. A golden starts as a snapshot RDS takes of the instance you named, so the data never crosses a network this tool is on and no credential for the production database is read.
How a golden and a branch are made
Section titled “How a golden and a branch are made”A golden is a manual DB snapshot, built in five steps:
- Snapshot the source instance.
- Restore that snapshot into a candidate instance.
- Rotate the candidate’s master password and close every login it inherited.
- Mask the candidate, verify it, and close any login the masking created.
- Snapshot the candidate. That snapshot is the golden. The candidate and the first snapshot are then deleted.
A published golden therefore costs snapshot storage and no compute, which is the one place this mechanism is cheaper than a clone.
A branch is an instance restored from a golden snapshot, with its master password rotated and its inherited logins closed before anything is handed a connection string.
What it creates in your account
Section titled “What it creates in your account”| Name | What it is |
|---|---|
af-g-<digest> |
A golden: a manual DB snapshot of a masked, verified candidate. |
af-b-<environment>-<digest> |
One environment’s branch: an instance restored from a golden. |
af-c-<digest> |
A candidate instance, which exists only while a refresh runs. |
af-t-<digest> |
The first snapshot of a refresh, which exists only while it runs. |
Every resource carries an antifailure tag and a digest of the source
instance’s ARN, and every destructive path reads both before it deletes
anything. An instance whose name matches the scheme and whose tags do not is
left alone, not adopted and not deleted. A second source instance in the same
account never lists, adopts or deletes the first one’s resources.
A candidate or first snapshot left behind by a killed refresh is removed by the next refresh once it is six hours old.
Credentials
Section titled “Credentials”Two things are read, both through the engine’s own resolution chain rather than out of the process environment, so every credential this provider uses is declared and appears in the same audit trail as the rest.
AWS_REGION says which region the instance is in. An instance in eu-west-1
does not exist in us-east-1, and asking the wrong region answers that the
instance is not there.
AF_RDS_BRANCH_KEY, or whatever api_key_env names, is not the source
instance’s password. A restored instance inherits the master credential of
the snapshot it came from, which is production’s. This provider rotates every
restored instance’s master password before anything connects, to a keyed hash
of that variable and the instance’s own identifier. The value is
deterministic, so a later command rebuilds a connection string without a
password having been stored anywhere. It is distinct per instance, so a
preview’s credential opens that preview and nothing else. Any high entropy
string will do, and changing it changes every branch’s password.
Rotating the master password is not the whole of it. A restore carries every
other login production had, each with its production password, and a password
change ends no session that already authenticated. So before a golden is
masked, and again before it is published, the provider disables every other
login role in the restored instance’s own catalog, clears its password, and
ends its sessions along with any other session of the administrator. The two
roles AWS reserves, rdsadmin and rdsrepladmin, are left alone. A login the
administrator cannot disable stops publication rather than surviving into it.
The AWS credentials themselves come from the environment, an ECS or EKS Pod Identity credential endpoint, or an EC2 instance role, in that order, and version 2 of the instance metadata service only.
The IAM actions needed are rds:CreateDBSnapshot and rds:DescribeDBInstances
on the source instance, and rds:RestoreDBInstanceFromDBSnapshot,
rds:ModifyDBInstance, rds:AddTagsToResource, rds:DescribeDBSnapshots,
rds:DeleteDBInstance and rds:DeleteDBSnapshot on what it creates.
Where a branch runs, and how it is reached
Section titled “Where a branch runs, and how it is reached”A restored instance is placed in the source instance’s own DB subnet group and VPC security groups, read from the source rather than configured. Left to its defaults, RDS would place it in the account’s default VPC, which is reachable from somewhere production is not. It is never publicly accessible, it takes no backups of its own, and IAM database authentication is off, so the derived password is the only way in.
AF_RDS_SSLMODE defaults to verify-full, which checks the certificate chain
and the hostname, and nothing weaker is accepted. The provider carries AWS’s
published RDS root bundles for the commercial and GovCloud partitions, pinned
by digest in its tests, and uses the one for the source’s partition. The engine
installs the same public bundle inside service and migration containers.
disable is accepted only for a loopback endpoint, which is the test fixture
and nothing else.
What this provider will not do
Section titled “What this provider will not do”It will not branch from an Aurora cluster. A snapshot restore of Aurora
works and copies every byte, where a clone would not. It refuses at startup and
names the aurora provider instead.
It does not implement reset. RDS has no restore in place. Deleting the
instance and restoring again is exactly what the reset capability is defined
not to be, so it is declared false and the conformance suite skips it by name.
It does not take a subset. A candidate is a restore of the source, so there is nothing empty to load a slice into, and a manifest asking for a subset is refused.
It does not implement pooled connection strings or IAM database authentication. RDS Proxy is a separate resource this provider does not create, and IAM authentication is turned off rather than half supported.
Air gapped installations
Section titled “Air gapped installations”RDS is refused under AF_AIR_GAPPED, deliberately. Restoring a snapshot
needs the RDS API, which an air gapped network by definition cannot reach. The
refusal happens before the environment is created and names the manifest line.
Every request the provider makes also goes through the air gap guard, so a
path that reached it anyway could not dial out.
What the tests prove, and what they do not
Section titled “What the tests prove, and what they do not”Part of this provider has run against real AWS, and part has not. On
2026-09-13 a test, TestAgainstRealRDS in ee/engine/db/rds/live_test.go,
drove the provider through the same registration the engine uses against an
RDS for PostgreSQL instance in us-east-1 (db.t4g.micro, Postgres 17.11,
20 GB of gp3 storage, 5000 rows). It ran from an EC2 instance inside the
instance’s VPC that read its role through instance metadata. The run reached a
masked, verified candidate and stopped before a golden was published, so no
golden snapshot, no branch, no isolation check and no branch teardown has run
on AWS.
What that run measured:
- the snapshot of the source took 1 minute 11 seconds, and the restore into a candidate took 5 minutes 4 seconds;
- RDS listed the new master password as pending within a second of
ModifyDBInstance, applied it 1 minute 11 seconds later, and the provider waited for it rather than connecting with the password the restore carried; - the candidate was reached over
verify-full, held exactly the source’s rows, and was masked and verified.
It also found three defects the fake could not show, each fixed since and refused by a test that fails without the fix. The credential path could not read an instance role on an instance that requires version 2 of instance metadata. The rotation was treated as done while RDS still listed the password as pending. And the attestation was stored in tag values whose characters AWS refuses, which is why the golden was not published. The provider with all three fixes has not run against AWS end to end.
Reading the code afterwards found a fourth, which no run had reached. A golden that lost one of its attestation tags, or had one shortened or rewritten, still read as verified and could be branched, because the chunks that remained decoded cleanly as a shorter attestation. The attestation now carries a count of its chunks and a digest of the whole. A golden missing a chunk, or whose chunks do not match the digest, is unverified, and branching from it is refused with the reason.
The conformance suite runs against a fake RDS control plane on localhost backed
by a real Postgres, in ee/engine/db/rds/fakerds. Every line of the provider
runs, and the claims about bytes are checked against bytes: a golden is masked
before it is verified and published only if verification passed, a branch
holds the golden’s rows and is isolated from the golden and from other
branches, and nothing leaks across a run. The fake recomputes every request’s
signature and refuses one that does not match.
The request shapes follow AWS’s published RDS service model, including two
details that are easy to get wrong and invisible to a fake written from the same
assumption: tags are sent as Tags.Tag.N, which is what the official SDK sends,
and an instance’s subnet group is read as the structure AWS returns rather than
as a string.
The verified connection path runs a real PostgreSQL TLS handshake through the driver the provider uses, against a certificate authority the test generates, and refuses a wrong hostname and a wrong signer. The live run’s connections to the source and to the candidate verified certificates RDS issued.
The benchmark does not carry the live run’s timings. It prints UNMEASURED
for every wall clock cell, because one restore at one size says nothing about
how the time grows with the data, and the comparison table says the same. What
it does measure is the provider’s own
work: the control plane calls a branch makes are identical at twenty gibibytes
and at a tebibyte, and a branch opens the database exactly once, to close the
logins the restore inherited.
Copy on write is reported as UNPROVEN. The conformance suite decides it with
a stopwatch, and over this fake a restore is a local
CREATE DATABASE ... TEMPLATE, which copies files, so the declaration of false
would pass for a reason that has nothing to do with RDS. The suite withholds
the verdict instead, and deciding it needs a run against a real account.