diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f26ae5e0..36a0d08e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index c2e049d4..cbcf286f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed - **Log target renamed**: `KEYSET` log target renamed to `ZEROKMS`. The environment variable `CS_LOG__KEYSET_LEVEL` is now `CS_LOG__ZEROKMS_LEVEL`. +- **Dependency upgrade**: Updated `cipherstash-client` from 0.33.2 to 0.34.0-alpha.4 with new `ZeroKMSBuilder` API and `AutoStrategy` authentication. ### Removed @@ -18,7 +19,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. diff --git a/CLAUDE.md b/CLAUDE.md index 58ead9cd..067ff964 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 @@ -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 @@ -76,7 +78,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 @@ -111,6 +113,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" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 623c1e35..0986a6df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,4 +38,4 @@ For more information see the [Code of Conduct FAQ](./CODE_OF_CONDUCT.md) or cont ## Licensing -See the [LICENSE](./LICENSE) file for our project's licensing. +See the [LICENSE](./LICENSE.md) file for our project's licensing. diff --git a/Cargo.lock b/Cargo.lock index 11adb87b..9cf56787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "tokio-util", "tracing", "tracing-subscriber", + "url", "uuid", "vitaminc-protected", "x509-parser", @@ -1683,9 +1684,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -2270,9 +2271,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -2997,9 +2998,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pg_escape" @@ -5045,14 +5046,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 54688d28..6e0dbb0c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -427,7 +427,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`. @@ -470,7 +470,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: @@ -496,7 +496,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 diff --git a/README.md b/README.md index 05ff580b..fed5c61f 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,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_ENCRYPT__DEFAULT_KEYSET_ID=your-keyset-id +CS_ENCRYPT__CLIENT_ID=your-client-id +CS_ENCRYPT__CLIENT_KEY=your-client-key +EOF # Start the containers docker compose up diff --git a/cipherstash-proxy-example.toml b/cipherstash-proxy-example.toml index 1851d6a8..77319993 100644 --- a/cipherstash-proxy-example.toml +++ b/cipherstash-proxy-example.toml @@ -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----- # """ diff --git a/docs/errors.md b/docs/errors.md index 670df8b7..9d8e5adf 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -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) @@ -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) @@ -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) @@ -91,7 +93,7 @@ Client authentication failed. Check username and password. -## ZeroKMS +## ZeroKMS Authentication failed when connecting to ZeroKMS. @@ -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 @@ -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. @@ -577,6 +581,41 @@ If the error persists, please contact CipherStash [support](https://cipherstash. +## Missing encrypt configuration + +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 `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. diff --git a/docs/how-to/index.md b/docs/how-to/index.md index 4e35f3bf..01f7a808 100644 --- a/docs/how-to/index.md +++ b/docs/how-to/index.md @@ -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: @@ -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 @@ -223,14 +243,14 @@ The first SQL statement adds a `match` index, which is used for partial matches The second SQL statement adds an `ore` index, which is used for ordering with `ORDER BY`. -> ![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 diff --git a/docs/reference/index.md b/docs/reference/index.md index 964c8d0b..f460a99b 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -16,7 +16,7 @@ This page contains reference documentation for configuring CipherStash Proxy and ## Proxy config options -You can configure CipherStash Proxy with a config file, enviroment variables, or a combination of the two – see [Configuring Proxy](#configuring-proxy) for instructions. +You can configure CipherStash Proxy with a config file, environment variables, or a combination of the two – see [Configuring Proxy](#configuring-proxy) for instructions. The following are all the configuration options available for Proxy, with their equivalent environment variables: @@ -29,7 +29,7 @@ The following are all the configuration options available for Proxy, with their # Env: CS_SERVER__HOST host = "0.0.0.0" -# Proxy host posgt +# Proxy host port # Optional # Default: `6432` # Env: CS_SERVER__PORT @@ -60,8 +60,8 @@ worker_threads = "4" # Env: CS_SERVER__THREAD_STACK_SIZE thread_stack_size = "2097152" -# Cipher cache size (number of entries) -# Sets the maximum number of encryption/decryption operations to cache +# Cipher cache size (number of keyset-scoped ciphers) +# Sets the maximum number of keyset-scoped ciphers to cache (internal sizing is calculated per entry) # Optional # Default: `64` # Env: CS_SERVER__CIPHER_CACHE_SIZE @@ -82,7 +82,7 @@ cipher_cache_ttl_seconds = "3600" # Env: CS_DATABASE__HOST host = "0.0.0.0" -# Database host post +# Database host port # Optional # Default: `5432` # Env: CS_DATABASE__PORT @@ -199,7 +199,7 @@ format = "pretty" # Log format # Optional # Valid values: `stdout | stderr` -# Default: `info` +# Default: `stdout` # Env: CS_LOG__OUTPUT output = "stdout" @@ -238,7 +238,7 @@ slow_db_response_min_duration_ms = "100" # Env: CS_PROMETHEUS__ENABLED enabled = "false" -# Prometheus exporter post +# Prometheus exporter port # Optional # Default: `9930` # Env: CS_PROMETHEUS__PORT @@ -562,6 +562,8 @@ If the proxy is running on a host other than localhost, access on that host. | `cipherstash_proxy_statements_session_duration_seconds_sum` | Count | Total time CipherStash Proxy spent processing SQL statements | | `cipherstash_proxy_statements_encrypted_total` | Counter | Number of SQL statements that required encryption | | `cipherstash_proxy_statements_passthrough_total` | Counter | Number of SQL statements that did not require encryption | +| `cipherstash_proxy_statements_passthrough_mapping_disabled_total` | Counter | Number of SQL statements passed through because mapping was disabled | +| `cipherstash_proxy_slow_statements_total` | Counter | Number of SQL statements that exceeded the slow statement threshold | | `cipherstash_proxy_statements_total` | Counter | Total number of SQL statements processed by CipherStash Proxy | | `cipherstash_proxy_statements_unmappable_total` | Counter | Total number of unmappable SQL statements processed by CipherStash Proxy | @@ -629,9 +631,9 @@ rate(cipherstash_proxy_keyset_cipher_cache_hits_total[5m]) ## Supported architectures -CipherStash Proxy is [available as a Docker container image](https://hub.docker.com/r/cipherstash/proxy) for `linux/arm64` architectures. +CipherStash Proxy is [available as a Docker container image](https://hub.docker.com/r/cipherstash/proxy) for `linux/arm64` and `linux/amd64` architectures. -If you're interested in a Docker image for other architectures (like `linux/amd64`), upvote [this idea](https://github.com/cipherstash/proxy/discussions/214). +For other architecture requests, see [this discussion](https://github.com/cipherstash/proxy/discussions/214). diff --git a/docs/reference/message-flow.md b/docs/reference/message-flow.md index 74293eb7..0ec46c41 100644 --- a/docs/reference/message-flow.md +++ b/docs/reference/message-flow.md @@ -4,9 +4,6 @@ Below are the flow diagrams for the message handling in CipherStash Proxy for Po ### Parse -![Parse message](./images/parse.svg "Parse") - - ```mermaid --- config: @@ -27,8 +24,6 @@ flowchart LR ### Bind -![Bind message](./images/bind.svg "Bind") - ```mermaid --- config: diff --git a/docs/reference/searchable-json.md b/docs/reference/searchable-json.md index 5f1329d8..12127830 100644 --- a/docs/reference/searchable-json.md +++ b/docs/reference/searchable-json.md @@ -6,7 +6,7 @@ This document outlines the supported JSONB functions and operators in CipherStas ## Table of Contents - [Setup](#setup) -- [Important Limtiations](#important-limitations) +- [Important Limitations](#important-limitations) - [Operators](#operators) - [->](#field_access_operator) - [->>](#field_access_as_text_operator) @@ -302,7 +302,7 @@ SELECT encrypted_jsonb @> '{"number": 99}' FROM cipherstash; ```sql -- nested object -SELECT encrypted_jsonb @> '{"object": {"string": "world", "number": 99},' FROM cipherstash; +SELECT encrypted_jsonb @> '{"object": {"string": "world", "number": 99}}' FROM cipherstash; ---------- ?column? @@ -334,7 +334,7 @@ SELECT '{ .. }' <@ encrypted_column FROM table_name; ```sql -- field/value returns true -SELECT '{"number": 1}' @> encrypted_jsonb FROM cipherstash; +SELECT '{"number": 1}' <@ encrypted_jsonb FROM cipherstash; ---------- ?column? @@ -345,7 +345,7 @@ SELECT '{"number": 1}' @> encrypted_jsonb FROM cipherstash; ```sql -- field/value returns false if no match -SELECT '{"number": 99}' @> encrypted_jsonb FROM cipherstash; +SELECT '{"number": 99}' <@ encrypted_jsonb FROM cipherstash; ---------- ?column? @@ -357,7 +357,7 @@ SELECT '{"number": 99}' @> encrypted_jsonb FROM cipherstash; ```sql -- nested object -SELECT '{"object": {"string": "world", "number": 99}' @> encrypted_jsonb FROM cipherstash; +SELECT '{"object": {"string": "world", "number": 99}}' <@ encrypted_jsonb FROM cipherstash; ---------- ?column? @@ -627,84 +627,6 @@ SELECT jsonb_array_length(jsonb_path_query(encrypted_jsonb, '$.unknown')) FROM c (0 rows) ``` ---------------------------------------------------------------- - - - - - - - - - -======================================= - - - - - - - - ---------------------------------------------------------------- - - - -## Containment Operators - -> **Note:** Containment operators work directly with JSONB literals without requiring explicit `::jsonb` type casts. The examples below use the simplified syntax intentionally. - -### `@>` (Contains Operator) - -Tests whether the left JSONB value contains the right JSONB value. - -**Syntax:** -```sql -SELECT encrypted_jsonb @> '{"field": "value"}' FROM table_name; -``` - -**Examples:** -```sql --- Check if contains string field -SELECT encrypted_jsonb @> '{"string": "hello"}' FROM encrypted; - --- Check if contains numeric field -SELECT encrypted_jsonb @> '{"number": 42}' FROM encrypted; - --- Check if contains array -SELECT encrypted_jsonb @> '{"array_number": [42, 84]}' FROM encrypted; - --- Check if contains nested object -SELECT encrypted_jsonb @> '{"nested": {"number": 1815, "string": "world"}}' FROM encrypted; -``` - -**Supported Containment Types:** -- String fields -- Numeric fields -- Complete arrays -- Nested objects - -### `<@` (Contained By Operator) - -Tests whether the left JSONB value is contained by the right JSONB value. - -**Syntax:** -```sql -SELECT '{"field": "value"}' <@ encrypted_jsonb FROM table_name; -``` - -**Examples:** -```sql --- Check if value is contained by the document -SELECT '{"string": "hello"}' <@ encrypted_jsonb FROM encrypted; - --- Check numeric containment -SELECT '{"number": 42}' <@ encrypted_jsonb FROM encrypted; - --- Check array containment -SELECT '{"array_string": ["hello", "world"]}' <@ encrypted_jsonb FROM encrypted; -``` - ## Comparison Operators in WHERE Clauses All standard comparison operators work with JSON field extraction: diff --git a/packages/cipherstash-proxy/Cargo.toml b/packages/cipherstash-proxy/Cargo.toml index 077764ff..364a229c 100644 --- a/packages/cipherstash-proxy/Cargo.toml +++ b/packages/cipherstash-proxy/Cargo.toml @@ -57,6 +57,7 @@ tracing-subscriber = { workspace = true } uuid = { version = "1.11.0", features = ["serde", "v4"] } vitaminc-protected = "0.1.0-pre4.2" x509-parser = "0.17.0" +url = "2.5.8" [dev-dependencies] diff --git a/packages/cipherstash-proxy/src/config/tandem.rs b/packages/cipherstash-proxy/src/config/tandem.rs index f149144d..9de837c0 100644 --- a/packages/cipherstash-proxy/src/config/tandem.rs +++ b/packages/cipherstash-proxy/src/config/tandem.rs @@ -67,6 +67,12 @@ pub struct DevelopmentConfig { #[serde(default)] pub enable_mapping_errors: bool, + + #[serde(default)] + pub zerokms_host: Option, + + #[serde(default)] + pub cts_host: Option, } /// Config defaults to a file called `tandem` in the current directory. @@ -252,6 +258,18 @@ impl TandemConfig { } } + pub fn zerokms_host(&self) -> Option { + self.development + .as_ref() + .and_then(|dev| dev.zerokms_host.clone()) + } + + pub fn cts_host(&self) -> Option { + self.development + .as_ref() + .and_then(|dev| dev.cts_host.clone()) + } + pub fn use_structured_logging(&self) -> bool { matches!(self.log.format, LogFormat::Structured) } diff --git a/packages/cipherstash-proxy/src/error.rs b/packages/cipherstash-proxy/src/error.rs index 98b8421f..f418aa7f 100644 --- a/packages/cipherstash-proxy/src/error.rs +++ b/packages/cipherstash-proxy/src/error.rs @@ -125,10 +125,7 @@ pub enum ConfigError { #[error("Client key is not valid. For help visit {}", ERROR_DOC_CONFIG_URL)] InvalidClientKey, - #[error( - "default_keyset_id is not a valid UUID. For help visit {}", - ERROR_DOC_CONFIG_URL - )] + #[error("default_keyset_id is not a valid UUID.")] InvalidDefaultKeysetId, #[error("Server host {name} is not a valid server name")] diff --git a/packages/cipherstash-proxy/src/proxy/zerokms/mod.rs b/packages/cipherstash-proxy/src/proxy/zerokms/mod.rs index f4e337e7..e0ebd1d3 100644 --- a/packages/cipherstash-proxy/src/proxy/zerokms/mod.rs +++ b/packages/cipherstash-proxy/src/proxy/zerokms/mod.rs @@ -10,12 +10,22 @@ use cipherstash_client::{ zerokms::{ClientKey, ZeroKMSBuilder}, AutoStrategy, ZeroKMS, }; +use url::Url; pub type ScopedCipher = cipherstash_client::encryption::ScopedCipher; pub type ZerokmsClient = ZeroKMS; pub(crate) fn init_zerokms_client(config: &TandemConfig) -> Result { + if config.cts_host().is_some() { + tracing::warn!( + target: "config", + "development.cts_host is configured but no longer supported. \ + CTS endpoint is now resolved automatically from credentials. \ + Remove development.cts_host from your configuration." + ); + } + let strategy = AutoStrategy::builder() .with_access_key(&config.auth.client_access_key) .with_workspace_crn(config.auth.workspace_crn.clone()) @@ -27,6 +37,17 @@ pub(crate) fn init_zerokms_client(config: &TandemConfig) -> Result **Note:** Elixir integration tests are currently disabled pending a fix for test flakiness. diff --git a/tests/integration/golang/README.md b/tests/integration/golang/README.md index 5a4fe9a7..697d2ef1 100644 --- a/tests/integration/golang/README.md +++ b/tests/integration/golang/README.md @@ -29,7 +29,7 @@ Alternatively, to run the tests outside of the container: ``` bash # Tell the tests where to find Proxy -export DATABASE_URL="postgresql://cipherstash:password@localhost:6432/cipherstash" +export DATABASE_URL="postgresql://cipherstash:p%40ssword@localhost:6432/cipherstash" # Run the tests go test -v ./...