CipherStash Proxy

Introduction

CipherStash Proxy provides transparent, searchable encryption for your existing Postgres database.

CipherStash Proxy:

  • Automatically encrypts and decrypts data with zero changes to SQL
  • Supports queries over encrypted values:
    • equality
    • comparison
    • ordering
    • grouping
  • Is written in Rust for high performance and strongly-typed mapping of SQL statements.
  • Manages keys using CipherStash ZeroKMS, offering up to 9x the performance of AWS KMS

Behind the scenes, CipherStash Proxy uses the Encrypt Query Language (EQL) to index and search encrypted data.

Tip

If you are looking for a quick start guide, check out the getting started guide.

Installing Proxy

CipherStash Proxy is available as a container image on Docker Hub that can be deployed locally, in CI/CD, through to production.

The easiest way to start using CipherStash Proxy with your application is by adding a container to your application's docker-compose.yml. The following is an example of what adding CipherStash Proxy to your app's docker-compose.yml might look like:

1services:
2  app:
3    # Your Postgres container config
4  db:
5    # Your Postgres container config
6  proxy:
7    image: cipherstash/proxy:latest
8    container_name: proxy
9    ports:
10      - 6432:6432
11      - 9930:9930
12    environment:
13      # Hostname of the Postgres database server connections will be proxied to
14      - CS_DATABASE__HOST=${CS_DATABASE__HOST}
15      # Port of the Postgres database server connections will be proxied to
16      - CS_DATABASE__PORT=${CS_DATABASE__PORT}
17      # Username of the Postgres database server connections will be proxied to
18      - CS_DATABASE__USERNAME=${CS_DATABASE__USERNAME}
19      # Password of the Postgres database server connections will be proxied to
20      - CS_DATABASE__PASSWORD=${CS_DATABASE__PASSWORD}
21      # The database name on the Postgres database server connections will be proxied to
22      - CS_DATABASE__NAME=${CS_DATABASE__NAME}
23      # The CipherStash workspace CRN for making requests for encryption keys
24      - CS_WORKSPACE_CRN=${CS_WORKSPACE_CRN}
25      # The CipherStash client access key for making requests for encryption keys
26      - CS_CLIENT_ACCESS_KEY=${CS_CLIENT_ACCESS_KEY}
27      # The CipherStash dataset ID for generating and retrieving encryption keys
28      - CS_DEFAULT_KEYSET_ID=${CS_DEFAULT_KEYSET_ID}
29      # The CipherStash client ID used to programmatically access a dataset
30      - CS_CLIENT_ID=${CS_CLIENT_ID}
31      # The CipherStash client key used to programmatically access a dataset
32      - CS_CLIENT_KEY=${CS_CLIENT_KEY}
33      # Toggle Prometheus exporter for CipherStash Proxy operations
34      - CS_PROMETHEUS__ENABLED=${CS_PROMETHEUS__ENABLED:-true}

For a fully-working example, check out the docker-compose.yml file in the Proxy repository.

Once you have set up a docker-compose.yml, start the Proxy container:

1docker compose up

Connect your PostgreSQL client to Proxy on TCP 6432.

Tip

Prometheus metrics are exposed on port 9930. Read more about them in the reference documentation.

Configuring Proxy

To run, CipherStash Proxy needs to know:

  • What port to run on
  • How to connect to the target PostgreSQL database
  • Secrets to authenticate to CipherStash

There are two ways to configure Proxy:

Proxy's configuration loading order of preference is:

  1. If cipherstash-proxy.toml is present in the current working directory, Proxy will read its config from that file
  2. If cipherstash-proxy.toml is not present, Proxy will look up environment variables to configure itself
  3. If both cipherstash-proxy.toml and environment variables are present, Proxy will use cipherstash-proxy.toml as the base configuration, and override it with any environment variables that are set

See Proxy config reference for all the available options.

Setting up the database schema

Under the hood, Proxy uses EQL to index and search encrypted data.

When you start the Proxy container, you can install EQL by setting the CS_DATABASE__INSTALL_EQL environment variable:

1CS_DATABASE__INSTALL_EQL=true

This will install the version of EQL bundled with the Proxy container. The version of EQL bundled with the Proxy container is tested to work with that version of Proxy.

Important

Using the CS_DATABASE__INSTALL_EQL environment variable is only recommended for development environments. You should install EQL by running the installation script as a database migration in production environments.

Once you have installed EQL, you can see what version is installed by querying the database:

1SELECT eql_v2.version();

Creating columns with the right types

In your existing PostgreSQL database, you store your data in tables and columns. Those columns have types like integer, text, timestamp, and boolean. When storing encrypted data in PostgreSQL with Proxy, you use a special column type called eql_v2_encrypted, which is provided by EQL. eql_v2_encrypted is a container column type that can be used for any type of encrypted data you want to store or search, whether they are numbers (int, small_int, big_int), text (text), dates and times (date. timestamp), or booleans (boolean).

Create a table with an encrypted column for email:

1CREATE TABLE users (
2    id SERIAL PRIMARY KEY,
3    email eql_v2_encrypted
4)

This creates a users table with two columns:

  • id, an autoincrementing integer column that is the primary key for the record
  • email, a eql_v2_encrypted column

There are important differences between the plaintext columns you've traditionally used in PostgreSQL and encrypted columns with CipherStash Proxy:

  • Plaintext columns can be searched if they don't have an index, albeit with the performance cost of a full table scan.
  • Encrypted columns cannot be searched without an encrypted index, and the encrypted indexes you define determine what kind of searches you can do on encrypted data.

In the previous step we created a table with an encrypted column, but without any encrypted indexes.

Now you can add an encrypted index for that encrypted column:

1SELECT eql_v2.add_search_config(
2  'users',
3  'email',
4  'unique',
5  'text'
6);

This statement adds a unique index for the email column in the users table, which has an underlying data type of text.

unique indexes are used to find records with columns with unique values, like with the = operator.

There are two other types of encrypted indexes you can use on text data:

1SELECT eql_v2.add_search_config(
2  'users',
3  'email',
4  'match',
5  'text'
6);
7
8SELECT eql_v2.add_search_config(
9  'users',
10  'email',
11  'ore',
12  'text'
13);

The first SQL statement adds a match index, which is used for partial matches with LIKE. The second SQL statement adds an ore index, which is used for ordering with ORDER BY.

Important

Adding, updating, or deleting encrypted indexes on columns that already contain encrypted data will not re-index that data. To use the new indexes, you must SELECT the data out of the column, and UPDATE it again.

To learn how to use encrypted indexes for other encrypted data types like text, int, boolean, date, and jsonb, see the EQL documentation.

When deploying CipherStash Proxy into production environments with real data, we recommend that you apply these database schema changes with the normal tools and process you use for making changes to your database schema.

Encrypting data in an existing database

CipherStash Proxy includes an encrypt tool – a CLI application to encrypt existing data, or to apply index changes after changes to the encryption configuration of a protected database. See the encrypt tool reference for info about using the encrypt tool.

Reference

See the CipherStash Proxy reference for all the available options.