Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,11 @@ packages/
│ │ ├── parser.rs # SQL parsing entry point
│ │ └── context/ # Session state (statements, portals, metadata)
│ ├── proxy/ # Encryption service, schema management, config
│ └── config/ # Configuration parsing
│ ├── config/ # Configuration parsing
│ ├── cli/ # CLI argument parsing
│ ├── connect/ # Database connection management
│ ├── tls/ # TLS configuration and setup
│ └── log/ # Logging targets and configuration
├── eql-mapper/ # SQL type inference and transformation
│ └── src/
│ ├── inference/ # Type inference engine
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Added

- **Cipher cache miss metric**: New Prometheus counter `cipherstash_proxy_keyset_cipher_cache_miss_total` tracks cache misses requiring cipher initialization. This complements the `cipherstash_proxy_keyset_cipher_cache_hit_total` metric, and can be used to calculate cache hit/miss ratio.
- **Cipher cache miss metric**: New Prometheus counter `cipherstash_proxy_keyset_cipher_cache_miss_total` tracks cache misses requiring cipher initialization. This complements the `cipherstash_proxy_keyset_cipher_cache_hits_total` metric, and can be used to calculate cache hit/miss ratio.
- **Cipher init duration metric**: New Prometheus histogram `cipherstash_proxy_keyset_cipher_init_duration_seconds` tracks cipher initialization time including ZeroKMS network calls.
- **Encrypt/decrypt timing**: Debug logs for `encrypt_eql` and `decrypt_eql` now include `duration_ms`.
- **Cache eviction logging**: ScopedCipher cache eviction events are now logged under the `ZEROKMS` target.
Expand Down
11 changes: 7 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ Key capabilities:

**Core Proxy (`packages/cipherstash-proxy/`):**
- `postgresql/` - PostgreSQL wire protocol implementation, message parsing, and client handling
- `encrypt/` - Integration with CipherStash ZeroKMS for key management and encryption operations
- `proxy/zerokms/` - ZeroKMS client initialization and key management
- `config/` - Configuration management for database connections, TLS, and encryption settings
- `eql/` - EQL v2 types and encryption abstractions
- `proxy/encrypt_config/` - Encryption configuration and schema management

**EQL Mapper (`packages/eql-mapper/`):**
- SQL parsing and type inference engine
Expand All @@ -29,7 +29,9 @@ Key capabilities:

**Integration Tests (`packages/cipherstash-proxy-integration/`):**
- Comprehensive test suite covering encryption scenarios
- Language-specific integration tests (Python, Go, Elixir)

**Language Integration Tests (`tests/python/`, `tests/integration/golang/`):**
- Language-specific integration tests (Python, Go)

**Showcase (`packages/showcase/`):**
- Healthcare data model demonstrating EQL v2 encryption
Expand Down Expand Up @@ -82,7 +84,7 @@ mise run reset
# Full test suite (hygiene + unit + integration)
mise run test

# Hygiene checks only
# Hygiene checks (compilation, formatting, clippy)
mise run check

