1use secrets::SecretVec;
2use serde::{Deserialize, Serialize, Serializer};
3
4use crate::models::SecretString;
5
6fn serialize_secretvec<S>(_secret: &SecretVec<u8>, serializer: S) -> Result<S::Ok, S::Error>
7where
8 S: Serializer,
9{
10 serializer.serialize_str("[REDACTED]")
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14#[serde(rename_all = "lowercase")]
15pub enum SignerType {
16 Test,
17 Local,
18 #[serde(rename = "aws_kms")]
19 AwsKms,
20 Vault,
21 Turnkey,
22}
23
24#[derive(Debug, Clone, Serialize)]
25pub struct SignerRepoModel {
26 pub id: String,
27 pub config: SignerConfig,
28}
29
30#[derive(Debug, Clone, Serialize)]
31pub struct LocalSignerConfig {
32 #[serde(serialize_with = "serialize_secretvec")]
33 pub raw_key: SecretVec<u8>,
34}
35
36#[derive(Debug, Clone, Serialize)]
37pub struct AwsKmsSignerConfig {
38 pub region: Option<String>,
39 pub key_id: String,
40}
41
42#[derive(Debug, Clone, Serialize)]
43pub struct VaultTransitSignerConfig {
44 pub key_name: String,
45 pub address: String,
46 pub namespace: Option<String>,
47 pub role_id: SecretString,
48 pub secret_id: SecretString,
49 pub pubkey: String,
50 pub mount_point: Option<String>,
51}
52
53#[derive(Debug, Clone, Serialize)]
54pub struct TurnkeySignerConfig {
55 pub api_public_key: String,
56 pub api_private_key: SecretString,
57 pub organization_id: String,
58 pub private_key_id: String,
59 pub public_key: String,
60}
61
62#[derive(Debug, Clone, Serialize)]
63pub struct GoogleCloudKmsSignerServiceAccountConfig {
64 pub private_key: SecretString,
65 pub private_key_id: SecretString,
66 pub project_id: String,
67 pub client_email: SecretString,
68 pub client_id: String,
69 pub auth_uri: String,
70 pub token_uri: String,
71 pub auth_provider_x509_cert_url: String,
72 pub client_x509_cert_url: String,
73 pub universe_domain: String,
74}
75
76#[derive(Debug, Clone, Serialize)]
77pub struct GoogleCloudKmsSignerKeyConfig {
78 pub location: String,
79 pub key_ring_id: String,
80 pub key_id: String,
81 pub key_version: u32,
82}
83
84#[derive(Debug, Clone, Serialize)]
85pub struct GoogleCloudKmsSignerConfig {
86 pub service_account: GoogleCloudKmsSignerServiceAccountConfig,
87 pub key: GoogleCloudKmsSignerKeyConfig,
88}
89
90#[derive(Debug, Clone, Serialize)]
91pub enum SignerConfig {
92 Test(LocalSignerConfig),
93 Local(LocalSignerConfig),
94 Vault(LocalSignerConfig),
95 VaultCloud(LocalSignerConfig),
96 VaultTransit(VaultTransitSignerConfig),
97 AwsKms(AwsKmsSignerConfig),
98 Turnkey(TurnkeySignerConfig),
99 GoogleCloudKms(GoogleCloudKmsSignerConfig),
100}
101
102impl SignerConfig {
103 pub fn get_local(&self) -> Option<&LocalSignerConfig> {
104 match self {
105 Self::Local(config)
106 | Self::Test(config)
107 | Self::Vault(config)
108 | Self::VaultCloud(config) => Some(config),
109 Self::VaultTransit(_)
110 | Self::AwsKms(_)
111 | Self::Turnkey(_)
112 | Self::GoogleCloudKms(_) => None,
113 }
114 }
115
116 pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerConfig> {
117 let SignerConfig::AwsKms(config) = self else {
118 return None;
119 };
120
121 Some(config)
122 }
123
124 pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerConfig> {
125 let SignerConfig::VaultTransit(config) = self else {
126 return None;
127 };
128
129 Some(config)
130 }
131
132 pub fn get_turnkey(&self) -> Option<&TurnkeySignerConfig> {
133 let SignerConfig::Turnkey(config) = self else {
134 return None;
135 };
136
137 Some(config)
138 }
139
140 pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerConfig> {
141 let SignerConfig::GoogleCloudKms(config) = self else {
142 return None;
143 };
144
145 Some(config)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use serde_json::{from_str, to_string};
153
154 #[test]
155 fn test_signer_type_serialization() {
156 assert_eq!(to_string(&SignerType::Test).unwrap(), "\"test\"");
157 assert_eq!(to_string(&SignerType::Local).unwrap(), "\"local\"");
158 assert_eq!(to_string(&SignerType::AwsKms).unwrap(), "\"aws_kms\"");
159 assert_eq!(to_string(&SignerType::Vault).unwrap(), "\"vault\"");
160 assert_eq!(to_string(&SignerType::Turnkey).unwrap(), "\"turnkey\"");
161 }
162
163 #[test]
164 fn test_signer_type_deserialization() {
165 assert_eq!(
166 from_str::<SignerType>("\"test\"").unwrap(),
167 SignerType::Test
168 );
169 assert_eq!(
170 from_str::<SignerType>("\"local\"").unwrap(),
171 SignerType::Local
172 );
173 assert_eq!(
174 from_str::<SignerType>("\"aws_kms\"").unwrap(),
175 SignerType::AwsKms
176 );
177 assert_eq!(
178 from_str::<SignerType>("\"vault\"").unwrap(),
179 SignerType::Vault
180 );
181 assert_eq!(
182 from_str::<SignerType>("\"turnkey\"").unwrap(),
183 SignerType::Turnkey
184 );
185 }
186
187 #[test]
188 fn test_signer_repo_model_creation() {
189 let model = SignerRepoModel {
190 id: "test-signer".to_string(),
191 config: SignerConfig::Test(LocalSignerConfig {
192 raw_key: SecretVec::new(4, |v| v.copy_from_slice(&[1, 2, 3, 4])),
193 }),
194 };
195
196 assert_eq!(model.id, "test-signer");
197 assert!(matches!(model.config, SignerConfig::Test(_)));
198 }
199
200 #[test]
201 fn test_local_signer_config() {
202 let private_key = vec![0, 1, 2, 3, 4, 5];
203 let config = LocalSignerConfig {
204 raw_key: SecretVec::new(private_key.len(), |v| v.copy_from_slice(&private_key)),
205 };
206
207 let test = config.raw_key.borrow();
208 assert_eq!(*test, private_key);
209 }
210
211 #[test]
212 fn test_vault_transit_signer_config() {
213 let config = VaultTransitSignerConfig {
214 key_name: "transit-key".to_string(),
215 address: "https://vault.example.com".to_string(),
216 namespace: Some("ns1".to_string()),
217 role_id: SecretString::new("role-123"),
218 secret_id: SecretString::new("secret-456"),
219 pubkey: "mypubkey123".to_string(),
220 mount_point: Some("transit".to_string()),
221 };
222
223 assert_eq!(config.key_name, "transit-key");
224 assert_eq!(config.address, "https://vault.example.com");
225 assert_eq!(config.namespace, Some("ns1".to_string()));
226 assert_eq!(config.role_id.to_str().as_str(), "role-123");
227 assert_eq!(config.secret_id.to_str().as_str(), "secret-456");
228 assert_eq!(config.pubkey, "mypubkey123");
229 assert_eq!(config.mount_point, Some("transit".to_string()));
230
231 let config2 = VaultTransitSignerConfig {
232 key_name: "transit-key".to_string(),
233 address: "https://vault.example.com".to_string(),
234 namespace: None,
235 role_id: SecretString::new("role-123"),
236 secret_id: SecretString::new("secret-456"),
237 pubkey: "mypubkey123".to_string(),
238 mount_point: None,
239 };
240
241 assert_eq!(config2.namespace, None);
242 assert_eq!(config2.mount_point, None);
243 }
244
245 #[test]
246 fn test_turnkey_signer_config() {
247 let config = TurnkeySignerConfig {
248 api_private_key: SecretString::new("123"),
249 api_public_key: "api_public_key".to_string(),
250 organization_id: "organization_id".to_string(),
251 private_key_id: "private_key_id".to_string(),
252 public_key: "public_key".to_string(),
253 };
254
255 assert_eq!(config.api_public_key, "api_public_key");
256 assert_eq!(config.organization_id, "organization_id");
257 assert_eq!(config.api_private_key.to_str().as_str(), "123");
258 assert_eq!(config.private_key_id, "private_key_id");
259 assert_eq!(config.public_key, "public_key");
260 }
261
262 #[test]
263 fn test_google_cloud_kms_config() {
264 let config = GoogleCloudKmsSignerConfig {
265 service_account: GoogleCloudKmsSignerServiceAccountConfig {
266 private_key: SecretString::new("private_key"),
267 private_key_id: SecretString::new("private_key_id"),
268 project_id: "project_id".to_string(),
269 client_email: SecretString::new("client_email"),
270 client_id: "client_id".to_string(),
271 auth_uri: "auth_uri".to_string(),
272 token_uri: "token_uri".to_string(),
273 auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
274 client_x509_cert_url: "client_x509_cert_url".to_string(),
275 universe_domain: "universe_domain".to_string(),
276 },
277 key: GoogleCloudKmsSignerKeyConfig {
278 location: "global".to_string(),
279 key_ring_id: "key_ring_id".to_string(),
280 key_id: "key_id".to_string(),
281 key_version: 1,
282 },
283 };
284
285 assert_eq!(config.service_account.project_id, "project_id");
286 assert_eq!(config.key.key_ring_id, "key_ring_id");
287 assert_eq!(config.key.key_id, "key_id");
288 assert_eq!(config.key.key_version, 1);
289 assert_eq!(
290 config.service_account.private_key.to_str().as_str(),
291 "private_key"
292 );
293 assert_eq!(
294 config.service_account.private_key_id.to_str().as_str(),
295 "private_key_id"
296 );
297 assert_eq!(
298 config.service_account.client_email.to_str().as_str(),
299 "client_email"
300 );
301 assert_eq!(config.service_account.client_id, "client_id");
302 assert_eq!(config.service_account.auth_uri, "auth_uri");
303 assert_eq!(config.service_account.token_uri, "token_uri");
304 assert_eq!(
305 config.service_account.auth_provider_x509_cert_url,
306 "auth_provider_x509_cert_url"
307 );
308 assert_eq!(
309 config.service_account.client_x509_cert_url,
310 "client_x509_cert_url"
311 );
312 assert_eq!(config.service_account.universe_domain, "universe_domain");
313 }
314
315 #[test]
316 fn test_signer_config_variants() {
317 let test_config = SignerConfig::Test(LocalSignerConfig {
318 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
319 });
320
321 let local_config = SignerConfig::Local(LocalSignerConfig {
322 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
323 });
324
325 let vault_config = SignerConfig::Vault(LocalSignerConfig {
326 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
327 });
328
329 let vault_cloud_config = SignerConfig::VaultCloud(LocalSignerConfig {
330 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[10, 11, 12])),
331 });
332
333 let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
334 key_name: "transit-key".to_string(),
335 address: "https://vault.example.com".to_string(),
336 namespace: None,
337 role_id: SecretString::new("role-123"),
338 secret_id: SecretString::new("secret-456"),
339 pubkey: "mypubkey123".to_string(),
340 mount_point: None,
341 });
342
343 let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
344 region: Some("us-east-1".to_string()),
345 key_id: "test-key-id".to_string(),
346 });
347
348 let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
349 api_private_key: SecretString::new("123"),
350 api_public_key: "api_public_key".to_string(),
351 organization_id: "organization_id".to_string(),
352 private_key_id: "private_key_id".to_string(),
353 public_key: "public_key".to_string(),
354 });
355
356 let google_cloud_kms_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
357 service_account: GoogleCloudKmsSignerServiceAccountConfig {
358 private_key: SecretString::new("private_key"),
359 private_key_id: SecretString::new("private_key_id"),
360 project_id: "project_id".to_string(),
361 client_email: SecretString::new("client_email"),
362 client_id: "client_id".to_string(),
363 auth_uri: "auth_uri".to_string(),
364 token_uri: "token_uri".to_string(),
365 auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
366 client_x509_cert_url: "client_x509_cert_url".to_string(),
367 universe_domain: "universe_domain".to_string(),
368 },
369 key: GoogleCloudKmsSignerKeyConfig {
370 location: "global".to_string(),
371 key_ring_id: "key_ring_id".to_string(),
372 key_id: "key_id".to_string(),
373 key_version: 1,
374 },
375 });
376
377 assert!(matches!(test_config, SignerConfig::Test(_)));
378 assert!(matches!(local_config, SignerConfig::Local(_)));
379 assert!(matches!(vault_config, SignerConfig::Vault(_)));
380 assert!(matches!(vault_cloud_config, SignerConfig::VaultCloud(_)));
381 assert!(matches!(
382 vault_transit_config,
383 SignerConfig::VaultTransit(_)
384 ));
385 assert!(matches!(aws_kms_config, SignerConfig::AwsKms(_)));
386 assert!(matches!(turnkey_config, SignerConfig::Turnkey(_)));
387 assert!(matches!(
388 google_cloud_kms_config,
389 SignerConfig::GoogleCloudKms(_)
390 ));
391 }
392
393 #[test]
394 fn test_signer_config_get_local() {
395 let local_config = SignerConfig::Local(LocalSignerConfig {
396 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
397 });
398 let retrieved = local_config.get_local().unwrap();
399 assert_eq!(*retrieved.raw_key.borrow(), vec![1, 2, 3]);
400
401 let test_config = SignerConfig::Test(LocalSignerConfig {
402 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
403 });
404 let retrieved = test_config.get_local().unwrap();
405 assert_eq!(*retrieved.raw_key.borrow(), vec![4, 5, 6]);
406
407 let vault_config = SignerConfig::Vault(LocalSignerConfig {
408 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
409 });
410 let retrieved = vault_config.get_local().unwrap();
411 assert_eq!(*retrieved.raw_key.borrow(), vec![7, 8, 9]);
412
413 let vault_cloud_config = SignerConfig::VaultCloud(LocalSignerConfig {
414 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[10, 11, 12])),
415 });
416 let retrieved = vault_cloud_config.get_local().unwrap();
417 assert_eq!(*retrieved.raw_key.borrow(), vec![10, 11, 12]);
418
419 let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
420 key_name: "transit-key".to_string(),
421 address: "https://vault.example.com".to_string(),
422 namespace: None,
423 role_id: SecretString::new("role-123"),
424 secret_id: SecretString::new("secret-456"),
425 pubkey: "mypubkey123".to_string(),
426 mount_point: None,
427 });
428 assert!(vault_transit_config.get_local().is_none());
429
430 let google_cloud_kms_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
431 service_account: GoogleCloudKmsSignerServiceAccountConfig {
432 private_key: SecretString::new("private_key"),
433 private_key_id: SecretString::new("private_key_id"),
434 project_id: "project_id".to_string(),
435 client_email: SecretString::new("client_email"),
436 client_id: "client_id".to_string(),
437 auth_uri: "auth_uri".to_string(),
438 token_uri: "token_uri".to_string(),
439 auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
440 client_x509_cert_url: "client_x509_cert_url".to_string(),
441 universe_domain: "universe_domain".to_string(),
442 },
443 key: GoogleCloudKmsSignerKeyConfig {
444 location: "global".to_string(),
445 key_ring_id: "key_ring_id".to_string(),
446 key_id: "key_id".to_string(),
447 key_version: 1,
448 },
449 });
450 assert!(google_cloud_kms_config.get_local().is_none());
451
452 let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
453 region: Some("us-east-1".to_string()),
454 key_id: "test-key-id".to_string(),
455 });
456 assert!(aws_kms_config.get_local().is_none());
457
458 let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
459 api_private_key: SecretString::new("123"),
460 api_public_key: "api_public_key".to_string(),
461 organization_id: "organization_id".to_string(),
462 private_key_id: "private_key_id".to_string(),
463 public_key: "public_key".to_string(),
464 });
465 assert!(turnkey_config.get_local().is_none());
466 }
467
468 #[test]
469 fn test_signer_config_get_aws_kms() {
470 let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
471 region: Some("us-east-1".to_string()),
472 key_id: "test-key-id".to_string(),
473 });
474 assert!(aws_kms_config.get_aws_kms().is_some());
475
476 let local_config = SignerConfig::Local(LocalSignerConfig {
478 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
479 });
480 assert!(local_config.get_aws_kms().is_none());
481
482 let test_config = SignerConfig::Test(LocalSignerConfig {
483 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
484 });
485 assert!(test_config.get_aws_kms().is_none());
486 }
487
488 #[test]
489 fn test_signer_config_get_vault_transit() {
490 let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
491 key_name: "transit-key".to_string(),
492 address: "https://vault.example.com".to_string(),
493 namespace: None,
494 role_id: SecretString::new("role-123"),
495 secret_id: SecretString::new("secret-456"),
496 pubkey: "mypubkey123".to_string(),
497 mount_point: None,
498 });
499 let retrieved = vault_transit_config.get_vault_transit().unwrap();
500 assert_eq!(retrieved.key_name, "transit-key");
501 assert_eq!(retrieved.address, "https://vault.example.com");
502
503 let local_config = SignerConfig::Local(LocalSignerConfig {
504 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
505 });
506 assert!(local_config.get_vault_transit().is_none());
507
508 let vault_config = SignerConfig::Vault(LocalSignerConfig {
509 raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
510 });
511 assert!(vault_config.get_vault_transit().is_none());
512 }
513
514 #[test]
515 fn test_signer_config_get_turnkey() {
516 let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
517 api_private_key: SecretString::new("123"),
518 api_public_key: "api_public_key".to_string(),
519 organization_id: "organization_id".to_string(),
520 private_key_id: "private_key_id".to_string(),
521 public_key: "public_key".to_string(),
522 });
523
524 let retrieved = turnkey_config.get_turnkey().unwrap();
525
526 assert_eq!(retrieved.api_public_key, "api_public_key");
527 assert_eq!(retrieved.organization_id, "organization_id");
528 assert_eq!(retrieved.api_private_key.to_str().as_str(), "123");
529 assert_eq!(retrieved.private_key_id, "private_key_id");
530 assert_eq!(retrieved.public_key, "public_key");
531 assert!(turnkey_config.get_aws_kms().is_none());
532 assert!(turnkey_config.get_local().is_none());
533 assert!(turnkey_config.get_vault_transit().is_none());
534 }
535
536 #[test]
537 fn test_signer_config_get_google_cloud_kms() {
538 let google_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
539 service_account: GoogleCloudKmsSignerServiceAccountConfig {
540 private_key: SecretString::new("private_key"),
541 private_key_id: SecretString::new("private_key_id"),
542 project_id: "project_id".to_string(),
543 client_email: SecretString::new("client_email"),
544 client_id: "client_id".to_string(),
545 auth_uri: "auth_uri".to_string(),
546 token_uri: "token_uri".to_string(),
547 auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
548 client_x509_cert_url: "client_x509_cert_url".to_string(),
549 universe_domain: "universe_domain".to_string(),
550 },
551 key: GoogleCloudKmsSignerKeyConfig {
552 location: "global".to_string(),
553 key_ring_id: "key_ring_id".to_string(),
554 key_id: "key_id".to_string(),
555 key_version: 1,
556 },
557 });
558 let retrieved = google_config.get_google_cloud_kms().unwrap();
559 assert_eq!(retrieved.service_account.project_id, "project_id");
560 assert!(google_config.get_aws_kms().is_none());
561 assert!(google_config.get_local().is_none());
562 assert!(google_config.get_vault_transit().is_none());
563 }
564}