Configuration
Install and configure CipherStash Proxy: Docker, TOML and environment variables, logging, Prometheus metrics, and the CLI.
CipherStash Proxy is available as a container image on Docker Hub. Deploy it locally, as a cloud sidecar, or as a standalone binary. It speaks the PostgreSQL protocol, so your application connects to Proxy exactly the same way it connects to PostgreSQL.
Installing Proxy
The quickest way to run Proxy alongside your application is to add a container to your docker-compose.yml:
services:
app:
# Your app container config
db:
# Your Postgres container config
proxy:
image: cipherstash/proxy:latest
container_name: proxy
ports:
- 6432:6432
- 9930:9930
environment:
- CS_DATABASE__HOST=${CS_DATABASE__HOST}
- CS_DATABASE__PORT=${CS_DATABASE__PORT}
- CS_DATABASE__USERNAME=${CS_DATABASE__USERNAME}
- CS_DATABASE__PASSWORD=${CS_DATABASE__PASSWORD}
- CS_DATABASE__NAME=${CS_DATABASE__NAME}
- CS_WORKSPACE_CRN=${CS_WORKSPACE_CRN}
- CS_CLIENT_ACCESS_KEY=${CS_CLIENT_ACCESS_KEY}
- CS_DEFAULT_KEYSET_ID=${CS_DEFAULT_KEYSET_ID}
- CS_CLIENT_ID=${CS_CLIENT_ID}
- CS_CLIENT_KEY=${CS_CLIENT_KEY}
- CS_PROMETHEUS__ENABLED=${CS_PROMETHEUS__ENABLED:-true}For a fully working example, see the docker-compose.yml in the Proxy repository.
Start the container, then connect your PostgreSQL client to Proxy on TCP 6432:
docker compose upUnlike the Stack SDK, Proxy always requires credentials to be supplied explicitly, because it runs as a separate process or container and cannot use the host's device-based authentication.
Create the four variables with stash env or the Dashboard, then supply them to the Proxy container. Workspace credentials shows both options and the complete environment block.
Setting up the database schema
Proxy queries encrypted data through EQL, which must be installed in the target database. Encrypted columns are typed with an EQL domain such as public.eql_v3_text_eq, and that type is what fixes the column's searchable capability. There is no database-side configuration table.
- Install EQL covers the install itself, including the permissions split and Supabase.
- Core concepts covers the variant model and which domain type to choose.
- Indexes covers adding functional indexes over the term extractors.
In development, the Proxy container can install EQL for you on startup:
CS_DATABASE__INSTALL_EQL=trueCheck the installed version:
SELECT eql_v3.version();CS_DATABASE__INSTALL_EQL is for development only. In production, install EQL as a database migration.
Configuration loading order
Proxy accepts configuration from a TOML file, environment variables, or both.
- If
cipherstash-proxy.tomlexists in the current working directory, Proxy reads it first. - Proxy then reads any environment variables that are set.
- When both are present, environment variables override values from the TOML file.
Config options
[server]
| Option | Env variable | Default | Description |
|---|---|---|---|
host | CS_SERVER__HOST | 0.0.0.0 | Proxy listen address |
port | CS_SERVER__PORT | 6432 | Proxy listen port |
require_tls | CS_SERVER__REQUIRE_TLS | false | Enforce TLS for client-to-proxy connections |
shutdown_timeout | CS_SERVER__SHUTDOWN_TIMEOUT | 2000 | Milliseconds to wait for connections to drain on shutdown |
worker_threads | CS_SERVER__WORKER_THREADS | NUMBER_OF_CORES/2 or 4 | Number of server worker threads |
thread_stack_size | CS_SERVER__THREAD_STACK_SIZE | 2097152 (2 MiB) | Thread stack size in bytes. Automatically set to 4 MiB when log level is debug or trace |
cipher_cache_size | CS_SERVER__CIPHER_CACHE_SIZE | 64 | Maximum number of encryption/decryption operations to cache |
cipher_cache_ttl_seconds | CS_SERVER__CIPHER_CACHE_TTL_SECONDS | 3600 | Seconds before cached cipher operations expire |
[database]
| Option | Env variable | Default | Description |
|---|---|---|---|
host | CS_DATABASE__HOST | 0.0.0.0 | Database host address |
port | CS_DATABASE__PORT | 5432 | Database port |
name | CS_DATABASE__NAME | (required) | Database name |
username | CS_DATABASE__USERNAME | (required) | Database username |
password | CS_DATABASE__PASSWORD | (required) | Database password |
connection_timeout | CS_DATABASE__CONNECTION_TIMEOUT | none | Milliseconds to hold an idle connection open. In production, set this higher than your application's connection pool idle timeout |
with_tls_verification | CS_DATABASE__WITH_TLS_VERIFICATION | false | Enable TLS verification between Proxy and the database |
config_reload_interval | CS_DATABASE__CONFIG_RELOAD_INTERVAL | 60 | Seconds between encrypted index configuration reloads |
schema_reload_interval | CS_DATABASE__SCHEMA_RELOAD_INTERVAL | 60 | Seconds between database schema reloads |
[tls]
Configure TLS for client-to-proxy connections. Provide either file paths or inline PEM strings.
| Option | Env variable | Description |
|---|---|---|
certificate_path | CS_TLS__CERTIFICATE_PATH | Path to the public certificate .crt file |
private_key_path | CS_TLS__PRIVATE_KEY_PATH | Path to the private key file |
certificate_pem | CS_TLS__CERTIFICATE_PEM | Public certificate as a PEM string |
private_key_pem | CS_TLS__PRIVATE_KEY_PEM | Private key as a PEM string |
[auth]
| Option | Env variable | Description |
|---|---|---|
workspace_crn | CS_WORKSPACE_CRN | CipherStash workspace CRN |
client_access_key | CS_CLIENT_ACCESS_KEY | CipherStash client access key |
[encrypt]
| Option | Env variable | Description |
|---|---|---|
default_keyset_id | CS_DEFAULT_KEYSET_ID | Default keyset. Omit to enable multitenant operation |
client_id | CS_CLIENT_ID | CipherStash client ID |
client_key | CS_CLIENT_KEY | CipherStash client key |
[log]
| Option | Env variable | Default | Description |
|---|---|---|---|
level | CS_LOG__LEVEL | info | Global log level. Valid values: error, warn, info, debug, trace |
format | CS_LOG__FORMAT | pretty (terminal), structured (non-terminal) | Log format. Valid values: pretty, text, structured (JSON) |
output | CS_LOG__OUTPUT | stdout | Log output destination. Valid values: stdout, stderr |
ansi_enabled | CS_LOG__ANSI_ENABLED | true (terminal), false (non-terminal) | Enable colored output |
slow_statements | CS_LOG__SLOW_STATEMENTS | false | Enable slow statement logging |
slow_statement_min_duration_ms | CS_LOG__SLOW_STATEMENT_MIN_DURATION_MS | 2000 | Minimum duration in milliseconds for a statement to be considered slow |
slow_db_response_min_duration_ms | CS_LOG__SLOW_DB_RESPONSE_MIN_DURATION_MS | 100 | Minimum duration in milliseconds for a database response to be considered slow |
[prometheus]
| Option | Env variable | Default | Description |
|---|---|---|---|
enabled | CS_PROMETHEUS__ENABLED | false | Enable the Prometheus metrics exporter |
port | CS_PROMETHEUS__PORT | 9930 | Port for the Prometheus exporter |
Full TOML example
[server]
host = "0.0.0.0"
port = "6432"
require_tls = "false"
shutdown_timeout = "2000"
worker_threads = "4"
thread_stack_size = "2097152"
cipher_cache_size = "64"
cipher_cache_ttl_seconds = "3600"
[database]
host = "0.0.0.0"
port = "5432"
name = "database"
username = "username"
password = "password"
connection_timeout = "300000"
with_tls_verification = "false"
config_reload_interval = "60"
schema_reload_interval = "60"
[tls]
certificate_path = "./server.crt"
private_key_path = "./server.key"
[auth]
workspace_crn = "cipherstash-workspace-crn"
client_access_key = "cipherstash-client-access-key"
[encrypt]
default_keyset_id = "cipherstash-keyset-id"
client_id = "cipherstash-client-id"
client_key = "cipherstash-client-key"
[log]
level = "info"
format = "pretty"
output = "stdout"
ansi_enabled = "true"
slow_statements = "false"
slow_statement_min_duration_ms = "2000"
slow_db_response_min_duration_ms = "100"
[prometheus]
enabled = "false"
port = "9930"Development settings
Defaults are tuned for production. When running Proxy locally, override these for a better development experience. None of these settings are appropriate for production.
Enable colored, human-readable logs:
CS_LOG__FORMAT="pretty"
CS_LOG__ANSI_ENABLED="true"Reduce reload intervals when iterating on your schema:
CS_DATABASE__CONFIG_RELOAD_INTERVAL="10"
CS_DATABASE__SCHEMA_RELOAD_INTERVAL="10"Slow query logging
Slow query logging identifies statements that take longer than expected:
CS_LOG__SLOW_STATEMENTS="true"By default, any statement taking longer than 2000 ms is flagged. Tune the thresholds to match your latency expectations:
CS_LOG__SLOW_STATEMENT_MIN_DURATION_MS="500" # statement total time
CS_LOG__SLOW_DB_RESPONSE_MIN_DURATION_MS="200" # database round-trip onlyWhen a slow statement is detected, Proxy emits a structured log line at the SLOW_STATEMENTS target. With format = "pretty", it looks like:
WARN slow_statement duration_ms=620 query="SELECT * FROM users WHERE ..."Use these lines to find queries that need indexes. A query that is unexpectedly slow is usually missing a functional index over the term extractor, or is passing an untyped operand. See query performance.
To isolate slow-statement output in production, set CS_LOG__SLOW_STATEMENTS_LEVEL=warn while keeping the global level at error.
Docker-specific options
These environment variables are only available in the Docker container image, not in the binary.
| Env variable | Description |
|---|---|
CS_DATABASE__INSTALL_EQL | Install EQL on container startup |
CS_DATABASE__INSTALL_EXAMPLE_SCHEMA | Load the example schema on container startup |
CS_DATABASE__INSTALL_AWS_RDS_CERT_BUNDLE | Add the AWS RDS certificate bundle for TLS verification |
CS_DATABASE__INSTALL_EQL and CS_DATABASE__INSTALL_EXAMPLE_SCHEMA are for development use only. Install EQL as a database migration in production.
Per-target log levels
Override the log level for specific internal components using the pattern CS_LOG__{TARGET}_LEVEL. These accept the same values as CS_LOG__LEVEL.
| Env variable | Target | Description |
|---|---|---|
CS_LOG__DEVELOPMENT_LEVEL | DEVELOPMENT | General development logging |
CS_LOG__AUTHENTICATION_LEVEL | AUTHENTICATION | Client authentication and SASL |
CS_LOG__CONFIG_LEVEL | CONFIG | Configuration loading |
CS_LOG__CONTEXT_LEVEL | CONTEXT | Connection context |
CS_LOG__ENCODING_LEVEL | ENCODING | Data encoding and decoding |
CS_LOG__ENCRYPT_LEVEL | ENCRYPT | Encryption operations |
CS_LOG__DECRYPT_LEVEL | DECRYPT | Decryption operations |
CS_LOG__ENCRYPT_CONFIG_LEVEL | ENCRYPT_CONFIG | Encryption configuration loading |
CS_LOG__ZEROKMS_LEVEL | ZEROKMS | ZeroKMS cipher initialization, cache, and connectivity |
CS_LOG__MIGRATE_LEVEL | MIGRATE | Schema migration |
CS_LOG__PROTOCOL_LEVEL | PROTOCOL | PostgreSQL wire protocol |
CS_LOG__MAPPER_LEVEL | MAPPER | SQL statement mapping and transformation |
CS_LOG__SCHEMA_LEVEL | SCHEMA | Database schema analysis |
CS_LOG__SLOW_STATEMENTS_LEVEL | SLOW_STATEMENTS | Slow statement detection |
CLI reference
cipherstash-proxy [OPTIONS] [DBNAME] [COMMAND]Commands
| Command | Description |
|---|---|
encrypt | Encrypt existing plaintext data in the database |
help | Print help information |
The encrypt command encrypts existing plaintext data in place. Follow the safeguards in Data migration before running it against populated production data.
Arguments and options
| Flag | Default | Description |
|---|---|---|
DBNAME | Database name (positional, optional) | |
-H, --db-host <DB_HOST> | 127.0.0.1 | Database host |
-u, --db-user <DB_USER> | postgres | Database user |
-p, --config-file-path <CONFIG_FILE_PATH> | cipherstash-proxy.toml | Path to the TOML config file |
-l, --log-level <LOG_LEVEL> | info | Log level |
-f, --log-format <LOG_FORMAT> | pretty (terminal), structured (non-terminal) | Log format |
Prometheus metrics
Enable the exporter with CS_PROMETHEUS__ENABLED=true. Metrics are exposed on port 9930 by default.
| Metric | Type | Description |
|---|---|---|
cipherstash_proxy_keyset_cipher_cache_hits_total | Counter | Keyset-scoped cipher cache hits |
cipherstash_proxy_keyset_cipher_cache_miss_total | Counter | Cipher cache misses requiring initialization |
cipherstash_proxy_keyset_cipher_init_total | Counter | New keyset-scoped cipher initializations |
cipherstash_proxy_keyset_cipher_init_duration_seconds | Histogram | Duration of cipher initialization, including ZeroKMS network call |
cipherstash_proxy_clients_active_connections | Gauge | Current active client connections |
cipherstash_proxy_clients_bytes_received_total | Counter | Bytes received from clients |
cipherstash_proxy_clients_bytes_sent_total | Counter | Bytes sent to clients |
cipherstash_proxy_decrypted_values_total | Counter | Individual values decrypted |
cipherstash_proxy_decryption_duration_seconds | Histogram | Time spent performing decryption |
cipherstash_proxy_decryption_duration_seconds_count | Counter | Number of decryption timing observations |
cipherstash_proxy_decryption_duration_seconds_sum | Counter | Total cumulative decryption time |
cipherstash_proxy_decryption_error_total | Counter | Unsuccessful decryption operations |
cipherstash_proxy_decryption_requests_total | Counter | ZeroKMS decrypt requests |
cipherstash_proxy_encrypted_values_total | Counter | Individual values encrypted |
cipherstash_proxy_encryption_duration_seconds | Histogram | Time spent performing encryption |
cipherstash_proxy_encryption_duration_seconds_count | Counter | Number of encryption timing observations |
cipherstash_proxy_encryption_duration_seconds_sum | Counter | Total cumulative encryption time |
cipherstash_proxy_encryption_error_total | Counter | Unsuccessful encryption operations |
cipherstash_proxy_encryption_requests_total | Counter | ZeroKMS encrypt requests |
cipherstash_proxy_rows_encrypted_total | Counter | Encrypted rows returned to clients |
cipherstash_proxy_rows_passthrough_total | Counter | Non-encrypted rows returned to clients |
cipherstash_proxy_rows_total | Counter | Total rows returned to clients |
cipherstash_proxy_server_bytes_received_total | Counter | Bytes received from the PostgreSQL server |
cipherstash_proxy_server_bytes_sent_total | Counter | Bytes sent to the PostgreSQL server |
cipherstash_proxy_statements_execution_duration_seconds | Histogram | Database SQL execution time |
cipherstash_proxy_statements_session_duration_seconds | Histogram | Total statement processing time (encrypt, execute, decrypt) |
cipherstash_proxy_statements_encrypted_total | Counter | Statements requiring encryption |
cipherstash_proxy_statements_passthrough_total | Counter | Statements not requiring encryption |
cipherstash_proxy_statements_total | Counter | Total statements processed |
cipherstash_proxy_statements_unmappable_total | Counter | Statements that could not be mapped |
Reloading configuration
When Proxy receives a SIGHUP, it reloads application-level configuration (database, auth, encrypt, log, prometheus, development) without disrupting active connections.
Network settings require a full restart: server.host, server.port, server.require_tls, server.worker_threads, and any tls configuration.
Supported architectures
CipherStash Proxy is available as a Docker container image for linux/arm64.