Skip to content

The Cryptic Elephant (TCE)

A Postgres extension for Transparent Column Encryption with the following objectives:

  • Fully Open-source, No Open-Core version, No Vendor Lock-in
  • Support of all major versions of Postgres, No Fork needed
  • Encrypt data in memory ( i.e. "data in use" encryption )
  • Use Envelop Encryption to protect the Data Encryption Key (DEK)
  • Store the Key Encryption Keys (KEK) in an external KMS
  • Easy and fast key rotations

This extension is developed in Rust and relies heavily on Rust Crypto libraries.

Warning

DISCLAIMER: This is an early working version. As we're moving towards a beta version in the forthcoming months we may introduce breaking changes or revert some features at any time. See CONTRIBUTING.md for more details on how to help this project.

!!DO NOT USE IN PRODUCTION!!

Partners

This project is co-developed by DALIBO and CNRS, and is open to other entities wishing to join us in this collaborative effort.

Check out our Development Partners Program for more details on how to contribute!

Purpose

If you’re asking whether this extension is for you, it probably isn’t :-)

This extension is designed for database subject to very strict data protection regulations such as DORA and PCI DSS. It aims at implementing encryption of "data in use" for PostgreSQL as a complement to the classic "encryption at rest" approach.

If these regulations don't apply to your context, congratulations ! You can ignore this project and implement some basic disk-level or filesystem-level encryption, which is most certainly good enough for your Postgres instances.

See the why chapter for a detailed analysis.

Preconditions

The following conditions must be true for the extension to function correctly:

  • The system administrators are trusted.
  • The postgres superusers are trusted and have a secret private key.

Install

ALTER DATABASE demo SET session_preload_libraries TO tce;
\connect demo
CREATE EXTENSION IF NOT EXISTS tce;

Impacts

Using TCE has a few impacts on backup and replication procedures.

Configure

CREATE ROLE alice LOGIN;

-- Enable this FOR TESTING PURPOSE ONLY
SET tce.enable_fetch_from_file TO TRUE;

-- private key must be on the same host as the database server.
-- It can be generated using one of the following commands:
-- `openssl genrsa -out /some/directory/alice_private_rsa.key 2048`
-- `ssh-keygen -t rsa -m PKCS8 -f /some/directory/alice_private_rsa.key`
SECURITY LABEL FOR tce_user_key ON ROLE alice
  IS 'FETCHED FROM FILE /some/directory/alice_private_rsa.key';

NOTICE: The configuration, specifically security labels and GUC settings, is accessible to unprivileged users. It can also appear in dumps depending on the utility and parameters employed.

Explicit Column Encryption

\connect demo alice

-- Given a classic table
CREATE TABLE spies (
  code TEXT,
  realname TEXT
);

INSERT INTO spies VALUES ('007','James Bond'), ('H21','Mata Hari');

-- Convert to TEXT column into a TCETEXT column
ALTER TABLE spies
  ALTER COLUMN realname
  TYPE TCETEXT
  USING realname::TCETEXT;

--
-- Enjoy !
--
-- The data is now encrypted on disk
-- and displayed in plain text to all users having the secret key
--

SET tce.show_raw TO TRUE;

SELECT realname, raw(realname) FROM spies;
  realname   |                     raw
-------------+----------------------------------------------
 James Bond  | \x34bebe556560e7fdd4abb441fcb537b7b8c0d67733
 Mata Hari   | \x37bdb54762699534529bb40655fb01232e6f12
(2 rows)

Transparent Column Encryption

ALTER DATABASE demo SET tce.transparent_column_encryption TO TRUE;

\connect demo alice

-- Create the table AFTER tce is enabled
CREATE TABLE person (
  id SERIAL,
  firstname VARCHAR(100),
  credit_card INTEGER
);

INSERT INTO person VALUES (1,'Bernard',1234567890), (2,'Bob',1234567890);

SELECT firstname, credit_card, raw(credit_card) FROM person;
 firstname | credit_card |                          raw
-----------+-------------+-------------------------------------------------------
 Bernard   | 1234567890  | 3923619818820789153246812041148227241194201238
 Bob       | 1234567890  | 16910846692501417132462151191111121924510524618918198

User Key Management

Envelope management

When the extension is just installed, no DEK exists in the database to cipher data. A super user must create its own key by setting the fetching method for his own account first.

-- Alice must be a super user to do this
\connect demo alice

SECURITY LABEL FOR tce_user_key ON ROLE alice
  IS 'FETCHED FROM FILE /some/directory/some_rsa_private.key';

Be aware that if several super user create their own label separately, several DEK will exist within the database leading to accounts unable to decipher some data.

From there, the super user can create envelopes for other users. It will automatically decipher the DEK to create new envelopes:

\connect demo alice

-- User bob must exist
SECURITY LABEL FOR tce_user_key ON ROLE bob
  IS 'FETCHED FROM URL https://some.server.org/somewhere/bob_private.key';

Key rotation

Over time, the superuser may want to change the user's key.

This is done simply by modifying the fetchkey method to point to another key.

SECURITY LABEL FOR tce_user_key ON ROLE alice
  IS 'FETCHED FROM FILE /some/directory/some_rsa_private.key';

-- A few moments later....

SECURITY LABEL FOR tce_user_key ON ROLE alice
  IS 'FETCHED FROM FILE /some/directory/another_rsa_private.key';

Demo

make demo

Build

  1. Install PGRX

https://github.com/pgcentralfoundation/pgrx/blob/develop/README.md

  1. Build and Run
cargo pgrx run
  1. Tests
cargo pgrx test
cargo pgrx regress