Hi @grill,
Your setup worked for a specific reason, and it has some edge cases.
With archive_command = 'pgbackrest ... archive-push %p', pgBackRest copies the WAL segments into the repo still encrypted. You’ve turned off archive-header-check and checksum-page, so pgBackRest never tries to read what’s inside them. It treats them as opaque files.
On restore, archive-get puts the same encrypted segments back into pg_wal. The restored server then decrypts them using the WAL key file in $PGDATA/pg_tde/, which came back with the backup and your principal key in Vault.
As long as the restored key file has a key for every LSN range you replay, recovery works. That’s what you’re seeing.
The restored WAL key file is a snapshot taken at backup time. The archive, though, keeps receiving WAL that may have been encrypted with keys created after that backup. For example, a new WAL key is generated when the server restarts, or when WAL encryption is toggled. If you do PITR from backup N to a point after one of those events, the restored cluster may not have the key for those segments, and recovery fails.
The same coupling shows up in a few other places:
- Standbys, other clusters, and verification tools. Anything that reads the archive needs this cluster’s key state. That includes a standby built from another backup, a restore to a different host or cluster, and
pgbackrest verify or other tooling.
- Principal key rotation. Old principal key versions must stay available in Vault for as long as archived WAL or backups depend on them.
The wrappers remove that coupling:
pg_tde_archive_decrypt stores plain WAL in the repo.
pg_tde_restore_encrypt re-encrypts the WAL with the restoring cluster’s current key.
The archive no longer depends on any particular snapshot of pg_tde/, so this is the configuration we test and support. Because the WAL in the repo is then unencrypted at the pg_tde level, please turn on pgBackRest repository encryption (repo1-cipher-type=aes-256-cbc plus repo1-cipher-pass) so the archive is still encrypted at rest.
As WAL encryption matured, the limitations page was updated to reflect what we actually test. It isn’t a sign that your current restores are wrong. It marks the line between what we’ve validated and a setup that works in the common case.
You can try to check on yourself:
- Take a full backup.
- Restart PostgreSQL.
- Generate some WAL and run
SELECT pg_switch_wal();.
- Restore that backup with
--type=time to a point after the restart.
If this succeeds in your environment, please share the result. We’d like to know.
For production, we recommend switching to:
archive_command = 'pg_tde_archive_decrypt %f %p "pgbackrest --stanza=main archive-push %%p"'
restore_command = 'pg_tde_restore_encrypt %f %p "pgbackrest --stanza=main archive-get %%f \"%%p\""'
Warm regards,
N.