@kibibit/configit 1.0.0-beta.26 → 1.0.0-beta.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +419 -0
  2. package/lib/scripts/test-vault-comprehensive.d.ts +2 -0
  3. package/lib/scripts/test-vault-comprehensive.d.ts.map +1 -0
  4. package/lib/scripts/test-vault-comprehensive.js +422 -0
  5. package/lib/scripts/test-vault-comprehensive.js.map +1 -0
  6. package/lib/scripts/test-vault-dynamic.d.ts +2 -0
  7. package/lib/scripts/test-vault-dynamic.d.ts.map +1 -0
  8. package/lib/scripts/test-vault-dynamic.js +193 -0
  9. package/lib/scripts/test-vault-dynamic.js.map +1 -0
  10. package/lib/scripts/test-vault-gcp-ttl.d.ts +3 -0
  11. package/lib/scripts/test-vault-gcp-ttl.d.ts.map +1 -0
  12. package/lib/scripts/test-vault-gcp-ttl.js +218 -0
  13. package/lib/scripts/test-vault-gcp-ttl.js.map +1 -0
  14. package/lib/scripts/test-vault.d.ts +2 -0
  15. package/lib/scripts/test-vault.d.ts.map +1 -0
  16. package/lib/scripts/test-vault.js +167 -0
  17. package/lib/scripts/test-vault.js.map +1 -0
  18. package/lib/src/config.errors.d.ts.map +1 -0
  19. package/lib/src/config.errors.js.map +1 -0
  20. package/lib/src/config.model.d.ts.map +1 -0
  21. package/lib/src/config.model.js.map +1 -0
  22. package/lib/{config.service.d.ts → src/config.service.d.ts} +10 -1
  23. package/lib/src/config.service.d.ts.map +1 -0
  24. package/lib/{config.service.js → src/config.service.js} +75 -9
  25. package/lib/src/config.service.js.map +1 -0
  26. package/lib/src/environment.service.d.ts.map +1 -0
  27. package/lib/src/environment.service.js.map +1 -0
  28. package/lib/{index.d.ts → src/index.d.ts} +1 -0
  29. package/lib/src/index.d.ts.map +1 -0
  30. package/lib/{index.js → src/index.js} +1 -0
  31. package/lib/src/index.js.map +1 -0
  32. package/lib/src/json-schema.validator.d.ts.map +1 -0
  33. package/lib/src/json-schema.validator.js.map +1 -0
  34. package/lib/src/vault/__tests__/vault-integration.test.d.ts +2 -0
  35. package/lib/src/vault/__tests__/vault-integration.test.d.ts.map +1 -0
  36. package/lib/src/vault/__tests__/vault-integration.test.js +190 -0
  37. package/lib/src/vault/__tests__/vault-integration.test.js.map +1 -0
  38. package/lib/src/vault/decorators.d.ts +17 -0
  39. package/lib/src/vault/decorators.d.ts.map +1 -0
  40. package/lib/src/vault/decorators.js +149 -0
  41. package/lib/src/vault/decorators.js.map +1 -0
  42. package/lib/src/vault/index.d.ts +7 -0
  43. package/lib/src/vault/index.d.ts.map +1 -0
  44. package/lib/src/vault/index.js +42 -0
  45. package/lib/src/vault/index.js.map +1 -0
  46. package/lib/src/vault/secret-refresh-manager.d.ts +23 -0
  47. package/lib/src/vault/secret-refresh-manager.d.ts.map +1 -0
  48. package/lib/src/vault/secret-refresh-manager.js +149 -0
  49. package/lib/src/vault/secret-refresh-manager.js.map +1 -0
  50. package/lib/src/vault/types.d.ts +149 -0
  51. package/lib/src/vault/types.d.ts.map +1 -0
  52. package/lib/src/vault/types.js +4 -0
  53. package/lib/src/vault/types.js.map +1 -0
  54. package/lib/src/vault/vault-cache.d.ts +20 -0
  55. package/lib/src/vault/vault-cache.d.ts.map +1 -0
  56. package/lib/src/vault/vault-cache.js +139 -0
  57. package/lib/src/vault/vault-cache.js.map +1 -0
  58. package/lib/src/vault/vault-integration.d.ts +27 -0
  59. package/lib/src/vault/vault-integration.d.ts.map +1 -0
  60. package/lib/src/vault/vault-integration.js +211 -0
  61. package/lib/src/vault/vault-integration.js.map +1 -0
  62. package/lib/src/vault/vault-provider.d.ts +37 -0
  63. package/lib/src/vault/vault-provider.d.ts.map +1 -0
  64. package/lib/src/vault/vault-provider.js +354 -0
  65. package/lib/src/vault/vault-provider.js.map +1 -0
  66. package/lib/tsconfig.tsbuildinfo +1 -1
  67. package/package.json +5 -65
  68. package/src/config.service.ts +155 -10
  69. package/src/config.service.vault.spec.ts +859 -0
  70. package/src/index.ts +1 -0
  71. package/src/vault/__tests__/vault-integration.test.ts +226 -0
  72. package/src/vault/decorators.ts +228 -0
  73. package/src/vault/index.ts +31 -0
  74. package/src/vault/secret-refresh-manager.ts +241 -0
  75. package/src/vault/types.ts +487 -0
  76. package/src/vault/vault-cache.ts +240 -0
  77. package/src/vault/vault-integration.ts +332 -0
  78. package/src/vault/vault-provider.ts +576 -0
  79. package/lib/config.errors.d.ts.map +0 -1
  80. package/lib/config.errors.js.map +0 -1
  81. package/lib/config.model.d.ts.map +0 -1
  82. package/lib/config.model.js.map +0 -1
  83. package/lib/config.service.d.ts.map +0 -1
  84. package/lib/config.service.js.map +0 -1
  85. package/lib/environment.service.d.ts.map +0 -1
  86. package/lib/environment.service.js.map +0 -1
  87. package/lib/index.d.ts.map +0 -1
  88. package/lib/index.js.map +0 -1
  89. package/lib/json-schema.validator.d.ts.map +0 -1
  90. package/lib/json-schema.validator.js.map +0 -1
  91. /package/lib/{config.errors.d.ts → src/config.errors.d.ts} +0 -0
  92. /package/lib/{config.errors.js → src/config.errors.js} +0 -0
  93. /package/lib/{config.model.d.ts → src/config.model.d.ts} +0 -0
  94. /package/lib/{config.model.js → src/config.model.js} +0 -0
  95. /package/lib/{environment.service.d.ts → src/environment.service.d.ts} +0 -0
  96. /package/lib/{environment.service.js → src/environment.service.js} +0 -0
  97. /package/lib/{json-schema.validator.d.ts → src/json-schema.validator.d.ts} +0 -0
  98. /package/lib/{json-schema.validator.js → src/json-schema.validator.js} +0 -0
