New to KubeDB? Please start with the KubeDB documentation.
Postgres Transparent Data Encryption (TDE)
Transparent Data Encryption (TDE) encrypts a Postgres cluster’s data at rest,
so the files on disk (table data, indexes, and optionally the WAL) are unreadable
without the encryption keys, even if someone gains access to the underlying
storage. KubeDB implements TDE using the Percona pg_tde
extension.
TDE is complementary to TLS/SSL, which protects data in transit. You can enable both.
Prerequisite: a Percona distribution version
pg_tde and its tde_heap access method are only available on Percona Server
for PostgreSQL 17.x, a patched build. TDE cannot be enabled on a community
PostgreSQL image. Use a PostgresVersion whose spec.distribution is Percona
and whose spec.tde.supported is true:
$ kubectl get postgresversion 17.9-percona -o jsonpath='{.spec.distribution} {.spec.tde.supported}{"\n"}'
Percona true
The admission webhook rejects spec.tde on any version that does not advertise
TDE support.
How it works
pg_tde uses a two-tier key hierarchy:
- Principal key (one per database): generated by
pg_tdeand stored in an external Key Management System (KMS). It never lives in the data directory. - Internal keys (one per relation file): stored encrypted, wrapped by the
principal key, inside
$PGDATA/pg_tde/. These encrypt the actual data files.
KubeDB’s Postgres operator wires everything up for you: it registers the key
provider, sets the principal key on first boot, mounts the KMS credentials into
the pod (outside the data directory), and injects pg_tde into
shared_preload_libraries. Replicas are seeded with pg_tde_basebackup and
failback uses pg_tde_rewind, so encryption is transparent across HA and
failover.
Key providers
You configure exactly one key provider under spec.tde.keyProvider:
| Provider | Field | Notes |
|---|---|---|
| HashiCorp Vault | keyProvider.vault | Recommended for HA and DR. A global provider. |
| KMIP server | keyProvider.kmip | For appliance-based KMS (Thales, Fortanix, etc.). A global provider. |
| Local keyring file | keyProvider.file | Standalone only. Cannot back replication or WAL encryption. |
A replicated cluster (replicas > 1) or one using WAL encryption must use a
global provider (Vault or KMIP), because the standbys need to reach the same key
material. The webhook enforces this.
Spec fields
spec:
tde:
keyProvider:
vault:
address: https://vault.example.com:8200
mountPath: secret
tokenSecretRef:
name: vault-token # Secret key: token
caSecretRef: # optional, Secret key: ca.crt
name: vault-ca
encryptWAL: false # cluster-wide WAL encryption (needs a rolling restart to enable)
enforceEncryption: false # refuse creation of any unencrypted table
defaultEncryptedTables: false # make tde_heap the default table access method
cipher: aes_128 # aes_128 (default) or aes_256
spec.tde.keyProvider and spec.tde.cipher are immutable after the database is
created: changing where the principal key lives, or the cipher, would orphan the
keys already used to encrypt existing data. spec.tde.encryptWAL is reconfigured
through the EnableWALEncryption PostgresOpsRequest, not by patching the field
directly, since enabling it also requires setting up a server key and a rolling
restart. Rotating the principal key is likewise done through a
RotatePrincipalKey PostgresOpsRequest (see the
guide).
Encrypting tables
With TDE enabled you can encrypt tables in three ways:
- Per table at creation:
CREATE TABLE t (...) USING tde_heap; - Convert an existing table:
ALTER TABLE t SET ACCESS METHOD tde_heap; - Cluster-wide: set
spec.tde.defaultEncryptedTables: trueso every new table is encrypted (default_table_access_method = tde_heap).
Set spec.tde.enforceEncryption: true to block the creation of any unencrypted
table.
Limitations
- Requires Percona Server for PostgreSQL 17.x. Community PostgreSQL is not supported.
- System catalogs, server statistics, and temporary files spilled to disk (queries
exceeding
work_mem) are not encrypted. pg_tdeis incompatible with the Citus and TimescaleDB extensions.- Enabling TDE is not retroactive: existing tables stay unencrypted until you
convert them with
ALTER TABLE ... SET ACCESS METHOD tde_heap. - Losing the principal key means losing the data. The KMS must be reachable at restore time.
Next Steps
- Follow the TDE guide to deploy an encrypted Postgres, rotate the principal key, and enable WAL encryption.
- Read backup & restore for a TDE-encrypted Postgres before you set up logical backup, continuous archiving, or PITR.































