G.10. TDE — enables page level encryption #
This section describes the Transparent Data Encryption (TDE) feature, which enables page level encryption in Postgres Pro Enterprise with the pgpro_tde extension.
G.10.1. Transparent Data Encryption (TDE) Overview #
Transparent Data Encryption (TDE) is encryption of the database files that is done at the page level.
pgpro_tde encrypts:
Files of the tables, indexes, sequences and other relations files including all forks.
Write-ahead log (WAL).
Temporary files that PostgreSQL server creates during its data processing for operations, such as sorting data that exceeds ots memory limit.
Data is encrypted when it is sent to the disk.
G.10.2. Why Use TDE? #
TDE prevents unauthorized viewing of data with encrypting data on disk. Unauthorized users can't access data if they:
have access to backup archives
had access to backups while they were being written
have reading privilege to a server
G.10.3. How Does TDE Work? #
G.10.3.1. Encryption Algorithms #
Data encryption consumes a significant part of the CPU resources and adds complexity to collaboration with technical support. To minimize these repercussions, Postgres Pro Enterprise allows encrypting only confidential data by moving them to special tablespaces. Encryption and decryption processes happen on the fly and do not cause any DBMS unavailability for the users. It also doesn't affect applications, working with DBMS, as all the queries to the DB encrypted data is processed transparently, as if it was unencrypted.
pgpro_tde calls an OpenSSL library to encrypt and decrypt data with AES algorithm. It uses OpenSSL, provided within the certified OS. It encrypts data files using the AES-256-GCM symmetric key algorithm that provides both data authenticity (integrity) and confidentiality. It encrypts WAL files using AES-256-CTR, incorporating LSN (log sequence number) as the counter component.
OpenSSL utilizes vectorization command extensions like AVX-512
for GCM
encryption method. With this extension AES-256-GCM
gets a dramatic performance boost. Check if your hardware and virtualization software support this extended commands set to ensure superior TDE performance.
G.10.3.2. Encrypting Keys #
Postgres Pro Enterprise encrypts relation files in the dedicated tablespaces using respective tablespace encryption keys, and encrypts WAL files using a special WAL encryption key. These keys are unique sequences of bytes and the system keeps them securely encrypted in the $PGDATA/pg_encryption/keys
file. On start-up, the system calls for an external security system to decrypt this file data and then keeps these keys in its memory.
The external security system, mentioned above, has its own main master key, which it uses to encrypt and decrypt keyset of the system's tablespace and WAL encryption keys. The master key is generated by and stored in an external key management system. For more details, see Section G.10.10.
There is one key set file per cluster named keys
that contains all the tablespace and WAL encryption keys. The system keeps it located under the $PGDATA/pg_encryption
folder. When new keys are created (e.g. after rotation), the system calls an external system to encrypt them and stores them at the end of the same file. Postgres Pro Enterprise never stores the keys in plaintext without encryption.
To boost security even more, mind the key rotation that allows limiting the data encrypted with a single tablespace encryption key. Rotation generates a new tablespace key, which encrypts all the new data. The old data is still available encrypted by means of the old keys it was encrypted with. When the DBMS updates a data file page, it re-encrypts it with a new key. Keys rotation occurs on-the-fly and doesn't require restarting the database server. To rotate a specific tablespace keys, run this command:
SELECT pg_rotate_encryption_key(tablespace oid)
Or
select pg_rotate_encryption_key((select oid from pg_tablespace where spcname='my-encrypted-tablespace-name'))
G.10.4. Installation #
The pgpro_tde extension is provided with Postgres Pro Enterprise as a separate package pgpro-tde-ent
. To enable pgpro_tde, complete the following steps:
Add the library name to the
shared_preload_libraries
parameter in thepostgresql.conf
file:shared_preload_libraries = 'pgpro_tde'
Note that the library names in the
shared_preload_libraries
variable must be added in the specific order.Reload the database server for the changes to take effect.
To verify that the
pgpro_tde
library was installed correctly, you can run the following command:SHOW shared_preload_libraries;
Before enabling pgpro_tde, set up your external key management system of your choice. For the purposes of this manual, HashiCorp Vault is used. For more details, see Section G.10.10.
Allow Postgres Pro Enterprise cluster access your external key management system
Stop your master and standby servers
Apply all the WAL files on standby servers
Update your
postgresql.conf
withPGDATA/pg_encryption/keys
information and the following parameters:encryption=on encryption_key_wrap_command = ... encryption_key_unwrap_command = ...
postgresql.conf
must be modified both on your master and all its standby servers. For more details on this configuration for HashiCorp as an example, refer to this section.Start the master server. Once started, they will encrypt WAL files in their respective
$PGDATA/pg_wal
directories.Copy
$PGDATA/pg_encryption/keys
file from the master server to thepg_encryption
directories of all its standby servers.Start standby servers. Once started, they encrypt the WAL files in their
$PGDATA/pg_wal
directories with the same WAL key as the master server. It allows exchanging WAL encrypted records between master and standby servers.
PGDATA/pg_encryption/keys
and meta data files (-tde files that store encryption-specific information) require back up, as in case of loss you will not be able to read the encrypted files.
G.10.5. Using TDE #
pgpro_tde can only be enabled for separate tablespaces. To encrypt a tablespace, you should enable the encryption
option when creating this tablespace. For example:
CREATE TABLESPACE secure_tablespace LOCATION '/My/Data/Dir' WITH (encryption=on);
Once set, the tablespace encryption option cannot be altered, so you cannot encrypt or decrypt a tablespace that already has encrypted or clear data files.
To encrypt a table, you should move it to an encrypted tablespace using ALTER TABLE name SET TABLESPACE encrypted_tablespace;
. For this you must have the owner permissions of the table and privileges to use this encrypted tablespace. However, operating with decrypted data of these tables is possible with just having regular permissions for the SELECT
, UPDATE
, INSERT
, UPDATE
, DELETE
, and TRUNCATE
statements.
If this is the first encryption operation on the tablespace, then the server creates the first tablespace encryption key. Master server sends this key via a special WAL file record to all the standby servers for applying to the corresponding tablespaces there. Note that the new encryption keys are replicated from the primary server to its standby servers with no additional action required.
Note that the new encryption keys are replicated from the primary server to its standby servers with no additional action required.
To decrypt this data, move it from an encrypted tablespace to any other tablespace that is not yet encrypted.
You can find out whether pgpro_tde is enabled on a server by querying \db+
that will result in a list of tablespaces. The encrypted tablespaces have encrypted=on
value. For example:
postgres=# \db+ List of tablespaces Name | Owner | Location | Access privileges | Options | Size | Description ------------+----------+------------------------------------------+-------------------+-----------------+--------+------------- encrypted | postgres | /var/lib/pgpro/ent-17/meta/pg_encryption | | {encryption=on} | 68 kB | pg_default | postgres | | | | 22 MB | pg_global | postgres | | | | 667 kB | (3 rows)
G.10.6. Updating Keys #
G.10.6.1. Updating Master Key #
If your master key expired or was compromised, a new master key must be generated and applied. The way it can be done depends on your selected solution. For demonstration purposes, HashiCorp Vault is used.
Postgres Pro Enterprise stores keys under ${PGDATA}/pg_encryption/keys
. For safety purposes, all the keys in this file are encrypted with a master kay that is store in the HashiCorp Vault. To set the vault up, the listener address an the instance token are required. The setup is done with the environment variables, here VAULT_ADDR
and VAULT_TOKEN
are given as an example:
echo VAULT_ADDR='http://127.0.0.1:8200' > /etc/env.d/99vault echo VAULT_TOKEN="hvs.C77DySgOTjliYqmtp3yA4osP" >> /etc/env.d/99vault
Enable transit with HashiCorp Vault Transit Secrets Engine:
vault secrets enable transit
Create a new key and give it a new unique name:
vault write -f transit/keys/pg-tde-new-master-key
When a new key is issued, you should re-encrypt your keyset file with the new master key.
cat keys | vault write -field=plaintext transit/decrypt/pg-tde-master-key ciphertext=- | vault write -field=ciphertext transit/encrypt/pg-tde-new-master-key plaintext=- > keys
By default, HashiCorp Vault works with the 256-bit keys. If any other keys are required, address HashiCorp Vault server admins to update the settings.
G.10.6.2. Updating Tablespace Keys #
To update your tablespace keys, the DBMS admin must call the SQL function pg_rotate_encryption_key
with a tablespace oid to generate a new key:
postgres=# \db+ List of tablespaces Name | Owner | Location | Access privileges | Options | Size | Description ------------+----------+------------------------------------------+-------------------+-----------------+--------+------------- encrypted | postgres | /var/lib/pgpro/ent-17/meta/pg_encryption | | {encryption=on} | 68 kB | pg_default | postgres | | | | 22 MB | pg_global | postgres | | | | 667 kB | (3 rows) postgres=# select * from pg_tablespace where spcname='encrypted'; oid | spcname | spcowner | spcacl | spcoptions -------+-----------+----------+--------+----------------- 24587 | encrypted | 10 | | {encryption=on} (1 row) postgres=# select pg_rotate_encryption_key(24587); pg_rotate_encryption_key -------------------------- t (1 row)
G.10.7. Applications Affected by pgpro_tde #
The following applications have a TDE-specific option, allowing special processing of data in database data files: pg_rewind
and pg_waldump
with the -D
option.
Any of them can be used with both encrypted and unencrypted data. They finds warp/unwarp commands and encryption options under the postgresql.conf
file. Then they find postgresql.conf
under the data directory (defined under PGDATA/
). If PGDATA/
is not specified or corrupted, it can be defined with -D --pgdata
. This approach provides the highest level of the backward compatibility with unencrypted mode.
G.10.8. Limitations #
Work with pg_probackup is limited to the following operations when
encryption=on
:Taking FULL or DELTA backups with the ARCHIVE WAL delivery mode
Restoring a cluster (both with specifying the backup and without)
Validating backups (with or without the
--wal
option)Merging FULL and DELTA backups with
--merge-expired
that merges the oldest incremental backup that satisfies the requirements of retention policy with its parent backups that have already expired.
Other operations are not supported, including point-in-time recovery (PITR) and restoring with the specified LSN, XID, or timeline.
Compressed File System (CFS) and pgpro_tde cannot be used simultaneously within the same tablespace.
Using pg_transfer is not supported.
G.10.9. TDE and HashiCorp Vault #
This section describes the Transparent Data Encryption (TDE) integration with the external key management system of HashiCorp Vault.
G.10.10. HashiCorp Vault integration #
G.10.10.1. How to Create Master Key And Configure Pro Enterprise #
Postgres Pro Enterprise stores keys under ${PGDATA}/pg_encryption/encryption_keys
. For safety purposes, all the keys in this file are encrypted with a master key that is store in the HashiCorp Vault.
To set the vault up, the listener address an the instance token are required. The setup is done with the environment variables, here VAULT_ADDR
and VAULT_TOKEN
are given as an example:
echo VAULT_ADDR='http://127.0.0.1:8200' > /etc/env.d/99vault echo VAULT_TOKEN="hvs.C77DySgOTjliYqmtp3yA4osP" >> /etc/env.d/99vault
Enable transit with HashiCorp Vault Transit Secrets Engine:
vault secrets enable transit
Create a key and give it a name:
vault write -f transit/keys/pg-tde-master-key
By default, HashiCorp Vault works with the 256-bit keys. If any other keys are required, address HashiCorp Vault server admins to update the settings.
G.10.10.2. Testing TDE #
To make sure everything is set up properly, run express tests:
Access
psql
with superuser privileges and run the following commands:ALTER SYSTEM SET encryption_key_wrap_command='base64 | vault write -field=ciphertext transit/encrypt/pg-tde-master-key plaintext=- > %p'; ALTER SYSTEM SET encryption_key_unwrap_command='cat %p | vault write -field=plaintext transit/decrypt/pg-tde-master-key ciphertext=- | base64 --decrypt';
Restart the server with
pg_ctl restart
for the changes to take effect.Once the server is up, run these commands:
CREATE TABLESPACE encrypted LOCATION ':PGDATA/encrypted_ts'; ALTER TABLESPACE encrypted SET (encryption=on); CREATE TABLE test_table TABLESPACE encrypted AS (SELECT * FROM generate_series(1, 100) AS col1);
If set up correctly, >${PGDATA}/pg_encryption/encryption_keys
will contain this type of data:
vault:v1:rdaF+sSfkKn9HBzdalat7mnynRRR6b00FQS159PCUMGmMZJYMNm/hWxbFFIeV8C43nO3UV4dmgn7pxnJkwo4IYq2+sUHSWT/
G.10.10.3. HashiCorp Vault Setup Recommendations #
It is advised that HashiCorp Vault is already integrated and managed by our company admins. However, for testing purposes you may need an independent instance of the vault server that is configured for the Postgres Pro Enterprise TDE specifically.
G.10.10.3.1. HashiCorp Vault Installation #
It is highly recommended to use your OS repository to install HashiCorp Vault. For Ubuntu:
apt-get install -y wget net-tools apt-transport-https wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor > /tmp/hashicorp.gpg mv /tmp/hashicorp.gpg /etc/apt/trusted.gpg.d/ chown root:root /etc/apt/trusted.gpg.d/hashicorp.gpg chmod ugo+r /etc/apt/trusted.gpg.d/hashicorp.gpg chmod go-w /etc/apt/trusted.gpg.d/hashicorp.gpg echo "deb https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list apt-get update apt-get install vault
After installation vault --version
returns the current version of the vault, for example:
Vault v1.15.6, built 2024-09-17T15:25:10Z
You can also run a temporary test vault in dev environment with a limited time-to-life by running vault server -dev
in a separate command line. Note that any data on this instance is limited by the backend process time. Each time this dev vault is started, a new unseal key is generated, which creates a new root token specified under the VAULT_TOKEN
variable.
For a persistent vault, configure the vault service to run automatically. The configuration commands are different for openrc
-based and systemd
-based OS. For Ubuntu:
systemctl enable vault --now
To get service status:
systemctl status vault
G.10.10.3.2. HashiCorp Vault Configuration #
Vault service requires minimum manual configuration. It only needs a backend specified. By default, the listener is available via HTTPS. You can switch to HTTP or disable authentication for CLI. In case of using HTTPS the self-signed certificate will not pass verification, so the latter should be disabled:
typeset -x VAULT_SKIP_VERIFY=true
Below is an example of the valid configuration:
api_addr = "https://127.0.0.1:8200" cluster_addr = "https://127.0.0.1:8210" cluster_name = "local-vault-cluster" disable_mlock = true ui = true backend "raft" { node_id = "local-vault-server" path = "/var/lib/vault" } listener "tcp" { address = "[::]:8200" cluster_address = "[::]:8210" tls_cert_file = "/var/lib/vault/cert.pem" tls_key_file = "/var/lib/vault/key.pem" } listener "tcp" { address = "127.0.0.1:8201" cluster_address = "127.0.0.1:8210" tls_disable = 1 }
To create self-signed certificate:
openssl req -x509 -newkey rsa:4096 -sha256 -days 365 \ -nodes -keyout /var/lib/vault/key.pem -out /var/lib/vault/cert.pem \ -subj "/CN=localhost" \ -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
This configuration requires the directory /var/lib/vault
to be available for reading and writing for the user this service runs under. raftdb
is defined as a backend, with two listeners: local and global with TLS.
To unseal the service before start, receive the key and the root token:
vault operator init -key-shares=1 -key-threshold=1 vault operator unseal key
Then authorize CLI:
vault login token
VAULT_TOKEN
for CLI is not required after this step. Once done, the vault is ready to be used with TDE.