Skip to content

Commit a7b5b86

Browse files
committed
🥅 fix: improve ZeroKMS error handling and startup validation
- Add dedicated ZeroKMSError type with clearer authentication failure messages - Validate ZeroKMS connection during proxy startup to fail fast on credential issues - Improve error documentation with step-by-step troubleshooting guidance - Enhanced logging with connection status and initialization feedback - Better error categorization for credential vs system issues This ensures users get immediate, actionable feedback when ZeroKMS authentication fails rather than encountering cryptic errors during operation.
1 parent 37a6111 commit a7b5b86

File tree

6 files changed

+65
-27
lines changed

6 files changed

+65
-27
lines changed

docs/errors.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- [KeysetName could not be set](#encrypt-keyset-name-could-not-be-set)
2323
- [Plaintext could not be encoded](#encrypt-plaintext-could-not-be-encoded)
2424
- [Unknown column](#encrypt-unknown-column)
25+
- [Unknown Keyset Identifier](#encrypt-unknown-keyset)
2526
- [Unknown table](#encrypt-unknown-table)
2627
- [Unknown index term](#encrypt-unknown-index-term)
2728
- [Column configuration mismatch](#encrypt-column-config-mismatch)
@@ -46,14 +47,14 @@ Authentication failed when connecting to the database.
4647
### Error message
4748

4849
```
49-
Database authentication failed: check username and password
50+
Database authentication failed. Check username and password
5051
```
5152

5253
### How to fix
5354

54-
Check the configured username and password are correct and can connect to the database.
55+
1. Check the configured username and password are correct and can connect to the database.
5556

56-
Check the database is using a supported authentication method.
57+
2. Check the database is using a supported authentication method.
5758

5859
CipherStash Proxy supports several PostgreSQL password authentication methods:
5960

@@ -76,21 +77,38 @@ Authentication failed when connecting a client to the proxy.
7677
### Error message
7778

7879
```
79-
Client authentication failed: check username and password
80+
Client authentication failed. Check username and password.
8081
```
8182

8283
### How to fix
8384

84-
Check the configured username and password are correct.
85+
1. Check the configured username and password are correct.
8586

8687

8788

8889
<!-- ---------------------------------------------------------------------------------------------------- -->
8990

9091

92+
## ZeroKMS <a id='authentication-failed-zerokms'></a>
93+
94+
Authentication failed when connecting to ZeroKMS.
95+
96+
97+
### Error message
98+
99+
```
100+
ZeroKMS authentication failed. Check the configured credentials.
101+
```
102+
103+
### How to Fix
104+
105+
1. Check that the configured `client` credentials are correct.
106+
2. Check that the active `keyset_name` or `keyset_id` is associated with a keyset in the configured workspace.
107+
91108

92109
<!-- ---------------------------------------------------------------------------------------------------- -->
93110

111+
94112
# Mapping errors
95113

96114

@@ -354,7 +372,7 @@ Keyset Name could not be set using `SET CIPHERSTASH.KEYSET_NAME`
354372
<!-- ---------------------------------------------------------------------------------------------------- -->
355373

356374

357-
## Unknown Keyset Identifier <a id='encrypt-unknown-keyset'></a>
375+
## Unknown keyset identifier <a id='encrypt-unknown-keyset'></a>
358376

359377
The specified keyset could not be loaded.
360378

@@ -370,11 +388,13 @@ Unknown keyset name or id '{keyset}'
370388
1. Check that the active `keyset_name` or `keyset_id` is associated with a keyset in the configured workspace.
371389
2. Check that the configured `client` has been granted access to the keyset via the dashboard.
372390
3. Keyset names are case sensitive. If setting the active keyset by name, check that the `keyset_name` is an exact match.
391+
4. Check that the configured `client` credentials are correct.
373392

374393

375394
<!-- ---------------------------------------------------------------------------------------------------- -->
376395

377396

397+
378398
## Could not decrypt data for keyset <a id='encrypt-could-not-decrypt-data-for-keyset'></a>
379399

380400
The data belonging to the active `keyset_id` could not be decrypted.

packages/cipherstash-proxy-integration/src/multitenant/set_keyset_id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ mod tests {
283283
if let Err(err) = result {
284284
let msg = err.to_string();
285285

286-
assert_eq!(msg, "db error: FATAL: Unknown keyset name or id '2cace9db-3a2a-4b46-a184-ba412b3e0730'. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-keyset");
286+
assert_eq!(msg, "db error: FATAL: Unknown keyset name or id '2cace9db-3a2a-4b46-a184-ba412b3e0730'. Check the configured credentials. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-keyset");
287287
} else {
288288
unreachable!();
289289
}

packages/cipherstash-proxy-integration/src/multitenant/set_keyset_name.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ mod tests {
341341
if let Err(err) = result {
342342
let msg = err.to_string();
343343

344-
assert_eq!(msg, "db error: FATAL: Unknown keyset name or id 'BLAHVTHA'. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-keyset");
344+
assert_eq!(msg, "db error: FATAL: Unknown keyset name or id 'BLAHVTHA'. Check the configured credentials. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-keyset");
345345
} else {
346346
unreachable!();
347347
}

packages/cipherstash-proxy/src/error.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub enum Error {
5252
Tls(#[from] rustls::Error),
5353

5454
#[error(transparent)]
55-
ZeroKMS(#[from] cipherstash_client::zerokms::Error),
55+
ZeroKMS(#[from] ZeroKMSError),
5656

5757
#[error("Unknown error")]
5858
Unknown,
@@ -67,6 +67,15 @@ pub enum ContextError {
6767
UnknownPortal,
6868
}
6969

70+
#[derive(Error, Debug)]
71+
pub enum ZeroKMSError {
72+
#[error("ZeroKMS authentication failed. Check the configured credentials. For help visit {}#zerokms-authentication-failed", ERROR_DOC_BASE_URL)]
73+
AuthenticationFailed,
74+
75+
#[error(transparent)]
76+
System(#[from] cipherstash_client::zerokms::Error),
77+
}
78+
7079
#[derive(Error, Debug)]
7180
pub enum MappingError {
7281
#[error("Invalid parameter for column '{}' of type '{}' in table '{}' (OID {}). For help visit {}#mapping-invalid-parameter",
@@ -283,7 +292,7 @@ pub enum EncryptError {
283292
UnknownColumn { table: String, column: String },
284293

285294
#[error(
286-
"Unknown keyset name or id '{keyset}'. For help visit {}#encrypt-unknown-keyset",
295+
"Unknown keyset name or id '{keyset}'. Check the configured credentials. For help visit {}#encrypt-unknown-keyset",
287296
ERROR_DOC_BASE_URL
288297
)]
289298
UnknownKeysetIdentifier { keyset: String },
@@ -300,10 +309,10 @@ pub enum EncryptError {
300309

301310
#[derive(Error, Debug)]
302311
pub enum ProtocolError {
303-
#[error("Database authentication failed: check username and password. For help visit {}#authentication-failed-database", ERROR_DOC_BASE_URL)]
312+
#[error("Database authentication failed. Check username and password. For help visit {}#authentication-failed-database", ERROR_DOC_BASE_URL)]
304313
AuthenticationFailed,
305314

306-
#[error("Client authentication failed: check username and password. For help visit {}#authentication-failed-client", ERROR_DOC_BASE_URL)]
315+
#[error("Client authentication failed. Check username and password. For help visit {}#authentication-failed-client", ERROR_DOC_BASE_URL)]
307316
ClientAuthenticationFailed,
308317

309318
#[error("Expected {expected} parameter format codes, received {received}")]

packages/cipherstash-proxy/src/proxy/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ pub struct Proxy {
3737

3838
impl Proxy {
3939
pub async fn init(config: TandemConfig) -> Result<Proxy, Error> {
40-
let zerokms = ZeroKms::new(&config)?;
40+
let zerokms = ZeroKms::init(&config)?;
41+
42+
// Attempt to connect to default keyset
43+
// Ensures error on start if credential or network issue
44+
zerokms.init_cipher(None).await?;
4145

4246
let encrypt_config = EncryptConfigManager::init(&config.database).await?;
4347
// TODO: populate EqlTraitImpls based in config

packages/cipherstash-proxy/src/proxy/zerokms/zerokms.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{
22
config::TandemConfig,
33
eql,
4-
error::{EncryptError, Error},
5-
log::ENCRYPT,
4+
error::{EncryptError, Error, ZeroKMSError},
5+
log::{ENCRYPT, PROXY},
66
postgresql::{Column, KeysetIdentifier},
77
prometheus::{KEYSET_CIPHER_CACHE_HITS_TOTAL, KEYSET_CIPHER_INIT_TOTAL},
88
};
@@ -13,7 +13,7 @@ use cipherstash_client::{
1313
use metrics::counter;
1414
use moka::future::Cache;
1515
use std::{sync::Arc, time::Duration};
16-
use tracing::debug;
16+
use tracing::{debug, info, warn};
1717

1818
use super::{
1919
init_zerokms_client, plaintext_type_name, to_eql_encrypted, to_eql_encrypted_from_index_term,
@@ -30,7 +30,7 @@ pub struct ZeroKms {
3030
}
3131

3232
impl ZeroKms {
33-
pub fn new(config: &TandemConfig) -> Result<Self, Error> {
33+
pub fn init(config: &TandemConfig) -> Result<Self, Error> {
3434
let zerokms_client = init_zerokms_client(config)?;
3535

3636
let cipher_cache = Cache::builder()
@@ -66,14 +66,14 @@ impl ZeroKms {
6666

6767
// Check cache first
6868
if let Some(cached_cipher) = self.cipher_cache.get(&cache_key).await {
69-
debug!(target: "proxy", msg = "Use cached ScopedCipher", ?keyset_id);
69+
debug!(target: PROXY, msg = "Use cached ScopedCipher", ?keyset_id);
7070
counter!(KEYSET_CIPHER_CACHE_HITS_TOTAL).increment(1);
7171
return Ok(cached_cipher);
7272
}
7373

7474
let zerokms_client = self.zerokms_client.clone();
7575

76-
debug!(target: "proxy", msg = "Initializing ZeroKMS ScopedCipher", ?keyset_id);
76+
debug!(target: PROXY, msg = "Initializing ZeroKMS ScopedCipher", ?keyset_id);
7777

7878
let identified_by = keyset_id.as_ref().map(|id| id.0.clone());
7979

@@ -94,12 +94,14 @@ impl ZeroKms {
9494
let entry_count = self.cipher_cache.entry_count();
9595
let memory_usage_bytes = self.cipher_cache.weighted_size();
9696

97-
debug!(target: "proxy", msg = "ScopedCipher cached", ?keyset_id, entry_count, memory_usage_bytes);
97+
info!(msg = "Connected to ZeroKMS");
98+
debug!(target: PROXY, msg = "ScopedCipher cached", ?keyset_id, entry_count, memory_usage_bytes);
9899

99100
Ok(arc_cipher)
100101
}
101102
Err(err) => {
102-
debug!(target: "proxy", msg = "Error initializing ZeroKMS ScopedCipher", error = err.to_string());
103+
debug!(target: PROXY, msg = "Error initializing ZeroKMS ScopedCipher", error = err.to_string());
104+
warn!(msg = "Error initializing ZeroKMS", error = err.to_string());
103105

104106
match err {
105107
cipherstash_client::zerokms::Error::LoadKeyset(_) => {
@@ -108,7 +110,10 @@ impl ZeroKms {
108110
}
109111
.into())
110112
}
111-
_ => Err(err.into()),
113+
cipherstash_client::zerokms::Error::Credentials(_) => {
114+
Err(ZeroKMSError::AuthenticationFailed.into())
115+
}
116+
_ => Err(Error::ZeroKMS(err.into())),
112117
}
113118
}
114119
}
@@ -219,10 +224,10 @@ impl ZeroKms {
219224
.filter_map(|(idx, eql)| Some((idx, eql?.body.ciphertext.unwrap())))
220225
.collect::<_>();
221226

222-
let decrypted = cipher.decrypt(encrypted).await.map_err(|e| -> Error {
223-
match &e {
227+
let decrypted = cipher.decrypt(encrypted).await.map_err(|err| -> Error {
228+
match &err {
224229
cipherstash_client::zerokms::Error::Decrypt(_) => {
225-
let error_msg = e.to_string();
230+
let error_msg = err.to_string();
226231
if error_msg.contains("Failed to retrieve key") {
227232
EncryptError::CouldNotDecryptDataForKeyset {
228233
keyset_id: keyset_id
@@ -231,10 +236,10 @@ impl ZeroKms {
231236
}
232237
.into()
233238
} else {
234-
e.into()
239+
Error::ZeroKMS(err.into())
235240
}
236241
}
237-
_ => e.into(),
242+
_ => Error::ZeroKMS(err.into()),
238243
}
239244
})?;
240245

0 commit comments

Comments
 (0)