Skip to content

column_encrypt v4.0 - Simplified API Release

Latest

Choose a tag to compare

@vibhorkum vibhorkum released this 06 Apr 15:05

column_encrypt v4.0

Transparent column-level encryption for PostgreSQL - Major Simplification Release

v4.0 is a clean API release that removes all deprecated functionality from previous versions, providing a minimal, secure, and easy-to-use encryption API.


Highlights

  • Simplified API: All functions consolidated under the encrypt schema
  • Single role model: Unified column_encrypt_user role replaces the 3-role system
  • Automatic log masking: No more manual cipher_key_disable_log() calls
  • Fixed encrypt schema: Improved security with non-relocatable extension

Security Updates (v4.0.1 patch)

Log Masking Fixes

Fixed: encrypt.register_key() and encrypt.blind_index() were not being masked in PostgreSQL logs. DEK, passphrase, and HMAC key arguments could leak into server logs on validation errors.

The emit_log_hook regex now includes all sensitive functions:

  • register_key, load_key, blind_index
  • Legacy: register_cipher_key, load_key_by_version, enc_store_key, enc_store_prv_key

INSERT/UPDATE Data Protection

New guidance: For comprehensive protection of sensitive data in INSERT/UPDATE statements, enable the encrypt.mask_query_literals GUC:

-- In postgresql.conf or per-session:
SET encrypt.mask_query_literals = on;

This masks ALL string literals in logged queries, protecting:

  • DEK values in INSERT/UPDATE statements
  • Passphrase values passed to functions
  • Any other string literal data

Trade-off: You lose visibility into actual values in logs, but gain complete protection against accidental secret exposure.


Installation

# Build and install
make && make install

# Add to postgresql.conf
shared_preload_libraries = 'column_encrypt'

# In PostgreSQL:
CREATE SCHEMA IF NOT EXISTS encrypt;
CREATE EXTENSION column_encrypt;

Supported PostgreSQL versions: 14, 15, 16, 17, 18


v4.0 API Reference

Function Description
encrypt.register_key(dek, passphrase, [activate]) Register new encryption key
encrypt.load_key(passphrase, [all_versions]) Load key(s) into session
encrypt.unload_key() Clear keys from session
encrypt.activate_key(key_id) Set active key for new encryptions
encrypt.revoke_key(key_id) Prevent key from being loaded
encrypt.rotate(schema, table, column, [batch_size]) Re-encrypt with active key
encrypt.verify(schema, table, column, [sample_size]) Verify encryption integrity
encrypt.keys() List all registered keys
encrypt.status() Quick status check
encrypt.blind_index(value, hmac_key) Create searchable blind index

Upgrade Path

v2.0 → v3.0 → v3.1 → v3.3 → v4.0

Important: Upgrade through v3.3 first to migrate your code from deprecated functions:

-- Step 1: Upgrade to v3.3 (deprecation release)
ALTER EXTENSION column_encrypt UPDATE TO '3.3';

-- Step 2: Update code to use encrypt.* API

-- Step 3: Upgrade to v4.0
ALTER EXTENSION column_encrypt UPDATE TO '4.0';

See MIGRATION.md for the complete guide.


Complete Version History

v4.0 (This Release)

Removed (use new encrypt.* API instead):

  • cipher_key_disable_log() / cipher_key_enable_log() → Automatic
  • register_cipher_key()encrypt.register_key()
  • load_key() / load_key_by_version()encrypt.load_key()
  • rm_key_details()encrypt.unload_key()
  • activate_cipher_key()encrypt.activate_key()
  • revoke_cipher_key()encrypt.revoke_key()
  • cipher_key_versions()encrypt.keys()
  • cipher_key_reencrypt_data*()encrypt.rotate()
  • cipher_verify_column_encryption()encrypt.verify()
  • All metrics, audit, and rotation job functions
  • cipher_key_audit_log, cipher_key_failed_attempts, cipher_rotation_jobs tables

Changed:

  • Single column_encrypt_user role replaces 3-role system
  • All functions use SECURITY DEFINER with SET search_path TO pg_catalog
  • Dynamic pgcrypto schema lookup (works regardless of where pgcrypto is installed)

Security:

  • Fixed log masking for register_key() and blind_index() functions
  • Fixed privilege escalation in SECURITY DEFINER functions
  • SET ROLE privilege reduction now properly honored
  • Schema-qualified all object references
  • Added encrypt.mask_query_literals GUC documentation for INSERT/UPDATE protection

v3.3 (Deprecation Release)

Added:

  • New encrypt schema with all v4.0 API functions
  • Deprecation warnings for old functions

Purpose: Bridge release allowing code migration before v4.0


v3.1 (Production Operations)

Added:

  • cipher_metrics() - Encryption statistics
  • cipher_coverage_audit() - Column coverage audit
  • cipher_start_rotation_job() - Background rotation jobs
  • cipher_key_audit_log - Audit logging table
  • Key expiration checking

v3.0 (Multi-Version Keys)

Added:

  • Role-based access control (3-role model)
  • Key lifecycle states: pending, active, retired, revoked
  • Multi-version key management with key_version column
  • loaded_cipher_key_versions() - Session introspection
  • cipher_key_reencrypt_data() / cipher_key_reencrypt_data_batch() - Key rotation
  • Blind index helpers
  • Docker-based replication test harness
  • Equality and hash semantics on decrypted plaintext (breaking change)

Changed:

  • Renamed keywrapped_key in cipher_key_table
  • Hash/equality operations now use decrypted values

Upgrade Note: REINDEX hash indexes on encrypted columns after upgrade


v2.0 (Two-Tier Key Model)

Added:

  • KEK/DEK model: passphrase wraps data encryption key
  • register_cipher_key() with passphrase wrapping
  • load_key() for session key loading
  • 2-byte key version header in ciphertext
  • Log masking via emit_log_hook
  • Secure memory zeroing with secure_memset

Changed:

  • Keys stored wrapped (encrypted) in database
  • Session keys in TopMemoryContext

v1.0 (Initial Release)

Added:

  • encrypted_text and encrypted_bytea custom types
  • Transparent encrypt/decrypt via type I/O
  • encrypt.enable GUC for global control
  • pgcrypto integration for AES encryption
  • Basic equality operators and hash index support
  • Type casts from bool, inet, cidr, xml, character

Security Model

  • Two-tier key model: KEK (passphrase) wraps DEK (data key)
  • AES-256: Via pgcrypto with iterated-salted S2K
  • Session isolation: Keys per-connection, cleared on disconnect
  • Log protection: Automatic masking of sensitive function calls
  • Query literal masking: Optional encrypt.mask_query_literals for INSERT/UPDATE protection
  • SECURITY DEFINER: All functions properly secured
  • Binary protocol blocked: Prevents encryption bypass

Documentation


License

PostgreSQL License


Full Changelog: v1.0...v4.0