# Unit tests only
Expand Down Expand Up @@ -117,6 +119,7 @@ mise run postgres:down
### Authentication & Encryption
Proxy requires CipherStash credentials configured in `mise.local.toml`:
```toml
[env]
CS_WORKSPACE_CRN = "crn:region:workspace-id"
CS_CLIENT_ACCESS_KEY = "your-access-key"
CS_DEFAULT_KEYSET_ID = "your-keyset-id"
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ Please do not create a public GitHub issue.
## Code of Conduct

This project has adopted the [Contributor Covenant](https://www.contributor-covenant.org/).
For more information see the [Code of Conduct FAQ](./CODE_OF_CONDUCT.md) or contact support@cipherstash.com with any questions.
For more information see the [Code of Conduct](./CODE_OF_CONDUCT.md) or contact support@cipherstash.com with any questions.

## Licensing

See the [LICENSE](./LICENSE) file for our project's licensing.
See the [LICENSE](./LICENSE.md) file for our project's licensing.
6 changes: 3 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ To use a different version of EQL, set the path to the desired EQL release file

PostgreSQL port numbers are 4 digits:

- The first two digits denote non-TLS (`55`) or non-TLS (`56`)
- The first two digits denote non-TLS (`55`) or TLS (`56`)
- The last two digits denote the version of PostgreSQL

PostgreSQL latest always runs on `5532`.
Expand Down Expand Up @@ -475,7 +475,7 @@ All containers use the same credentials and database, defined in `tests/pg/commo
POSTGRES_DB="cipherstash"
POSTGRES_USER="cipherstash"
PGUSER="cipherstash"
POSTGRES_PASSWORD="password"
POSTGRES_PASSWORD="p@ssword"
```

PostgreSQL configuration files live at:
Expand All @@ -501,7 +501,7 @@ Environment files:

If you ever get confused about where your configuration is coming from, run `mise cfg` to get a list of config files in use.

Certificates are generated by `mkcert`, and live in `tests/tls/`.
Certificates are generated by `openssl`, and live in `tests/tls/`.


#### Configuration: development endpoints
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@

<!-- start -->

## Proxy V2 now available

[Read the announcement](https://cipherstash.com/blog/introducing-proxy)

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

CipherStash Proxy:
Expand Down Expand Up @@ -68,9 +64,15 @@ cd proxy
# Sign up, create a workspace, and generate credentials
# Visit: https://dashboard.cipherstash.com/sign-up

# Put credentials in .env.proxy.docker
# Copy the credentials from the dashboard and paste them into .env.proxy.docker using your preferred text editor.
nano .env.proxy.docker
# Create .env.proxy.docker with your CipherStash credentials
# Replace the placeholder values with your actual credentials from the dashboard
cat > .env.proxy.docker << 'EOF'
CS_WORKSPACE_CRN=crn:...your-workspace-crn...
CS_CLIENT_ACCESS_KEY=your-client-access-key
CS_DEFAULT_KEYSET_ID=your-keyset-id
CS_CLIENT_ID=your-client-id
CS_CLIENT_KEY=your-client-key
EOF
Comment thread
Copilot marked this conversation as resolved.

# Start the containers
docker compose up
Expand Down
9 changes: 3 additions & 6 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ This repository contains the source code for CipherStash Proxy, including:

### CipherStash Proxy

| Version | Supported |
| ------- | ------------------ |
| 2.1.x | :white_check_mark: |
| < 2.1 | :x: |
**Security fixes are released for the latest release line.** Security reports are welcome for any version, but fixes land in the latest release — if you are running an older version, plan to upgrade to receive them.


All software follows semantic versioning and undergoes internal security review, automated analysis, and reproducible builds as part of our SDLC.
Expand Down Expand Up @@ -74,7 +71,7 @@ The following are **in scope**:

The following are **out of scope**:

- Example [schema](./docs/sql/schema-example.sql) and [configuration](./cipherstash-proxy-example.toml) (though we are still grateful for any relevant disclosires there)
- Example [schema](./docs/sql/schema-example.sql) and [configuration](./cipherstash-proxy-example.toml) (though we are still grateful for any relevant disclosures there)
- Social engineering, physical attacks, or denial-of-service
- Attacks requiring privileged access to developer machines or CI/CD infrastructure

Expand All @@ -92,7 +89,7 @@ To maintain a strong security posture, contributors MUST:
### 🛡 Coding & dependency hygiene
- Avoid adding dependencies unless necessary
- Keep dependencies updated and vetted
- Use TypeScript for all new code
- Use Rust for all new code
- Ensure all code paths that handle keys or encrypted data include type-safe boundaries

### 🔍 Testing & review
Expand Down
11 changes: 5 additions & 6 deletions cipherstash-proxy-example.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
[tls]
type = "Path" # To provide paths to PEM files
certificate = "tests/tls/server.cert"
private_key = "tests/tls/server.key"
certificate_path = "tests/tls/server.cert"
private_key_path = "tests/tls/server.key"

# type = "Pem" # To directly provide PEM contents
# certificate = """-----BEGIN CERTIFICATE-----
# To directly provide PEM contents:
# certificate_pem = """-----BEGIN CERTIFICATE-----
# ...your certificate content here...
# -----END CERTIFICATE-----
# """
# private_key = """-----BEGIN PRIVATE KEY-----
# private_key_pem = """-----BEGIN PRIVATE KEY-----
# ...your private key content here...
# -----END PRIVATE KEY-----
# """
Expand Down
47 changes: 43 additions & 4 deletions docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Authentication errors:
- [Database](#authentication-failed-database)
- [Client](#authentication-failed-client)
- [ZeroKMS](#zerokms-authentication-failed)

- Mapping errors:
- [Invalid parameter](#mapping-invalid-parameter)
Expand All @@ -15,8 +16,7 @@

- Encrypt errors:
- [Column could not be encrypted](#encrypt-column-could-not-be-encrypted)
- [Column could not be encrypted](#encrypt-column-could-not-be-encrypted)
- [Could not decrypt data for keyset](#encrypt-encrypt-could-not-decrypt-data-for-keyset)
- [Could not decrypt data for keyset](#encrypt-could-not-decrypt-data-for-keyset)
- [KeysetId could not be parsed](#encrypt-keyset-id-could-not-be-parsed)
- [KeysetId could not be set](#encrypt-keyset-id-could-not-be-set)
- [KeysetName could not be set](#encrypt-keyset-name-could-not-be-set)
Expand All @@ -26,6 +26,8 @@
- [Unknown table](#encrypt-unknown-table)
- [Unknown index term](#encrypt-unknown-index-term)
- [Column configuration mismatch](#encrypt-column-config-mismatch)
- [Missing encrypt configuration](#encrypt-missing-encrypt-configuration)
- [Unexpected SET keyset](#encrypt-unexpected-set-keyset)

- Decrypt errors:
- [Column could not be deserialised](#encrypt-column-could-not-be-deserialised)
Expand Down Expand Up @@ -91,7 +93,7 @@ Client authentication failed. Check username and password.
<!-- ---------------------------------------------------------------------------------------------------- -->


## ZeroKMS <a id='authentication-failed-zerokms'></a>
## ZeroKMS <a id='zerokms-authentication-failed'></a>

Authentication failed when connecting to ZeroKMS.

Expand Down Expand Up @@ -184,7 +186,7 @@ The parameter type is not supported.
### Error message

```
Encryption of PostgreSQL {name} (OID {oid}) types is not currently supported.
Encryption of EQL column {column_type} using strategy {eql_term} is not supported.
```

### How to fix
Expand Down Expand Up @@ -218,6 +220,8 @@ When `mapping_errors_enabled` is `false` (the default), then type check errors a

When `mapping_errors_enabled` is `true`, then type check errors are raised, and statement execution halts.

Configure this setting with the environment variable `CS_DEVELOPMENT__ENABLE_MAPPING_ERRORS` or in the TOML config file under `[development] enable_mapping_errors = true`.

In our experience, most production systems have a relatively small number of columns that require protection.
As SQL is large and complex, instead of blocking statements with type check errors that are false negatives, the default behaviour of Proxy is to allow the statement.

Expand Down Expand Up @@ -577,6 +581,41 @@ If the error persists, please contact CipherStash [support](https://cipherstash.
<!-- ---------------------------------------------------------------------------------------------------- -->


## Missing encrypt configuration <a id='encrypt-missing-encrypt-configuration'></a>

The encrypted column type does not have a matching encrypt configuration.


### Error message

```
Missing encrypt configuration for column type `{plaintext_type}`.
```

### How to fix

1. Define the encrypted configuration for the column type using [EQL](https://github.com/cipherstash/encrypt-query-language).
2. If this error persists, please contact CipherStash [support](https://cipherstash.com/support) as this may indicate a bug.


<!-- ---------------------------------------------------------------------------------------------------- -->


## Unexpected SET keyset <a id='encrypt-unexpected-set-keyset'></a>

A `SET CIPHERSTASH.KEYSET` statement was used when a default keyset has already been configured.


### Error message

```
Cannot SET CIPHERSTASH.KEYSET if a default keyset has been configured.
```

### How to fix

1. Remove the `SET CIPHERSTASH.KEYSET` statement from your application code.
2. Or remove the `default_keyset_id` from the proxy configuration to allow dynamic keyset selection.


<!-- ---------------------------------------------------------------------------------------------------- -->
Expand Down
28 changes: 24 additions & 4 deletions docs/how-to/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ services:
```