package/README.md CHANGED
@@ -111,6 +111,425 @@ export const configService = new ExtConfigService() as ExtConfigService;
111
111
 
112
112
  ```
113
113
 
114
+ ## Vault Integration
115
+
116
+ Configit supports HashiCorp Vault integration for dynamic secrets management with automatic TTL-based refresh. This enables secure, centralized secret management with automatic rotation for database credentials, API keys, and other sensitive configuration values.
117
+
118
+ ### Overview
119
+
120
+ Vault integration provides:
121
+ - **Dynamic Secrets**: Automatically rotate credentials before expiration
122
+ - **Centralized Management**: Store secrets in HashiCorp Vault
123
+ - **Automatic Refresh**: Background refresh based on TTL (Time To Live)
124
+ - **Multiple Engines**: Support for KV v1/v2, Database, AWS, GCP, Azure, and more
125
+ - **Source Priority**: Vault secrets have highest priority (override env vars and config files)
126
+ - **Graceful Fallback**: Optional secrets can fall back to environment variables
127
+
128
+ ### Prerequisites
129
+
130
+ 1. **HashiCorp Vault** running and accessible
131
+ - Development: `http://127.0.0.1:8200`
132
+ - Production: HTTPS endpoint (required)
133
+
134
+ 2. **Authentication Method** configured:
135
+ - **Token**: Simple token-based auth (dev only)
136
+ - **AppRole**: Recommended for production
137
+ - **GCP IAM**: For GCP workloads
138
+ - **AWS IAM**: For AWS workloads
139
+
140
+ 3. **Vault Secrets** configured:
141
+ - KV secrets: `secret/data/myapp/api_key`
142
+ - Database credentials: `database/creds/my-role`
143
+ - Other engines as needed
144
+
145
+ ### Installation
146
+
147
+ Vault integration is included in `@kibibit/configit` - no additional packages required.
148
+
149
+ ### Configuration with Vault
150
+
151
+ Configure Vault integration by passing `vault` options to `ConfigService`:
152
+
153
+ ```typescript
154
+ import { ConfigService, IVaultConfigOptions } from '@kibibit/configit';
155
+
156
+ const vaultOptions: IVaultConfigOptions = {
157
+ endpoint: process.env.VAULT_ADDR || 'http://127.0.0.1:8200',
158
+ auth: {
159
+ method: 'token',
160
+ config: {
161
+ token: process.env.VAULT_TOKEN
162
+ }
163
+ },
164
+ tls: {
165
+ enabled: true,
166
+ verifyCertificate: true
167
+ },
168
+ refreshBuffer: 300, // Refresh 5 minutes before expiry (default)
169
+ fallback: {
170
+ required: true, // Fail fast if Vault unavailable
171
+ useCacheOnFailure: true,
172
+ maxCacheAge: 3600000 // 1 hour
173
+ }
174
+ };
175
+
176
+ const configService = new ConfigService(ProjectConfig, undefined, {
177
+ vault: vaultOptions
178
+ });
179
+
180
+ // Initialize Vault (async - call before accessing config)
181
+ await configService.initializeVault();
182
+ ```
183
+
184
+ #### Authentication Methods
185
+
186
+ **Token Authentication** (Development):
187
+ ```typescript
188
+ auth: {
189
+ method: 'token',
190
+ config: {
191
+ token: process.env.VAULT_TOKEN
192
+ }
193
+ }
194
+ ```
195
+
196
+ **AppRole Authentication** (Production):
197
+ ```typescript
198
+ auth: {
199
+ method: 'approle',
200
+ config: {
201
+ roleId: process.env.VAULT_ROLE_ID,
202
+ secretId: process.env.VAULT_SECRET_ID, // From secure source
203
+ mountPath: 'approle' // Optional, defaults to 'approle'
204
+ }
205
+ }
206
+ ```
207
+
208
+ **GCP IAM Authentication**:
209
+ ```typescript
210
+ auth: {
211
+ method: 'gcp',
212
+ config: {
213
+ role: 'my-vault-role',
214
+ serviceAccountKeyFile: '/path/to/key.json', // Optional, uses ADC if not provided
215
+ serviceAccountEmail: 'my-service@project.iam.gserviceaccount.com', // Optional
216
+ jwtExpiration: 900 // Optional, default 15 minutes
217
+ }
218
+ }
219
+ ```
220
+
221
+ **AWS IAM Authentication**:
222
+ ```typescript
223
+ auth: {
224
+ method: 'aws',
225
+ config: {
226
+ role: 'my-vault-role'
227
+ // Uses instance profile or environment credentials automatically
228
+ }
229
+ }
230
+ ```
231
+
232
+ **Multiple Auth Methods** (Fallback Chain):
233
+ ```typescript
234
+ auth: {
235
+ methods: [
236
+ {
237
+ type: 'gcp',
238
+ config: { role: 'my-role' }
239
+ },
240
+ {
241
+ type: 'approle',
242
+ config: {
243
+ roleId: process.env.VAULT_ROLE_ID,
244
+ secretId: process.env.VAULT_SECRET_ID
245
+ }
246
+ }
247
+ ]
248
+ }
249
+ ```
250
+
251
+ #### TLS Configuration
252
+
253
+ ```typescript
254
+ tls: {
255
+ enabled: true, // Required (cannot be disabled)
256
+ verifyCertificate: true, // Verify server certificate
257
+ certificateFingerprint: 'sha256:...', // Optional: pin certificate
258
+ caCert: '-----BEGIN CERTIFICATE-----\n...', // Optional: custom CA
259
+ minVersion: 'TLSv1.2' // Optional: minimum TLS version
260
+ }
261
+ ```
262
+
263
+ #### Refresh Buffer
264
+
265
+ The refresh buffer determines when secrets are refreshed before expiration:
266
+
267
+ ```typescript
268
+ refreshBuffer: 300 // Refresh 300 seconds (5 minutes) before TTL expires
269
+ ```
270
+
271
+ Default: `min(10% of TTL, 300 seconds)` - whichever is smaller.
272
+
273
+ ### Vault Decorators
274
+
275
+ Use composable decorators to mark configuration properties as Vault secrets. Decorators work alongside `@ConfigVariable` and `class-validator` decorators.
276
+
277
+ #### `@VaultPath(path)` - Required
278
+
279
+ Specifies the Vault path for a property. Any property with `@VaultPath` is treated as a Vault secret.
280
+
281
+ ```typescript
282
+ @VaultPath('secret/data/myapp/api_key')
283
+ API_KEY: string;
284
+ ```
285
+
286
+ #### `@VaultEngine(type)` - Optional
287
+
288
+ Specifies the Vault secrets engine type. Auto-detected from path if not provided.
289
+
290
+ ```typescript
291
+ @VaultEngine('database') // 'kv-v1', 'kv-v2', 'database', 'aws', 'gcp', etc.
292
+ DATABASE_PASSWORD: string;
293
+ ```
294
+
295
+ Supported engines:
296
+ - `kv-v1`, `kv-v2`: Key-Value stores (default: `kv-v2`)
297
+ - `database`: Database secrets engine (dynamic credentials)
298
+ - `aws`, `azure`, `gcp`: Cloud provider secrets engines
299
+ - `transit`, `pki`: Encryption and certificate engines
300
+ - `custom`: Custom engines (requires custom extraction logic)
301
+
302
+ #### `@VaultKey(key)` - Optional
303
+
304
+ Specifies the key name within the secret. Only used for KV v1/v2 engines. Defaults to property name in kebab-case.
305
+
306
+ ```typescript
307
+ @VaultKey('api_key') // If key name differs from property name
308
+ API_KEY: string;
309
+ ```
310
+
311
+ #### `@VaultRefreshBuffer(seconds)` - Optional
312
+
313
+ Override default refresh buffer for a specific secret.
314
+
315
+ ```typescript
316
+ @VaultRefreshBuffer(600) // Refresh 10 minutes before expiry
317
+ DATABASE_PASSWORD: string;
318
+ ```
319
+
320
+ #### `@VaultOptional()` - Optional
321
+
322
+ Mark secret as optional - allows fallback to environment variable if Vault unavailable.
323
+
324
+ ```typescript
325
+ @VaultOptional()
326
+ FEATURE_FLAG?: boolean;
327
+ ```
328
+
329
+ ### Usage Examples
330
+
331
+ #### Basic Example with Token Auth
332
+
333
+ ```typescript
334
+ import { BaseConfig, Configuration, ConfigVariable, VaultPath, VaultKey } from '@kibibit/configit';
335
+ import { IsString } from 'class-validator';
336
+
337
+ @Configuration()
338
+ export class AppConfig extends BaseConfig {
339
+ @VaultPath('secret/data/myapp/api_key')
340
+ @VaultKey('api_key')
341
+ @ConfigVariable('API key for external service')
342
+ @IsString()
343
+ API_KEY: string;
344
+
345
+ @ConfigVariable('Server port')
346
+ @IsNumber()
347
+ PORT: number;
348
+ }
349
+
350
+ // Initialize with Vault
351
+ const configService = new ConfigService(AppConfig, undefined, {
352
+ vault: {
353
+ endpoint: process.env.VAULT_ADDR || 'http://127.0.0.1:8200',
354
+ auth: {
355
+ method: 'token',
356
+ config: {
357
+ token: process.env.VAULT_TOKEN
358
+ }
359
+ }
360
+ }
361
+ });
362
+
363
+ await configService.initializeVault();
364
+ console.log(configService.config.API_KEY); // Loaded from Vault
365
+ ```
366
+
367
+ #### GCP IAM Authentication
368
+
369
+ ```typescript
370
+ const configService = new ConfigService(AppConfig, undefined, {
371
+ vault: {
372
+ endpoint: 'https://vault.example.com',
373
+ auth: {
374
+ method: 'gcp',
375
+ config: {
376
+ role: 'my-vault-role'
377
+ // Uses Application Default Credentials (ADC)
378
+ }
379
+ },
380
+ tls: {
381
+ enabled: true,
382
+ verifyCertificate: true
383
+ }
384
+ }
385
+ });
386
+
387
+ await configService.initializeVault();
388
+ ```
389
+
390
+ #### Dynamic Database Credentials
391
+
392
+ ```typescript
393
+ import { BaseConfig, Configuration, ConfigVariable, VaultPath, VaultEngine, VaultKey } from '@kibibit/configit';
394
+ import { IsString } from 'class-validator';
395
+
396
+ @Configuration()
397
+ export class DatabaseConfig extends BaseConfig {
398
+ @VaultPath('database/creds/my-role')
399
+ @VaultEngine('database')
400
+ @VaultKey('username')
401
+ @ConfigVariable('Database username')
402
+ @IsString()
403
+ DATABASE_USERNAME: string;
404
+
405
+ @VaultPath('database/creds/my-role')
406
+ @VaultEngine('database')
407
+ @VaultKey('password')
408
+ @ConfigVariable('Database password')
409
+ @IsString()
410
+ DATABASE_PASSWORD: string;
411
+ }
412
+ ```
413
+
414
+ **Behavior**:
415
+ - Credentials automatically refresh before TTL expires
416
+ - Both `username` and `password` refreshed together (same lease)
417
+ - Background refresh happens seamlessly
418
+
419
+ #### Optional Secret with Fallback
420
+
421
+ ```typescript
422
+ @Configuration()
423
+ export class OptionalConfig extends BaseConfig {
424
+ @VaultPath('secret/data/myapp/feature_flag')
425
+ @VaultKey('enabled')
426
+ @VaultOptional()
427
+ @ConfigVariable('Optional feature flag')
428
+ @IsOptional()
429
+ @IsBoolean()
430
+ FEATURE_FLAG_ENABLED?: boolean;
431
+ }
432
+ ```
433
+
434
+ If Vault is unavailable, falls back to `FEATURE_FLAG_ENABLED` environment variable.
435
+
436
+ #### Mixed Vault and Non-Vault Properties
437
+
438
+ ```typescript
439
+ @Configuration()
440
+ export class MixedConfig extends BaseConfig {
441
+ // From Vault
442
+ @VaultPath('database/creds/my-role')
443
+ @VaultEngine('database')
444
+ @VaultKey('password')
445
+ @ConfigVariable('Database password')
446
+ @IsString()
447
+ DATABASE_PASSWORD: string;
448
+
449
+ // From environment variable (no Vault decorators)
450
+ @ConfigVariable('Database host')
451
+ @IsString()
452
+ DATABASE_HOST: string;
453
+
454
+ // From Vault
455
+ @VaultPath('secret/data/myapp/api_key')
456
+ @ConfigVariable('API key')
457
+ @IsString()
458
+ API_KEY: string;
459
+ }
460
+ ```
461
+
462
+ ### Source Hierarchy
463
+
464
+ Configit uses the following source priority (highest to lowest):
465
+
466
+ 1. **Vault** (if configured) - Highest priority
467
+ 2. **CLI arguments** (`--key=value`)
468
+ 3. **Environment variables** (`KEY=value`)
469
+ 4. **Config files** (`.env.development.json`, etc.) - Lowest priority
470
+
471
+ Vault secrets are injected into `nconf.overrides()` which has the highest priority in the nconf hierarchy.
472
+
473
+ ### Health Monitoring
474
+
475
+ Monitor Vault connection status and secret refresh schedule:
476
+
477
+ ```typescript
478
+ const health = configService.getVaultHealth();
479
+
480
+ if (health) {
481
+ console.log('Connected:', health.connected);
482
+ console.log('Authenticated:', health.authenticated);
483
+ console.log('Cached secrets:', health.cacheSize);
484
+ console.log('Scheduled refreshes:', health.refreshQueueSize);
485
+ console.log('Last refresh:', new Date(health.lastRefreshTime));
486
+ console.log('Recent errors:', health.errors);
487
+ }
488
+ ```
489
+
490
+ **Health Status Fields**:
491
+ - `connected`: Whether connected to Vault
492
+ - `authenticated`: Whether authenticated successfully
493
+ - `cacheSize`: Number of cached secrets
494
+ - `refreshQueueSize`: Number of scheduled refreshes
495
+ - `lastRefreshTime`: Timestamp of last refresh
496
+ - `errors`: Array of recent errors (last 10)
497
+
498
+ ### Example: NestJS Integration
499
+
500
+ See `examples/vault-nestjs-sequelize/` for a complete example showing:
501
+ - NestJS application setup
502
+ - Sequelize with dynamic database credentials
503
+ - Automatic credential rotation
504
+ - Health check endpoints
505
+
506
+ ```typescript
507
+ // In NestJS onModuleInit
508
+ export class ConfigModule implements OnModuleInit {
509
+ async onModuleInit() {
510
+ await configService.initializeVault();
511
+ }
512
+ }
513
+ ```
514
+
515
+ ### Troubleshooting
516
+
517
+ **Vault Connection Failed**:
518
+ - Verify Vault is running: `vault status`
519
+ - Check endpoint URL and TLS configuration
520
+ - Verify authentication credentials
521
+
522
+ **Secrets Not Refreshing**:
523
+ - Check `getVaultHealth()` for refresh queue status
524
+ - Verify TTL is set on secrets (dynamic secrets only)
525
+ - Check refresh buffer configuration
526
+
527
+ **Secret Not Found**:
528
+ - Verify Vault path exists: `vault kv get secret/data/myapp/api_key`
529
+ - Check authentication has read permissions
530
+ - Use `@VaultOptional()` to allow fallback
531
+
532
+ For more examples and advanced usage, see the `examples/` folder.
114
533
 
115
534
  ## Features
116
535
  - Supports JSON\YAML files\env variables\cli flags as configuration inputs. See `yaml-config` in the examples folder
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ //# sourceMappingURL=test-vault-comprehensive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-vault-comprehensive.d.ts","sourceRoot":"","sources":["../../scripts/test-vault-comprehensive.ts"],"names":[],"mappings":"AAYA,OAAO,kBAAkB,CAAC"}