Skip to content

Rate this page
Thanks for your feedback
Thank you! The feedback has been submitted.

Get free database assistance or contact our experts for personalized support.

Vault configuration

You can configure pg_tde to use HashiCorp Vault as a global key provider for managing encryption keys securely. Both the open source and enterprise editions are supported.

Configure Vault with pg_tde in Docker

This example setup describes how to run HashiCorp Vault and Percona PostgreSQL with pg_tde side by side using Docker, configure Vault policies, and connect it as a global key provider for TDE encryption.

Note

For production deployments, follow your organization’s security standards.

1. Create the docker-compose.yaml file

The following docker-compose.yaml file is an example on how to run both Vault and PostgreSQL with a shared secrets volume:

docker-compose.yaml (example file)
version: '3.8'

services:
vault:
    image: hashicorp/vault:latest
    container_name: vault
    ports:
    - "8200:8200"
    volumes:
    - ./vault-config.hcl:/vault/config/vault-config.hcl
    - ./vault-data:/vault/data
    - shared-secrets:/vault/secrets
    environment:
    VAULT_ADDR: http://127.0.0.1:8200
    command: vault server -config=/vault/config/vault-config.hcl

pg:
    image: percona/percona-distribution-postgresql:17.5-2
    container_name: pg
    ports:
    - "5432:5432"
    environment:
    POSTGRES_PASSWORD: secret
    ENABLE_PG_TDE: "1"
    volumes:
    - ./pgdata:/var/lib/postgresql/data
    - shared-secrets:/etc/postgresql/secrets:ro
    depends_on:
    - vault

volumes:
shared-secrets:

2. Enable the KV v2 secrets engine

In the Vault container, enable a KV v2 storage engine for pg_tde:

vault secrets enable -path=tde -version=2 kv

This creates a tde/ mount for storing encrypted keys.

3. Create a Vault policy for pg_tde

Define a Vault policy that grants pg_tde access to read, write, and list keys.

vault policy write tde-policy - <<EOF
path "tde/data/*" {
  capabilities = ["read", "create", "update", "list"]
}

path "tde/metadata/*" {
  capabilities = ["read", "list"]
}
EOF

This allows pg_tde to:

  • read, create, and update encryption keys
  • list and access metadata for the tde/ path

Tip

If you encounter the following error:

ERROR: failed to get mount info for "http://vault:8200" at mountpoint ...

Ensure your Vault policy includes the following path:

path "sys/mounts/*" {
  capabilities = ["read"]
}

This allows pg_tde to read the mount metadata from Vault.

4. Create an Authentication Method and Token

Enable the AppRole authentication method:

vault auth enable approle
vault write auth/approle/role/tde-role policies="tde-policy"

Generate a token associated with the tde-policy:

vault token create -policy="tde-policy"

Example output:

Key                  Value
token                hvs.{secret_code}
token_policies       ["default" "tde-policy"]

5. Share the token with PostgreSQL

Copy the generated token into the shared secrets directory (shared secrets volume) so PostgreSQL can use it:

echo "hvs.secret_code" > /vault/secrets/vault_token.txt

Tip

You can access this file in PostgreSQL at /etc/postgresql/secrets/vault_token.txt.

6. Register Vault as a global key provider in PostgreSQL

In the PostgreSQL container, connect pg_tde to Vault using:

SELECT pg_tde_add_global_key_provider_vault_v2(
  'vault-provider',
  'http://vault:8200',
  'tde/data/global-key',
  '/etc/postgresql/secrets/vault_token.txt',
  NULL
);

7. Create and set the global master key

Create the global master key:

SELECT pg_tde_create_key_using_global_key_provider(
  'global-master-key',
  'vault-provider'
);

Then set it:

SELECT pg_tde_set_default_key_using_global_key_provider(
  'global-master-key',
  'vault-provider'
);

8. Test encryption with a sample table

Create a sample table:

CREATE TABLE secure_data (
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name TEXT,
  amount NUMERIC(10,2),
  created_at DATE
) USING tde_heap;

Then insert data into the table:

INSERT INTO secure_data (name, amount, created_at) VALUES
('Alice', 1234.56, '2025-08-01'),
('Bob', 7890.12, '2025-08-10'),
('Charlie', 345.67, '2025-08-19');

Query the table and confirm that the encryption is functioning:

select * from secure_data;
 id |  name   | amount  | created_at
----+---------+---------+------------
  1 | Alice   | 1234.56 | 2025-08-01
  2 | Bob     | 7890.12 | 2025-08-10
  3 | Charlie |  345.67 | 2025-08-19
(3 rows)

Example global key provider usage

SELECT pg_tde_add_global_key_provider_vault_v2(
    'provider-name',
    'url',
    'mount',
    'secret_token_path',
    'ca_path'
);

Parameter descriptions

  • provider-name is the name to identify this key provider
  • secret_token_path is a path to the file that contains an access token with read and write access to the above mount point
  • url is the URL of the Vault server
  • mount is the mount point where the keyring should store the keys
  • [optional] ca_path is the path of the CA file used for SSL verification

The following example is for testing purposes only. Use secure tokens and proper SSL validation in production environments:

SELECT pg_tde_add_global_key_provider_vault_v2(
    'my-vault',
    'https://vault.vault.svc.cluster.local:8200',
    'secret/data',
    '/path/to/token_file',
    '/path/to/ca_cert.pem'
);

For more information on related functions, see Function Reference.

Required permissions

The PostgreSQL instance requires the following Vault API capabilities to manage and read encryption keys:

  • sys/mounts/<mount>/* - read permissions
  • <mount>/data/* - create, read permissions
  • <mount>/metadata/* - list permissions

Note

For more information on Vault permissions, see the following documentation.

Next steps

Global Principal Key Configuration