@onivoro/server-aws-credential-providers 24.0.0

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.
package/README.md ADDED
@@ -0,0 +1,592 @@
1
+ # @onivoro/server-aws-credential-providers
2
+
3
+ A NestJS module for managing AWS credential providers with support for multiple AWS profiles, credential resolution, and secure credential management for server-side applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @onivoro/server-aws-credential-providers
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Multi-Profile Support**: Manage multiple AWS profiles (dev, staging, production)
14
+ - **Credential Resolution**: Automatic credential resolution from various sources
15
+ - **Profile-Based Configuration**: Profile-specific credential providers
16
+ - **Environment Integration**: Seamless integration with AWS environment configurations
17
+ - **Secure Credential Management**: Safe handling of AWS credentials
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Module Configuration
22
+
23
+ ```typescript
24
+ import { ServerAwsCredentialProvidersModule } from '@onivoro/server-aws-credential-providers';
25
+
26
+ @Module({
27
+ imports: [
28
+ ServerAwsCredentialProvidersModule.forRoot({
29
+ profiles: {
30
+ development: {
31
+ region: 'us-east-1',
32
+ accessKeyId: process.env.AWS_DEV_ACCESS_KEY_ID,
33
+ secretAccessKey: process.env.AWS_DEV_SECRET_ACCESS_KEY,
34
+ },
35
+ production: {
36
+ region: 'us-west-2',
37
+ accessKeyId: process.env.AWS_PROD_ACCESS_KEY_ID,
38
+ secretAccessKey: process.env.AWS_PROD_SECRET_ACCESS_KEY,
39
+ }
40
+ },
41
+ defaultProfile: 'development'
42
+ }),
43
+ ],
44
+ })
45
+ export class AppModule {}
46
+ ```
47
+
48
+ ### 2. Using AWS Credentials
49
+
50
+ ```typescript
51
+ import { AwsCredentials } from '@onivoro/server-aws-credential-providers';
52
+
53
+ @Injectable()
54
+ export class S3Service {
55
+ constructor(private awsCredentials: AwsCredentials) {}
56
+
57
+ async getS3Client(profile: string = 'development') {
58
+ const credentials = await this.awsCredentials.getCredentials(profile);
59
+
60
+ return new S3Client({
61
+ region: credentials.region,
62
+ credentials: {
63
+ accessKeyId: credentials.accessKeyId,
64
+ secretAccessKey: credentials.secretAccessKey,
65
+ sessionToken: credentials.sessionToken,
66
+ }
67
+ });
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Configuration
73
+
74
+ ### ServerAwsCredentialProvidersConfig
75
+
76
+ ```typescript
77
+ import { ServerAwsCredentialProvidersConfig } from '@onivoro/server-aws-credential-providers';
78
+
79
+ export class AppAwsCredentialsConfig extends ServerAwsCredentialProvidersConfig {
80
+ profiles = {
81
+ development: {
82
+ region: process.env.AWS_DEV_REGION || 'us-east-1',
83
+ accessKeyId: process.env.AWS_DEV_ACCESS_KEY_ID,
84
+ secretAccessKey: process.env.AWS_DEV_SECRET_ACCESS_KEY,
85
+ roleArn: process.env.AWS_DEV_ROLE_ARN,
86
+ },
87
+ staging: {
88
+ region: process.env.AWS_STAGING_REGION || 'us-east-1',
89
+ accessKeyId: process.env.AWS_STAGING_ACCESS_KEY_ID,
90
+ secretAccessKey: process.env.AWS_STAGING_SECRET_ACCESS_KEY,
91
+ roleArn: process.env.AWS_STAGING_ROLE_ARN,
92
+ },
93
+ production: {
94
+ region: process.env.AWS_PROD_REGION || 'us-west-2',
95
+ accessKeyId: process.env.AWS_PROD_ACCESS_KEY_ID,
96
+ secretAccessKey: process.env.AWS_PROD_SECRET_ACCESS_KEY,
97
+ roleArn: process.env.AWS_PROD_ROLE_ARN,
98
+ }
99
+ };
100
+ defaultProfile = process.env.AWS_DEFAULT_PROFILE || 'development';
101
+ credentialProviderTimeout = parseInt(process.env.AWS_CREDENTIAL_TIMEOUT) || 30000;
102
+ }
103
+ ```
104
+
105
+ ### Environment Variables
106
+
107
+ ```bash
108
+ # Development Profile
109
+ AWS_DEV_REGION=us-east-1
110
+ AWS_DEV_ACCESS_KEY_ID=your-dev-access-key
111
+ AWS_DEV_SECRET_ACCESS_KEY=your-dev-secret-key
112
+ AWS_DEV_ROLE_ARN=arn:aws:iam::123456789012:role/DevRole
113
+
114
+ # Staging Profile
115
+ AWS_STAGING_REGION=us-east-1
116
+ AWS_STAGING_ACCESS_KEY_ID=your-staging-access-key
117
+ AWS_STAGING_SECRET_ACCESS_KEY=your-staging-secret-key
118
+ AWS_STAGING_ROLE_ARN=arn:aws:iam::123456789012:role/StagingRole
119
+
120
+ # Production Profile
121
+ AWS_PROD_REGION=us-west-2
122
+ AWS_PROD_ACCESS_KEY_ID=your-prod-access-key
123
+ AWS_PROD_SECRET_ACCESS_KEY=your-prod-secret-key
124
+ AWS_PROD_ROLE_ARN=arn:aws:iam::123456789012:role/ProdRole
125
+
126
+ # Default Settings
127
+ AWS_DEFAULT_PROFILE=development
128
+ AWS_CREDENTIAL_TIMEOUT=30000
129
+ ```
130
+
131
+ ## Core Classes
132
+
133
+ ### AwsCredentials
134
+
135
+ Main service for managing AWS credentials:
136
+
137
+ ```typescript
138
+ import { AwsCredentials } from '@onivoro/server-aws-credential-providers';
139
+
140
+ @Injectable()
141
+ export class CloudService {
142
+ constructor(private awsCredentials: AwsCredentials) {}
143
+
144
+ async getDynamoDBClient(profile?: string) {
145
+ const credentials = await this.awsCredentials.getCredentials(profile);
146
+
147
+ return new DynamoDBClient({
148
+ region: credentials.region,
149
+ credentials: {
150
+ accessKeyId: credentials.accessKeyId,
151
+ secretAccessKey: credentials.secretAccessKey,
152
+ sessionToken: credentials.sessionToken,
153
+ }
154
+ });
155
+ }
156
+
157
+ async assumeRole(roleArn: string, sessionName: string, profile?: string) {
158
+ return this.awsCredentials.assumeRole({
159
+ roleArn,
160
+ sessionName,
161
+ profile
162
+ });
163
+ }
164
+
165
+ async getCredentialsForProfile(profileName: string) {
166
+ return this.awsCredentials.getCredentials(profileName);
167
+ }
168
+
169
+ async refreshCredentials(profile?: string) {
170
+ return this.awsCredentials.refreshCredentials(profile);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ## Utility Functions
176
+
177
+ ### resolveAwsCredentialProvidersByProfile
178
+
179
+ Resolves credential providers for a specific profile:
180
+
181
+ ```typescript
182
+ import { resolveAwsCredentialProvidersByProfile } from '@onivoro/server-aws-credential-providers';
183
+
184
+ // Resolve credentials for a specific profile
185
+ const credentialProvider = await resolveAwsCredentialProvidersByProfile('production');
186
+
187
+ // Use with AWS SDK clients
188
+ const s3Client = new S3Client({
189
+ region: 'us-west-2',
190
+ credentials: credentialProvider
191
+ });
192
+ ```
193
+
194
+ ## Advanced Usage
195
+
196
+ ### Multi-Environment Service
197
+
198
+ ```typescript
199
+ @Injectable()
200
+ export class MultiEnvironmentService {
201
+ constructor(private awsCredentials: AwsCredentials) {}
202
+
203
+ async deployToMultipleEnvironments(deploymentConfig: any) {
204
+ const environments = ['development', 'staging', 'production'];
205
+ const results = [];
206
+
207
+ for (const env of environments) {
208
+ try {
209
+ console.log(`Deploying to ${env}...`);
210
+
211
+ const credentials = await this.awsCredentials.getCredentials(env);
212
+ const client = this.createClientForEnvironment(env, credentials);
213
+
214
+ const result = await this.performDeployment(client, deploymentConfig);
215
+ results.push({ environment: env, success: true, result });
216
+
217
+ console.log(`✅ Successfully deployed to ${env}`);
218
+ } catch (error) {
219
+ console.error(`❌ Failed to deploy to ${env}:`, error.message);
220
+ results.push({
221
+ environment: env,
222
+ success: false,
223
+ error: error.message
224
+ });
225
+ }
226
+ }
227
+
228
+ return results;
229
+ }
230
+
231
+ private createClientForEnvironment(environment: string, credentials: any) {
232
+ // Create appropriate AWS service client based on environment
233
+ switch (environment) {
234
+ case 'development':
235
+ return new S3Client({ region: 'us-east-1', credentials });
236
+ case 'staging':
237
+ return new S3Client({ region: 'us-east-1', credentials });
238
+ case 'production':
239
+ return new S3Client({ region: 'us-west-2', credentials });
240
+ default:
241
+ throw new Error(`Unknown environment: ${environment}`);
242
+ }
243
+ }
244
+
245
+ private async performDeployment(client: any, config: any) {
246
+ // Deployment logic here
247
+ return { deploymentId: `deploy-${Date.now()}` };
248
+ }
249
+ }
250
+ ```
251
+
252
+ ### Credential Caching Service
253
+
254
+ ```typescript
255
+ @Injectable()
256
+ export class CredentialCacheService {
257
+ private credentialCache = new Map<string, { credentials: any; expiry: Date }>();
258
+ private readonly CACHE_DURATION = 50 * 60 * 1000; // 50 minutes
259
+
260
+ constructor(private awsCredentials: AwsCredentials) {}
261
+
262
+ async getCachedCredentials(profile: string = 'default') {
263
+ const cacheKey = `credentials-${profile}`;
264
+ const cached = this.credentialCache.get(cacheKey);
265
+
266
+ if (cached && cached.expiry > new Date()) {
267
+ console.log(`Using cached credentials for profile: ${profile}`);
268
+ return cached.credentials;
269
+ }
270
+
271
+ console.log(`Fetching fresh credentials for profile: ${profile}`);
272
+ const credentials = await this.awsCredentials.getCredentials(profile);
273
+
274
+ // Cache the credentials
275
+ this.credentialCache.set(cacheKey, {
276
+ credentials,
277
+ expiry: new Date(Date.now() + this.CACHE_DURATION)
278
+ });
279
+
280
+ return credentials;
281
+ }
282
+
283
+ clearCache(profile?: string) {
284
+ if (profile) {
285
+ this.credentialCache.delete(`credentials-${profile}`);
286
+ } else {
287
+ this.credentialCache.clear();
288
+ }
289
+ }
290
+
291
+ getCacheStatus() {
292
+ const status = Array.from(this.credentialCache.entries()).map(([key, value]) => ({
293
+ profile: key.replace('credentials-', ''),
294
+ hasCredentials: !!value.credentials,
295
+ expiresAt: value.expiry,
296
+ isExpired: value.expiry <= new Date()
297
+ }));
298
+
299
+ return status;
300
+ }
301
+ }
302
+ ```
303
+
304
+ ### Cross-Account Access Service
305
+
306
+ ```typescript
307
+ @Injectable()
308
+ export class CrossAccountService {
309
+ constructor(private awsCredentials: AwsCredentials) {}
310
+
311
+ async accessCrossAccountResource(
312
+ targetAccountId: string,
313
+ roleName: string,
314
+ sourceProfile: string = 'production'
315
+ ) {
316
+ const sourceCredentials = await this.awsCredentials.getCredentials(sourceProfile);
317
+
318
+ // Create STS client with source credentials
319
+ const stsClient = new STSClient({
320
+ region: sourceCredentials.region,
321
+ credentials: sourceCredentials
322
+ });
323
+
324
+ // Assume role in target account
325
+ const roleArn = `arn:aws:iam::${targetAccountId}:role/${roleName}`;
326
+ const assumeRoleCommand = new AssumeRoleCommand({
327
+ RoleArn: roleArn,
328
+ RoleSessionName: `cross-account-${Date.now()}`,
329
+ DurationSeconds: 3600 // 1 hour
330
+ });
331
+
332
+ const assumeRoleResponse = await stsClient.send(assumeRoleCommand);
333
+
334
+ if (!assumeRoleResponse.Credentials) {
335
+ throw new Error('Failed to assume cross-account role');
336
+ }
337
+
338
+ return {
339
+ accessKeyId: assumeRoleResponse.Credentials.AccessKeyId!,
340
+ secretAccessKey: assumeRoleResponse.Credentials.SecretAccessKey!,
341
+ sessionToken: assumeRoleResponse.Credentials.SessionToken!,
342
+ expiration: assumeRoleResponse.Credentials.Expiration
343
+ };
344
+ }
345
+
346
+ async createCrossAccountClient<T>(
347
+ clientClass: new (config: any) => T,
348
+ targetAccountId: string,
349
+ roleName: string,
350
+ region: string,
351
+ sourceProfile?: string
352
+ ): Promise<T> {
353
+ const crossAccountCredentials = await this.accessCrossAccountResource(
354
+ targetAccountId,
355
+ roleName,
356
+ sourceProfile
357
+ );
358
+
359
+ return new clientClass({
360
+ region,
361
+ credentials: {
362
+ accessKeyId: crossAccountCredentials.accessKeyId,
363
+ secretAccessKey: crossAccountCredentials.secretAccessKey,
364
+ sessionToken: crossAccountCredentials.sessionToken
365
+ }
366
+ });
367
+ }
368
+ }
369
+ ```
370
+
371
+ ### Profile Validation Service
372
+
373
+ ```typescript
374
+ @Injectable()
375
+ export class ProfileValidationService {
376
+ constructor(private awsCredentials: AwsCredentials) {}
377
+
378
+ async validateAllProfiles() {
379
+ const config = this.awsCredentials.getConfiguration();
380
+ const results = [];
381
+
382
+ for (const [profileName, profileConfig] of Object.entries(config.profiles)) {
383
+ try {
384
+ console.log(`Validating profile: ${profileName}`);
385
+
386
+ const credentials = await this.awsCredentials.getCredentials(profileName);
387
+
388
+ // Test credentials by calling STS GetCallerIdentity
389
+ const stsClient = new STSClient({
390
+ region: profileConfig.region,
391
+ credentials
392
+ });
393
+
394
+ const identity = await stsClient.send(new GetCallerIdentityCommand({}));
395
+
396
+ results.push({
397
+ profile: profileName,
398
+ valid: true,
399
+ account: identity.Account,
400
+ arn: identity.Arn,
401
+ userId: identity.UserId
402
+ });
403
+
404
+ console.log(`✅ Profile ${profileName} is valid (Account: ${identity.Account})`);
405
+ } catch (error) {
406
+ console.error(`❌ Profile ${profileName} validation failed:`, error.message);
407
+ results.push({
408
+ profile: profileName,
409
+ valid: false,
410
+ error: error.message
411
+ });
412
+ }
413
+ }
414
+
415
+ return results;
416
+ }
417
+
418
+ async validateProfile(profileName: string) {
419
+ try {
420
+ const credentials = await this.awsCredentials.getCredentials(profileName);
421
+ const config = this.awsCredentials.getConfiguration();
422
+ const profileConfig = config.profiles[profileName];
423
+
424
+ if (!profileConfig) {
425
+ throw new Error(`Profile ${profileName} not found in configuration`);
426
+ }
427
+
428
+ const stsClient = new STSClient({
429
+ region: profileConfig.region,
430
+ credentials
431
+ });
432
+
433
+ const identity = await stsClient.send(new GetCallerIdentityCommand({}));
434
+
435
+ return {
436
+ profile: profileName,
437
+ valid: true,
438
+ account: identity.Account,
439
+ arn: identity.Arn,
440
+ userId: identity.UserId,
441
+ region: profileConfig.region
442
+ };
443
+ } catch (error) {
444
+ return {
445
+ profile: profileName,
446
+ valid: false,
447
+ error: error.message
448
+ };
449
+ }
450
+ }
451
+ }
452
+ ```
453
+
454
+ ## Integration Examples
455
+
456
+ ### Using with Other AWS Services
457
+
458
+ ```typescript
459
+ @Injectable()
460
+ export class IntegratedAwsService {
461
+ constructor(private awsCredentials: AwsCredentials) {}
462
+
463
+ async createS3Service(profile?: string) {
464
+ const credentials = await this.awsCredentials.getCredentials(profile);
465
+ return new S3Service(new S3Client({
466
+ region: credentials.region,
467
+ credentials
468
+ }));
469
+ }
470
+
471
+ async createDynamoDBService(profile?: string) {
472
+ const credentials = await this.awsCredentials.getCredentials(profile);
473
+ return new DynamoDBService(new DynamoDBClient({
474
+ region: credentials.region,
475
+ credentials
476
+ }));
477
+ }
478
+
479
+ async createLambdaService(profile?: string) {
480
+ const credentials = await this.awsCredentials.getCredentials(profile);
481
+ return new LambdaService(new LambdaClient({
482
+ region: credentials.region,
483
+ credentials
484
+ }));
485
+ }
486
+ }
487
+ ```
488
+
489
+ ## Best Practices
490
+
491
+ ### 1. Environment-Specific Profiles
492
+
493
+ ```typescript
494
+ const getProfileForEnvironment = (env: string) => {
495
+ switch (env) {
496
+ case 'development':
497
+ case 'dev':
498
+ return 'development';
499
+ case 'staging':
500
+ case 'test':
501
+ return 'staging';
502
+ case 'production':
503
+ case 'prod':
504
+ return 'production';
505
+ default:
506
+ return 'development';
507
+ }
508
+ };
509
+ ```
510
+
511
+ ### 2. Credential Rotation Handling
512
+
513
+ ```typescript
514
+ @Injectable()
515
+ export class CredentialRotationService {
516
+ constructor(private awsCredentials: AwsCredentials) {}
517
+
518
+ async handleCredentialRotation(profile: string) {
519
+ try {
520
+ // Clear any cached credentials
521
+ await this.awsCredentials.refreshCredentials(profile);
522
+
523
+ // Verify new credentials work
524
+ const validation = await this.validateCredentials(profile);
525
+
526
+ if (!validation.valid) {
527
+ throw new Error(`New credentials for ${profile} are invalid`);
528
+ }
529
+
530
+ console.log(`✅ Credentials rotated successfully for ${profile}`);
531
+ return { success: true, profile, newIdentity: validation };
532
+
533
+ } catch (error) {
534
+ console.error(`❌ Credential rotation failed for ${profile}:`, error.message);
535
+ throw error;
536
+ }
537
+ }
538
+
539
+ private async validateCredentials(profile: string) {
540
+ const credentials = await this.awsCredentials.getCredentials(profile);
541
+ // Validation logic here
542
+ return { valid: true };
543
+ }
544
+ }
545
+ ```
546
+
547
+ ## Testing
548
+
549
+ ```typescript
550
+ import { Test, TestingModule } from '@nestjs/testing';
551
+ import { ServerAwsCredentialProvidersModule, AwsCredentials } from '@onivoro/server-aws-credential-providers';
552
+
553
+ describe('AwsCredentials', () => {
554
+ let service: AwsCredentials;
555
+
556
+ beforeEach(async () => {
557
+ const module: TestingModule = await Test.createTestingModule({
558
+ imports: [ServerAwsCredentialProvidersModule.forRoot({
559
+ profiles: {
560
+ test: {
561
+ region: 'us-east-1',
562
+ accessKeyId: 'test-key',
563
+ secretAccessKey: 'test-secret'
564
+ }
565
+ }
566
+ })],
567
+ }).compile();
568
+
569
+ service = module.get<AwsCredentials>(AwsCredentials);
570
+ });
571
+
572
+ it('should resolve credentials for profile', async () => {
573
+ const credentials = await service.getCredentials('test');
574
+ expect(credentials).toBeDefined();
575
+ expect(credentials.region).toBe('us-east-1');
576
+ });
577
+ });
578
+ ```
579
+
580
+ ## API Reference
581
+
582
+ ### Exported Classes
583
+ - `AwsCredentials`: Main credential management service
584
+ - `ServerAwsCredentialProvidersConfig`: Configuration class
585
+ - `ServerAwsCredentialProvidersModule`: NestJS module
586
+
587
+ ### Exported Functions
588
+ - `resolveAwsCredentialProvidersByProfile`: Profile-specific credential resolution
589
+
590
+ ## License
591
+
592
+ This package is part of the Onivoro monorepo and follows the same licensing terms.
package/jest.config.ts ADDED
@@ -0,0 +1,11 @@
1
+ /* eslint-disable */
2
+ export default {
3
+ displayName: 'lib-server-aws-credential-providers',
4
+ preset: '../../../jest.preset.js',
5
+ testEnvironment: 'node',
6
+ transform: {
7
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
8
+ },
9
+ moduleFileExtensions: ['ts', 'js', 'html'],
10
+ coverageDirectory: '../../../coverage/libs/server/aws-credential-providers',
11
+ };
package/package.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@onivoro/server-aws-credential-providers",
3
+ "version": "24.0.0",
4
+ "type": "commonjs",
5
+ "main": "./src/index.js",
6
+ "types": "./src/index.d.ts",
7
+ "dependencies": {
8
+ "tslib": "^2.3.0"
9
+ }
10
+ }
package/project.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "lib-server-aws-credential-providers",
3
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "libs/server/aws-credential-providers/src",
5
+ "projectType": "library",
6
+ "targets": {
7
+ "build": {
8
+ "executor": "@nx/js:tsc",
9
+ "outputs": ["{options.outputPath}"],
10
+ "options": {
11
+ "outputPath": "dist/libs/server/aws-credential-providers",
12
+ "main": "libs/server/aws-credential-providers/src/index.ts",
13
+ "tsConfig": "libs/server/aws-credential-providers/tsconfig.lib.json",
14
+ "assets": [
15
+ "libs/server/aws-credential-providers/README.md",
16
+ "libs/server/aws-credential-providers/package.json"
17
+ ],
18
+ "declaration": true
19
+ }
20
+ }
21
+ },
22
+ "tags": []
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './lib/aws-credentials.class';
2
+ export * from './lib/resolve-aws-credential-providers-by-profile.function';
3
+ export * from './lib/server-aws-credential-providers-config.class';
4
+ export * from './lib/server-aws-credential-providers.module';
@@ -0,0 +1,4 @@
1
+ export class AwsCredentials {
2
+ accessKeyId: string;
3
+ secretAccessKey: string;
4
+ }
@@ -0,0 +1,43 @@
1
+ import { fromIni } from "@aws-sdk/credential-providers";
2
+ import { AwsCredentials } from "./aws-credentials.class";
3
+
4
+ const AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID';
5
+ const AWS_SECRET_ACCESS_KEY = 'AWS_SECRET_ACCESS_KEY';
6
+
7
+ export async function resolveAwsCredentialProvidersByProfile(profile?: string | undefined): Promise<AwsCredentials | undefined> {
8
+ if (profile) {
9
+ try {
10
+ console.warn(`attempting to use AWS profile "${profile}" for AWS authentication`);
11
+
12
+ const credentialResolver = fromIni({ profile });
13
+
14
+ return await credentialResolver();
15
+ } catch (error) {
16
+ console.warn(`failed to load AWS profile "${profile}"... ensure that ${[AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY].map(_ => `"${_.toLowerCase()}"`).join(' and ')} are lowercase in your ~/.aws/credentials file`);
17
+
18
+ if (
19
+ (process.env[AWS_ACCESS_KEY_ID] && process.env[AWS_SECRET_ACCESS_KEY])
20
+ ) {
21
+ console.log(`using UPPERCASE AWS_* environment variables for AWS authentication`);
22
+
23
+ return {
24
+ accessKeyId: process.env[AWS_ACCESS_KEY_ID],
25
+ secretAccessKey: process.env[AWS_SECRET_ACCESS_KEY],
26
+ };
27
+ }
28
+
29
+ if (
30
+ (process.env[AWS_ACCESS_KEY_ID.toLowerCase()] && process.env[AWS_SECRET_ACCESS_KEY.toLowerCase()])
31
+ ) {
32
+ console.log(`using lowercase aws_* environment variables for AWS authentication`);
33
+
34
+ return {
35
+ accessKeyId: process.env[AWS_ACCESS_KEY_ID.toLowerCase()]!,
36
+ secretAccessKey: process.env[AWS_SECRET_ACCESS_KEY.toLowerCase()]!,
37
+ };
38
+ }
39
+
40
+ return undefined;
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,3 @@
1
+ export class ServerAwsCredentialProvidersConfig {
2
+ AWS_PROFILE?: string;
3
+ }
@@ -0,0 +1,21 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { ServerAwsCredentialProvidersConfig } from './server-aws-credential-providers-config.class';
3
+ import { resolveAwsCredentialProvidersByProfile } from './resolve-aws-credential-providers-by-profile.function';
4
+ import { AwsCredentials } from './aws-credentials.class';
5
+
6
+ @Module({})
7
+ export class ServerAwsCredentialProvidersModule {
8
+ static configure(config: ServerAwsCredentialProvidersConfig) {
9
+ return {
10
+ module: ServerAwsCredentialProvidersModule,
11
+ providers: [
12
+ { provide: ServerAwsCredentialProvidersConfig, useValue: config },
13
+ {
14
+ provide: AwsCredentials,
15
+ useFactory: async () => await resolveAwsCredentialProvidersByProfile(config.AWS_PROFILE),
16
+ },
17
+ ],
18
+ exports: [AwsCredentials, ServerAwsCredentialProvidersConfig],
19
+ };
20
+ }
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../../tsconfig.server.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../../dist/out-tsc"
5
+ },
6
+ "files": [],
7
+ "include": [],
8
+ "references": [
9
+ {
10
+ "path": "./tsconfig.lib.json"
11
+ },
12
+ {
13
+ "path": "./tsconfig.spec.json"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "declaration": true
5
+ },
6
+ "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"],
7
+ "include": ["**/*.ts"]
8
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": [
5
+ "jest",
6
+ "node"
7
+ ]
8
+ },
9
+ "include": [
10
+ "jest.config.ts",
11
+ "**/*.test.ts",
12
+ "**/*.spec.ts",
13
+ "**/*.test.tsx",
14
+ "**/*.spec.tsx",
15
+ "**/*.test.js",
16
+ "**/*.spec.js",
17
+ "**/*.test.jsx",
18
+ "**/*.spec.jsx",
19
+ "**/*.d.ts"
20
+ ]
21
+ }