This project tests Percona's PG TDE (Transparent Data Encryption) extension with HashiCorp Vault for multi-tenant encryption.
- PostgreSQL: Percona Distribution PostgreSQL 17.5-2 with PG TDE
- Vault: HashiCorp Vault (latest) for key management
- Test Setup: 3 tenants with separate databases and encryption keys
-
Start the stack (includes automatic initialization):
docker-compose up -d
This will automatically:
- Start Vault and PostgreSQL
- Initialize Vault with tenant encryption keys
- Create encrypted databases for each tenant
- Insert sample patient data
-
Verify encryption (optional):
cd scripts ./03-verify-encryption-host.sh
If you encounter "key already exists" errors, use the clean restart script:
./scripts/00-clean-restart.sh- Docker and Docker Compose
curlandopensslavailable on host
- ✅ 3 tenant databases (
tenant_001,tenant_002,tenant_003) - ✅ Each tenant has its own encryption key stored in Vault
- ✅
patientstable with 5 records per tenant database - ✅ Each database encrypted with its own tenant-specific key
- ✅ Data files are encrypted on disk using
tde_heapaccess method - ✅ No readable text in data files
The verification script checks:
- Locates PostgreSQL data files on disk
- Verifies tenant databases are created
- Searches for readable text in encrypted files
- Shows hex dumps of encrypted data
- Confirms data access through SQL queries per database
- Validates each tenant's database is encrypted using
tde_heap - Confirms each tenant has its own key provider in Vault
- Vault UI: http://localhost:8200
- Token:
myroot
- Token:
- PostgreSQL:
localhost:5433- User:
postgres - Password:
postgres
- User:
A Spring Boot Kotlin client is available in the kotlin-client directory that provides a REST API for the multi-tenant encrypted databases.
- Multi-tenant routing: Uses HTTP header
X-Tenant-IDto route to correct encrypted database - Virtual threads: Leverages Java 21+ virtual threads for improved performance
- Spring Boot 3.2: Modern reactive Spring stack with Kotlin
- Comprehensive testing: Integration tests using Testcontainers with full Percona + Vault stack
cd kotlin-client
mvn spring-boot:runThe API will be available at http://localhost:8080
GET /patients- Get all patients for a tenant (requiresX-Tenant-IDheader)GET /patients/{id}- Get specific patient by ID (requiresX-Tenant-IDheader)
The client includes integration tests that use Testcontainers to spin up the full Percona + Vault + PG TDE stack:
cd kotlin-client
mvn testThe integration tests (PerconaVaultIntegrationTest) verify:
- Multi-tenant API functionality with encrypted databases
- Proper tenant isolation (each tenant accesses its own database)
- Error handling for invalid tenants and missing headers
- Concurrent request handling across tenants
- API operations return correct encrypted data
docker-compose down -v