pg_vault_tde

Transparent Data Encryption for PostgreSQL through custom table and index access methods

Overview

PackageVersionCategoryLicenseLanguage
pg_vault_tde1.7.0SECPostgreSQLC
IDExtensionBinLibLoadCreateTrustRelocSchema
7510pg_vault_tdeYesYesYesYesNoNo-
Relatedpg_tde supabase_vault pgsodium column_encrypt pgcryptokey pgcrypto

Requires PostgreSQL 17+, OpenSSL 3, libcurl, and shared_preload_libraries=pg_vault_tde; RPM excludes EL8; includes pg_dump_tde, pg_restore_tde, and pg_basebackup_tde.

Version

TypeRepoVersionPG VerPackageDeps
EXTPIGSTY1.7.01817161514pg_vault_tde-
RPMPIGSTY1.7.01817161514pg_vault_tde_$vopenssl-libs, libcurl
DEBPIGSTY1.7.01817161514postgresql-$v-pg-vault-tde`libssl3
OS / PGPG18PG17PG16PG15PG14
el8.x86_64N/AN/AN/AN/AN/A
el8.aarch64N/AN/AN/AN/AN/A
el9.x86_64N/AN/AN/A
el9.aarch64N/AN/AN/A
el10.x86_64N/AN/AN/A
el10.aarch64N/AN/AN/A
d12.x86_64N/AN/AN/A
d12.aarch64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
d13.x86_64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
d13.aarch64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
u22.x86_64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
u22.aarch64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
u24.x86_64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
u24.aarch64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A
u26.x86_64N/AN/AN/A
u26.aarch64
PIGSTY 1.7.0
PIGSTY 1.7.0
N/AN/AN/A

Build

You can build the RPM / DEB packages for pg_vault_tde using pig build:

pig build pkg pg_vault_tde         # build RPM / DEB packages

Install

You can install pg_vault_tde directly. First, make sure the PGDG and PIGSTY repositories are added and enabled:

pig repo add pgsql -u          # Add repo and update cache

Install the extension using pig or apt/yum/dnf:

pig install pg_vault_tde;          # Install for current active PG version
pig ext install -y pg_vault_tde -v 18  # PG 18
pig ext install -y pg_vault_tde -v 17  # PG 17
dnf install -y pg_vault_tde_18       # PG 18
dnf install -y pg_vault_tde_17       # PG 17
apt install -y postgresql-18-pg-vault-tde   # PG 18
apt install -y postgresql-17-pg-vault-tde   # PG 17

Preload:

shared_preload_libraries = 'pg_vault_tde';

Create Extension:

CREATE EXTENSION pg_vault_tde;

Usage

Sources:

pg_vault_tde adds transparent tuple encryption for PostgreSQL 17 and 18 through the encrypted_heap table access method. It encrypts user-column data with AES-256-GCM before storage and manages per-relation data-encryption keys through HashiCorp Vault/OpenBao, a local PKCS#12 wallet, or—in v1.7—a PKCS#11 HSM. MVCC tuple headers remain plaintext.

Configure and Install

shared_preload_libraries = 'pg_vault_tde'
pg_vault_tde.kms_provider = 'vault'
pg_vault_tde.vault_url = 'https://vault.example.com:8200'
pg_vault_tde.vault_transit_mount = 'transit'
pg_vault_tde.vault_key_name = 'pg-tde-dek'
pg_vault_tde.vault_ca_cert = '/etc/ssl/vault/ca.pem'

Configure Vault authentication through the documented token, AppRole, or Kubernetes settings without committing secrets to PostgreSQL configuration. Restart PostgreSQL, then create the extension:

CREATE EXTENSION pg_vault_tde;
SELECT * FROM pg_vault_tde_health_check();

kms_provider has no usable default and must be set explicitly. The extension requires OpenSSL 3 and libcurl in addition to PostgreSQL server files.

Create an Encrypted Table

CREATE TABLE customer_secrets (
  id bigint GENERATED ALWAYS AS IDENTITY NOT NULL,
  email text,
  ssn text
) USING encrypted_heap;

Encryption is table-level: ordinary heap tables are unchanged. Tuple values, TOAST data, and WAL representations are encrypted; tuple headers required for MVCC remain visible.

Indexes

Use tde_btree for equality lookup without storing plaintext keys:

CREATE UNIQUE INDEX customer_secrets_id_tde_idx
ON customer_secrets USING tde_btree (id);

CREATE INDEX customer_secrets_email_tde_idx
ON customer_secrets USING tde_btree (email);

tde_btree uses deterministic AES-256-SIV and supports equality, not range ordering or index-only scans. Other access methods on an encrypted_heap table are rejected by default because they would write plaintext index keys. PRIMARY KEY and UNIQUE table constraints still create native btree indexes and produce a warning; decide whether that exposure is acceptable before defining them.

Integrity and Rotation

SELECT * FROM pg_vault_tde_verify_integrity('customer_secrets');
SELECT * FROM pg_vault_tde_encrypted_size('customer_secrets');

SELECT pg_vault_tde_rotate_online('customer_secrets', 1000);
SELECT * FROM pg_vault_tde_get_rotation_status('customer_secrets');

SELECT pg_vault_tde_rotate_kek();

Online DEK rotation re-encrypts a table in batches and rebuilds its tde_btree indexes. KEK rotation re-wraps per-table DEKs without rewriting tuples. Restrict these operations, monitor completion, and avoid concurrent key-catalog restoration.

Provider and Backup Boundaries

  • The local wallet defaults outside PGDATA; copy and protect it separately because plain pg_basebackup does not include it.
  • Version 1.7 adds the pkcs11 provider and pg_vault_tde_pkcs11_keygen(). The standalone pg_dump_tde and pg_restore_tde tools do not support PKCS#11 in this release.
  • Plain pg_dump and COPY ... TO read decrypted rows and therefore produce plaintext without a warning. Use the supplied encrypted logical-backup tools where supported.
  • Physical backups contain encrypted relation bytes and wrapped DEKs, but not the KEK. Provision access to the Vault/HSM or copy the local wallet separately. The key-sealing functions and pg_basebackup_tde wrapper can accompany a physical backup with a tamper-evident DEK bundle.

Critical Caveats

  • Never toggle pg_vault_tde.enabled while an encrypted_heap table contains rows written under the other setting. The extension does not rewrite existing rows and mixed formats can be silently misread as corruption.
  • Ordinary indexes, statistics, logs, query results, client traffic, temporary work, and backups can expose plaintext outside the encrypted heap. TDE is one storage-layer control, not end-to-end encryption.
  • tde_btree disables range semantics, and encrypted tables disable HOT updates in the current design; benchmark update-heavy workloads and index maintenance.
  • Keep KMS credentials, wallet passphrases, HSM PINs, KEKs, sealed bundles, and restore procedures under separate access controls. A backup without the matching key path is unrecoverable.
  • Package release 1.7.0 installs SQL extension version 1.7, is not relocatable, requires preloading and a restart, and supports PostgreSQL 17-18 only.

Last Modified: 2026-08-09: update extension count (24575456)