For a fully-working example, go to [`docker-compose.yml`](./docker-compose.yml).
For a fully-working example, go to [`docker-compose.yml`](../../docker-compose.yml).
Follow the steps in [Getting started](../README.md#getting-started) to see it in action.

Once you have set up a `docker-compose.yml`, start the Proxy container:
Expand Down Expand Up @@ -132,7 +132,27 @@ Read the full list of configuration options and what they do in the [reference d

## Running Proxy locally

TODO: Add instructions for running Proxy locally
To run CipherStash Proxy locally for development:

```bash
# Install prerequisites
mise trust --yes && mise install

# Start PostgreSQL and install EQL
mise run postgres:up --extra-args "--detach --wait"
mise run postgres:setup

# Run Proxy as a local process
mise run proxy
```

Alternatively, run Proxy in a container:

```bash
mise run proxy:up --extra-args "--detach --wait"
```

See [Configuring Proxy](#configuring-proxy) for required environment variables and configuration options.

## Setting up the database schema

Expand Down Expand Up @@ -233,14 +253,14 @@ The third SQL statement adds an `ope` index, which supports the same range and o
`ore` and `ope` are alternatives for range and ordering queries — add one or the other to a column, not both. `ore` is the recommended default. `ope` produces ciphertexts that sort under PostgreSQL's native byte ordering, which makes ordering and range scans cheaper, but as an order-preserving scheme it reveals more about the relative order of stored values than `ore` does. Choose based on your performance and threat-model requirements; see the [EQL `INDEX` documentation](https://github.com/cipherstash/encrypt-query-language/blob/main/docs/reference/INDEX.md) for the full tradeoffs.


> ![IMPORTANT]
> [!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](https://github.com/cipherstash/encrypt-query-language/blob/main/docs/reference/INDEX.md).

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.

To see more examples of how to modify your database schema, check out [the example schema](./sql/schema-example.sql) from [Getting started](#getting-started).
To see more examples of how to modify your database schema, check out [the example schema](../sql/schema-example.sql) from [Getting started](#getting-started).

## Encrypting data in an existing database

Expand Down
4 changes: 2 additions & 2 deletions docs/reference/encrypt-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CipherStash Proxy includes an `encrypt` tool – a CLI application to encrypt ex
## Using the `encrypt` tool

Encrypt the `source` column data in `table` into the specified encrypted `target` column.
The `encrypt` tool connects to CipherStash Proxy using the `cipherstash.toml` configuration or `ENV` variables.
The `encrypt` tool connects to CipherStash Proxy using the `cipherstash-proxy.toml` configuration or `ENV` variables.

```
cipherstash-proxy encrypt [OPTIONS] --table <TABLE> --columns <SOURCE_COLUMN=TARGET_COLUMN>...
Expand All @@ -25,7 +25,7 @@ At a high-level, the process for encrypting a column in the database is:
1. Add a new encrypted destination column with the appropriate encryption configuration.
2. Using CipherStash Proxy to process:
1. Select from the original plaintext column.
2. Update the encrpted column to set the plaintext value.
2. Update the encrypted column to set the plaintext value.
3. Drop the original plaintext column.
4. Rename the encrypted column to the original plaintext column name.

Expand Down
Loading
Loading