@onivoro/server-aws-sts 24.39.0 → 25.1.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 +31 -124
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ AWS STS integration for NestJS applications.
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @onivoro/server-aws-sts
|
|
8
|
+
npm install @onivoro/server-aws-sts @aws-sdk/client-sts
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
@@ -20,23 +20,30 @@ import { ServerAwsStsModule } from '@onivoro/server-aws-sts';
|
|
|
20
20
|
|
|
21
21
|
@Module({
|
|
22
22
|
imports: [
|
|
23
|
-
ServerAwsStsModule.configure(
|
|
24
|
-
|
|
23
|
+
ServerAwsStsModule.configure({
|
|
24
|
+
AWS_REGION: process.env.AWS_REGION!,
|
|
25
|
+
AWS_PROFILE: process.env.AWS_PROFILE, // optional
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
25
28
|
})
|
|
26
29
|
export class AppModule {}
|
|
27
30
|
```
|
|
28
31
|
|
|
29
32
|
## Configuration
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
`configure()` takes the config object directly; the module does not read environment variables itself.
|
|
32
35
|
|
|
33
36
|
```typescript
|
|
34
37
|
export class ServerAwsStsConfig {
|
|
38
|
+
AWS_PROFILE?: string;
|
|
35
39
|
AWS_REGION: string;
|
|
36
|
-
AWS_PROFILE?: string; // Optional AWS profile
|
|
37
40
|
}
|
|
38
41
|
```
|
|
39
42
|
|
|
43
|
+
Credentials come from [`@onivoro/server-aws-credential-providers`](../aws-credential-providers/): when `AWS_PROFILE` is set the named profile is used, otherwise the AWS SDK default credential chain applies.
|
|
44
|
+
|
|
45
|
+
The module provides and exports `StsService`, an `STSClient`, and `ServerAwsStsConfig`.
|
|
46
|
+
|
|
40
47
|
## Service
|
|
41
48
|
|
|
42
49
|
### StsService
|
|
@@ -61,20 +68,16 @@ export class AccountService {
|
|
|
61
68
|
|
|
62
69
|
## Available Method
|
|
63
70
|
|
|
64
|
-
-
|
|
71
|
+
- **`getAccountId(): Promise<string | undefined>`**: calls `GetCallerIdentityCommand` and returns `Account`.
|
|
65
72
|
|
|
66
73
|
## Direct Client Access
|
|
67
74
|
|
|
68
|
-
The service exposes the underlying
|
|
75
|
+
The service exposes the underlying client as the public `stsClient` property (you can also inject `STSClient` directly):
|
|
69
76
|
|
|
70
77
|
```typescript
|
|
71
78
|
import { Injectable } from '@nestjs/common';
|
|
72
79
|
import { StsService } from '@onivoro/server-aws-sts';
|
|
73
|
-
import {
|
|
74
|
-
AssumeRoleCommand,
|
|
75
|
-
GetSessionTokenCommand,
|
|
76
|
-
GetAccessKeyInfoCommand
|
|
77
|
-
} from '@aws-sdk/client-sts';
|
|
80
|
+
import { AssumeRoleCommand, GetSessionTokenCommand, GetAccessKeyInfoCommand, GetCallerIdentityCommand } from '@aws-sdk/client-sts';
|
|
78
81
|
|
|
79
82
|
@Injectable()
|
|
80
83
|
export class AdvancedStsService {
|
|
@@ -85,9 +88,9 @@ export class AdvancedStsService {
|
|
|
85
88
|
const command = new AssumeRoleCommand({
|
|
86
89
|
RoleArn: roleArn,
|
|
87
90
|
RoleSessionName: sessionName,
|
|
88
|
-
DurationSeconds: 3600 // 1 hour
|
|
91
|
+
DurationSeconds: 3600, // 1 hour
|
|
89
92
|
});
|
|
90
|
-
|
|
93
|
+
|
|
91
94
|
const response = await this.stsService.stsClient.send(command);
|
|
92
95
|
return response.Credentials;
|
|
93
96
|
}
|
|
@@ -95,9 +98,9 @@ export class AdvancedStsService {
|
|
|
95
98
|
// Get temporary session token
|
|
96
99
|
async getSessionToken(durationSeconds: number = 3600) {
|
|
97
100
|
const command = new GetSessionTokenCommand({
|
|
98
|
-
DurationSeconds: durationSeconds
|
|
101
|
+
DurationSeconds: durationSeconds,
|
|
99
102
|
});
|
|
100
|
-
|
|
103
|
+
|
|
101
104
|
const response = await this.stsService.stsClient.send(command);
|
|
102
105
|
return response.Credentials;
|
|
103
106
|
}
|
|
@@ -105,9 +108,9 @@ export class AdvancedStsService {
|
|
|
105
108
|
// Get access key info
|
|
106
109
|
async getAccessKeyInfo(accessKeyId: string) {
|
|
107
110
|
const command = new GetAccessKeyInfoCommand({
|
|
108
|
-
AccessKeyId: accessKeyId
|
|
111
|
+
AccessKeyId: accessKeyId,
|
|
109
112
|
});
|
|
110
|
-
|
|
113
|
+
|
|
111
114
|
return await this.stsService.stsClient.send(command);
|
|
112
115
|
}
|
|
113
116
|
|
|
@@ -115,120 +118,20 @@ export class AdvancedStsService {
|
|
|
115
118
|
async getCallerIdentity() {
|
|
116
119
|
const command = new GetCallerIdentityCommand({});
|
|
117
120
|
const response = await this.stsService.stsClient.send(command);
|
|
118
|
-
|
|
121
|
+
|
|
119
122
|
return {
|
|
120
123
|
accountId: response.Account,
|
|
121
124
|
arn: response.Arn,
|
|
122
|
-
userId: response.UserId
|
|
125
|
+
userId: response.UserId,
|
|
123
126
|
};
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
```
|
|
127
130
|
|
|
128
|
-
## Complete Example
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
import { Module, Injectable, Controller, Get, Post, Body } from '@nestjs/common';
|
|
132
|
-
import { ServerAwsStsModule, StsService } from '@onivoro/server-aws-sts';
|
|
133
|
-
import { AssumeRoleCommand } from '@aws-sdk/client-sts';
|
|
134
|
-
|
|
135
|
-
@Module({
|
|
136
|
-
imports: [ServerAwsStsModule.configure()],
|
|
137
|
-
controllers: [SecurityController],
|
|
138
|
-
providers: [SecurityService]
|
|
139
|
-
})
|
|
140
|
-
export class SecurityModule {}
|
|
141
|
-
|
|
142
|
-
@Injectable()
|
|
143
|
-
export class SecurityService {
|
|
144
|
-
constructor(private readonly stsService: StsService) {}
|
|
145
|
-
|
|
146
|
-
async getCrossAccountCredentials(targetAccountId: string, roleName: string) {
|
|
147
|
-
const currentAccountId = await this.stsService.getAccountId();
|
|
148
|
-
const roleArn = `arn:aws:iam::${targetAccountId}:role/${roleName}`;
|
|
149
|
-
const sessionName = `cross-account-${currentAccountId}-${Date.now()}`;
|
|
150
|
-
|
|
151
|
-
const command = new AssumeRoleCommand({
|
|
152
|
-
RoleArn: roleArn,
|
|
153
|
-
RoleSessionName: sessionName,
|
|
154
|
-
DurationSeconds: 3600,
|
|
155
|
-
ExternalId: process.env.EXTERNAL_ID // If required by trust policy
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const response = await this.stsService.stsClient.send(command);
|
|
160
|
-
return {
|
|
161
|
-
accessKeyId: response.Credentials.AccessKeyId,
|
|
162
|
-
secretAccessKey: response.Credentials.SecretAccessKey,
|
|
163
|
-
sessionToken: response.Credentials.SessionToken,
|
|
164
|
-
expiration: response.Credentials.Expiration
|
|
165
|
-
};
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.error('Failed to assume role:', error);
|
|
168
|
-
throw error;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async validateCurrentCredentials() {
|
|
173
|
-
try {
|
|
174
|
-
const accountId = await this.stsService.getAccountId();
|
|
175
|
-
return {
|
|
176
|
-
valid: true,
|
|
177
|
-
accountId
|
|
178
|
-
};
|
|
179
|
-
} catch (error) {
|
|
180
|
-
return {
|
|
181
|
-
valid: false,
|
|
182
|
-
error: error.message
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
@Controller('security')
|
|
189
|
-
export class SecurityController {
|
|
190
|
-
constructor(private readonly securityService: SecurityService) {}
|
|
191
|
-
|
|
192
|
-
@Get('account')
|
|
193
|
-
async getAccountInfo() {
|
|
194
|
-
const accountId = await this.securityService.stsService.getAccountId();
|
|
195
|
-
return { accountId };
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
@Get('validate')
|
|
199
|
-
async validateCredentials() {
|
|
200
|
-
return await this.securityService.validateCurrentCredentials();
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
@Post('assume-role')
|
|
204
|
-
async assumeRole(@Body() body: {
|
|
205
|
-
targetAccountId: string;
|
|
206
|
-
roleName: string;
|
|
207
|
-
}) {
|
|
208
|
-
return await this.securityService.getCrossAccountCredentials(
|
|
209
|
-
body.targetAccountId,
|
|
210
|
-
body.roleName
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## Environment Variables
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
# Required
|
|
220
|
-
AWS_REGION=us-east-1
|
|
221
|
-
|
|
222
|
-
# Optional
|
|
223
|
-
AWS_PROFILE=my-profile
|
|
224
|
-
|
|
225
|
-
# For cross-account access
|
|
226
|
-
EXTERNAL_ID=unique-external-id # If required by role trust policy
|
|
227
|
-
```
|
|
228
|
-
|
|
229
131
|
## Common Use Cases
|
|
230
132
|
|
|
231
133
|
### 1. Account Verification
|
|
134
|
+
|
|
232
135
|
```typescript
|
|
233
136
|
const accountId = await stsService.getAccountId();
|
|
234
137
|
if (accountId !== expectedAccountId) {
|
|
@@ -237,19 +140,23 @@ if (accountId !== expectedAccountId) {
|
|
|
237
140
|
```
|
|
238
141
|
|
|
239
142
|
### 2. Dynamic Resource ARN Construction
|
|
143
|
+
|
|
240
144
|
```typescript
|
|
241
145
|
const accountId = await stsService.getAccountId();
|
|
242
146
|
const bucketArn = `arn:aws:s3:::my-bucket-${accountId}`;
|
|
243
147
|
```
|
|
244
148
|
|
|
245
149
|
### 3. Cross-Account Access Setup
|
|
150
|
+
|
|
246
151
|
```typescript
|
|
152
|
+
import { AssumeRoleCommand } from '@aws-sdk/client-sts';
|
|
153
|
+
|
|
247
154
|
// Use the exposed stsClient for assume role operations
|
|
248
155
|
const assumeRoleCommand = new AssumeRoleCommand({
|
|
249
156
|
RoleArn: `arn:aws:iam::${targetAccount}:role/${roleName}`,
|
|
250
|
-
RoleSessionName: 'my-session'
|
|
157
|
+
RoleSessionName: 'my-session',
|
|
251
158
|
});
|
|
252
|
-
const
|
|
159
|
+
const { Credentials } = await stsService.stsClient.send(assumeRoleCommand);
|
|
253
160
|
```
|
|
254
161
|
|
|
255
162
|
## Limitations
|
|
@@ -269,4 +176,4 @@ const credentials = await stsService.stsClient.send(assumeRoleCommand);
|
|
|
269
176
|
|
|
270
177
|
## License
|
|
271
178
|
|
|
272
|
-
MIT
|
|
179
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onivoro/server-aws-sts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "25.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"url": "https://github.com/onivoro/monorepo.git"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@onivoro/server-aws-credential-providers": "
|
|
14
|
-
"@onivoro/server-common": "
|
|
13
|
+
"@onivoro/server-aws-credential-providers": "25.1.0",
|
|
14
|
+
"@onivoro/server-common": "25.1.0",
|
|
15
15
|
"tslib": "^2.3.0"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|