@friggframework/devtools 2.0.0-next.33 → 2.0.0-next.34
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/frigg-cli/deploy-command/index.js +6 -3
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +442 -411
- package/infrastructure/GENERATE-IAM-DOCS.md +91 -66
- package/infrastructure/frigg-deployment-iam-stack.yaml +22 -0
- package/infrastructure/iam-generator.js +210 -229
- package/infrastructure/serverless-template.js +412 -243
- package/package.json +6 -6
|
@@ -8,9 +8,12 @@ const { AWSDiscovery } = require('./aws-discovery');
|
|
|
8
8
|
* @returns {boolean} True if discovery should run
|
|
9
9
|
*/
|
|
10
10
|
const shouldRunDiscovery = (AppDefinition) => {
|
|
11
|
-
return
|
|
12
|
-
AppDefinition.
|
|
13
|
-
AppDefinition.
|
|
11
|
+
return (
|
|
12
|
+
AppDefinition.vpc?.enable === true ||
|
|
13
|
+
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption ===
|
|
14
|
+
true ||
|
|
15
|
+
AppDefinition.ssm?.enable === true
|
|
16
|
+
);
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
/**
|
|
@@ -32,7 +35,9 @@ const findNodeModulesPath = () => {
|
|
|
32
35
|
const potentialPath = path.join(currentDir, 'node_modules');
|
|
33
36
|
if (fs.existsSync(potentialPath)) {
|
|
34
37
|
nodeModulesPath = potentialPath;
|
|
35
|
-
console.log(
|
|
38
|
+
console.log(
|
|
39
|
+
`Found node_modules at: ${nodeModulesPath} (method 1)`
|
|
40
|
+
);
|
|
36
41
|
break;
|
|
37
42
|
}
|
|
38
43
|
// Move up one directory
|
|
@@ -49,10 +54,14 @@ const findNodeModulesPath = () => {
|
|
|
49
54
|
try {
|
|
50
55
|
// This requires child_process, so let's require it here
|
|
51
56
|
const { execSync } = require('node:child_process');
|
|
52
|
-
const npmRoot = execSync('npm root', {
|
|
57
|
+
const npmRoot = execSync('npm root', {
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
}).trim();
|
|
53
60
|
if (fs.existsSync(npmRoot)) {
|
|
54
61
|
nodeModulesPath = npmRoot;
|
|
55
|
-
console.log(
|
|
62
|
+
console.log(
|
|
63
|
+
`Found node_modules at: ${nodeModulesPath} (method 2)`
|
|
64
|
+
);
|
|
56
65
|
}
|
|
57
66
|
} catch (npmError) {
|
|
58
67
|
console.error('Error executing npm root:', npmError);
|
|
@@ -65,10 +74,15 @@ const findNodeModulesPath = () => {
|
|
|
65
74
|
for (let i = 0; i < 5; i++) {
|
|
66
75
|
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
67
76
|
if (fs.existsSync(packageJsonPath)) {
|
|
68
|
-
const potentialNodeModules = path.join(
|
|
77
|
+
const potentialNodeModules = path.join(
|
|
78
|
+
currentDir,
|
|
79
|
+
'node_modules'
|
|
80
|
+
);
|
|
69
81
|
if (fs.existsSync(potentialNodeModules)) {
|
|
70
82
|
nodeModulesPath = potentialNodeModules;
|
|
71
|
-
console.log(
|
|
83
|
+
console.log(
|
|
84
|
+
`Found node_modules at: ${nodeModulesPath} (method 3)`
|
|
85
|
+
);
|
|
72
86
|
break;
|
|
73
87
|
}
|
|
74
88
|
}
|
|
@@ -86,7 +100,9 @@ const findNodeModulesPath = () => {
|
|
|
86
100
|
return nodeModulesPath;
|
|
87
101
|
}
|
|
88
102
|
|
|
89
|
-
console.warn(
|
|
103
|
+
console.warn(
|
|
104
|
+
'Could not find node_modules path, falling back to default'
|
|
105
|
+
);
|
|
90
106
|
return path.resolve(process.cwd(), '../node_modules');
|
|
91
107
|
} catch (error) {
|
|
92
108
|
console.error('Error finding node_modules path:', error);
|
|
@@ -119,8 +135,13 @@ const modifyHandlerPaths = (functions) => {
|
|
|
119
135
|
if (functionDef?.handler?.includes('node_modules/')) {
|
|
120
136
|
// Replace node_modules/ with the actual path to node_modules/
|
|
121
137
|
const relativePath = path.relative(process.cwd(), nodeModulesPath);
|
|
122
|
-
functionDef.handler = functionDef.handler.replace(
|
|
123
|
-
|
|
138
|
+
functionDef.handler = functionDef.handler.replace(
|
|
139
|
+
'node_modules/',
|
|
140
|
+
`${relativePath}/`
|
|
141
|
+
);
|
|
142
|
+
console.log(
|
|
143
|
+
`Updated handler for ${functionName}: ${functionDef.handler}`
|
|
144
|
+
);
|
|
124
145
|
}
|
|
125
146
|
}
|
|
126
147
|
|
|
@@ -145,9 +166,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
145
166
|
EnableDnsHostnames: true,
|
|
146
167
|
EnableDnsSupport: true,
|
|
147
168
|
Tags: [
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
169
|
+
{
|
|
170
|
+
Key: 'Name',
|
|
171
|
+
Value: '${self:service}-${self:provider.stage}-vpc',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
151
175
|
},
|
|
152
176
|
|
|
153
177
|
// Internet Gateway
|
|
@@ -155,9 +179,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
155
179
|
Type: 'AWS::EC2::InternetGateway',
|
|
156
180
|
Properties: {
|
|
157
181
|
Tags: [
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
|
|
182
|
+
{
|
|
183
|
+
Key: 'Name',
|
|
184
|
+
Value: '${self:service}-${self:provider.stage}-igw',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
},
|
|
161
188
|
},
|
|
162
189
|
|
|
163
190
|
// Attach Internet Gateway to VPC
|
|
@@ -165,8 +192,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
165
192
|
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
166
193
|
Properties: {
|
|
167
194
|
VpcId: { Ref: 'FriggVPC' },
|
|
168
|
-
InternetGatewayId: { Ref: 'FriggInternetGateway' }
|
|
169
|
-
}
|
|
195
|
+
InternetGatewayId: { Ref: 'FriggInternetGateway' },
|
|
196
|
+
},
|
|
170
197
|
},
|
|
171
198
|
|
|
172
199
|
// Public Subnet for NAT Gateway
|
|
@@ -178,9 +205,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
178
205
|
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
179
206
|
MapPublicIpOnLaunch: true,
|
|
180
207
|
Tags: [
|
|
181
|
-
{
|
|
182
|
-
|
|
183
|
-
|
|
208
|
+
{
|
|
209
|
+
Key: 'Name',
|
|
210
|
+
Value: '${self:service}-${self:provider.stage}-public-subnet',
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
184
214
|
},
|
|
185
215
|
|
|
186
216
|
// Private Subnet 1 for Lambda
|
|
@@ -191,9 +221,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
191
221
|
CidrBlock: '10.0.2.0/24',
|
|
192
222
|
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
193
223
|
Tags: [
|
|
194
|
-
{
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
{
|
|
225
|
+
Key: 'Name',
|
|
226
|
+
Value: '${self:service}-${self:provider.stage}-private-subnet-1',
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
197
230
|
},
|
|
198
231
|
|
|
199
232
|
// Private Subnet 2 for Lambda (different AZ for redundancy)
|
|
@@ -204,9 +237,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
204
237
|
CidrBlock: '10.0.3.0/24',
|
|
205
238
|
AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
|
|
206
239
|
Tags: [
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
240
|
+
{
|
|
241
|
+
Key: 'Name',
|
|
242
|
+
Value: '${self:service}-${self:provider.stage}-private-subnet-2',
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
},
|
|
210
246
|
},
|
|
211
247
|
|
|
212
248
|
// Elastic IP for NAT Gateway
|
|
@@ -215,22 +251,30 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
215
251
|
Properties: {
|
|
216
252
|
Domain: 'vpc',
|
|
217
253
|
Tags: [
|
|
218
|
-
{
|
|
219
|
-
|
|
254
|
+
{
|
|
255
|
+
Key: 'Name',
|
|
256
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
220
259
|
},
|
|
221
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
260
|
+
DependsOn: 'FriggVPCGatewayAttachment',
|
|
222
261
|
},
|
|
223
262
|
|
|
224
263
|
// NAT Gateway for private subnet internet access
|
|
225
264
|
FriggNATGateway: {
|
|
226
265
|
Type: 'AWS::EC2::NatGateway',
|
|
227
266
|
Properties: {
|
|
228
|
-
AllocationId: {
|
|
267
|
+
AllocationId: {
|
|
268
|
+
'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'],
|
|
269
|
+
},
|
|
229
270
|
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
230
271
|
Tags: [
|
|
231
|
-
{
|
|
232
|
-
|
|
233
|
-
|
|
272
|
+
{
|
|
273
|
+
Key: 'Name',
|
|
274
|
+
Value: '${self:service}-${self:provider.stage}-nat-gateway',
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
},
|
|
234
278
|
},
|
|
235
279
|
|
|
236
280
|
// Public Route Table
|
|
@@ -239,9 +283,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
239
283
|
Properties: {
|
|
240
284
|
VpcId: { Ref: 'FriggVPC' },
|
|
241
285
|
Tags: [
|
|
242
|
-
{
|
|
243
|
-
|
|
244
|
-
|
|
286
|
+
{
|
|
287
|
+
Key: 'Name',
|
|
288
|
+
Value: '${self:service}-${self:provider.stage}-public-rt',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
245
292
|
},
|
|
246
293
|
|
|
247
294
|
// Public Route to Internet Gateway
|
|
@@ -250,9 +297,9 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
250
297
|
Properties: {
|
|
251
298
|
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
252
299
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
253
|
-
GatewayId: { Ref: 'FriggInternetGateway' }
|
|
300
|
+
GatewayId: { Ref: 'FriggInternetGateway' },
|
|
254
301
|
},
|
|
255
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
302
|
+
DependsOn: 'FriggVPCGatewayAttachment',
|
|
256
303
|
},
|
|
257
304
|
|
|
258
305
|
// Associate Public Subnet with Public Route Table
|
|
@@ -260,8 +307,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
260
307
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
261
308
|
Properties: {
|
|
262
309
|
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
263
|
-
RouteTableId: { Ref: 'FriggPublicRouteTable' }
|
|
264
|
-
}
|
|
310
|
+
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
311
|
+
},
|
|
265
312
|
},
|
|
266
313
|
|
|
267
314
|
// Private Route Table
|
|
@@ -270,9 +317,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
270
317
|
Properties: {
|
|
271
318
|
VpcId: { Ref: 'FriggVPC' },
|
|
272
319
|
Tags: [
|
|
273
|
-
{
|
|
274
|
-
|
|
275
|
-
|
|
320
|
+
{
|
|
321
|
+
Key: 'Name',
|
|
322
|
+
Value: '${self:service}-${self:provider.stage}-private-rt',
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
},
|
|
276
326
|
},
|
|
277
327
|
|
|
278
328
|
// Private Route to NAT Gateway
|
|
@@ -281,8 +331,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
281
331
|
Properties: {
|
|
282
332
|
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
283
333
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
284
|
-
NatGatewayId: { Ref: 'FriggNATGateway' }
|
|
285
|
-
}
|
|
334
|
+
NatGatewayId: { Ref: 'FriggNATGateway' },
|
|
335
|
+
},
|
|
286
336
|
},
|
|
287
337
|
|
|
288
338
|
// Associate Private Subnet 1 with Private Route Table
|
|
@@ -290,8 +340,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
290
340
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
291
341
|
Properties: {
|
|
292
342
|
SubnetId: { Ref: 'FriggPrivateSubnet1' },
|
|
293
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
294
|
-
}
|
|
343
|
+
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
344
|
+
},
|
|
295
345
|
},
|
|
296
346
|
|
|
297
347
|
// Associate Private Subnet 2 with Private Route Table
|
|
@@ -299,8 +349,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
299
349
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
300
350
|
Properties: {
|
|
301
351
|
SubnetId: { Ref: 'FriggPrivateSubnet2' },
|
|
302
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
303
|
-
}
|
|
352
|
+
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
353
|
+
},
|
|
304
354
|
},
|
|
305
355
|
|
|
306
356
|
// Security Group for Lambda functions
|
|
@@ -315,35 +365,38 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
315
365
|
FromPort: 443,
|
|
316
366
|
ToPort: 443,
|
|
317
367
|
CidrIp: '0.0.0.0/0',
|
|
318
|
-
Description: 'HTTPS outbound'
|
|
368
|
+
Description: 'HTTPS outbound',
|
|
319
369
|
},
|
|
320
370
|
{
|
|
321
371
|
IpProtocol: 'tcp',
|
|
322
372
|
FromPort: 80,
|
|
323
373
|
ToPort: 80,
|
|
324
374
|
CidrIp: '0.0.0.0/0',
|
|
325
|
-
Description: 'HTTP outbound'
|
|
375
|
+
Description: 'HTTP outbound',
|
|
326
376
|
},
|
|
327
377
|
{
|
|
328
378
|
IpProtocol: 'tcp',
|
|
329
379
|
FromPort: 53,
|
|
330
380
|
ToPort: 53,
|
|
331
381
|
CidrIp: '0.0.0.0/0',
|
|
332
|
-
Description: 'DNS TCP'
|
|
382
|
+
Description: 'DNS TCP',
|
|
333
383
|
},
|
|
334
384
|
{
|
|
335
385
|
IpProtocol: 'udp',
|
|
336
386
|
FromPort: 53,
|
|
337
387
|
ToPort: 53,
|
|
338
388
|
CidrIp: '0.0.0.0/0',
|
|
339
|
-
Description: 'DNS UDP'
|
|
340
|
-
}
|
|
389
|
+
Description: 'DNS UDP',
|
|
390
|
+
},
|
|
341
391
|
],
|
|
342
392
|
Tags: [
|
|
343
|
-
{
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
393
|
+
{
|
|
394
|
+
Key: 'Name',
|
|
395
|
+
Value: '${self:service}-${self:provider.stage}-lambda-sg',
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
},
|
|
399
|
+
},
|
|
347
400
|
};
|
|
348
401
|
|
|
349
402
|
// Add VPC Endpoints for cost optimization
|
|
@@ -355,10 +408,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
355
408
|
VpcId: { Ref: 'FriggVPC' },
|
|
356
409
|
ServiceName: 'com.amazonaws.${self:provider.region}.s3',
|
|
357
410
|
VpcEndpointType: 'Gateway',
|
|
358
|
-
RouteTableIds: [
|
|
359
|
-
|
|
360
|
-
]
|
|
361
|
-
}
|
|
411
|
+
RouteTableIds: [{ Ref: 'FriggPrivateRouteTable' }],
|
|
412
|
+
},
|
|
362
413
|
};
|
|
363
414
|
|
|
364
415
|
// DynamoDB Gateway Endpoint (free)
|
|
@@ -368,14 +419,15 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
368
419
|
VpcId: { Ref: 'FriggVPC' },
|
|
369
420
|
ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
|
|
370
421
|
VpcEndpointType: 'Gateway',
|
|
371
|
-
RouteTableIds: [
|
|
372
|
-
|
|
373
|
-
]
|
|
374
|
-
}
|
|
422
|
+
RouteTableIds: [{ Ref: 'FriggPrivateRouteTable' }],
|
|
423
|
+
},
|
|
375
424
|
};
|
|
376
425
|
|
|
377
426
|
// KMS Interface Endpoint (paid, but useful if using KMS)
|
|
378
|
-
if (
|
|
427
|
+
if (
|
|
428
|
+
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption ===
|
|
429
|
+
true
|
|
430
|
+
) {
|
|
379
431
|
vpcResources.FriggKMSVPCEndpoint = {
|
|
380
432
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
381
433
|
Properties: {
|
|
@@ -384,13 +436,13 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
384
436
|
VpcEndpointType: 'Interface',
|
|
385
437
|
SubnetIds: [
|
|
386
438
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
387
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
439
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
388
440
|
],
|
|
389
441
|
SecurityGroupIds: [
|
|
390
|
-
{ Ref: 'FriggVPCEndpointSecurityGroup' }
|
|
442
|
+
{ Ref: 'FriggVPCEndpointSecurityGroup' },
|
|
391
443
|
],
|
|
392
|
-
PrivateDnsEnabled: true
|
|
393
|
-
}
|
|
444
|
+
PrivateDnsEnabled: true,
|
|
445
|
+
},
|
|
394
446
|
};
|
|
395
447
|
}
|
|
396
448
|
|
|
@@ -399,17 +451,16 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
399
451
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
400
452
|
Properties: {
|
|
401
453
|
VpcId: { Ref: 'FriggVPC' },
|
|
402
|
-
ServiceName:
|
|
454
|
+
ServiceName:
|
|
455
|
+
'com.amazonaws.${self:provider.region}.secretsmanager',
|
|
403
456
|
VpcEndpointType: 'Interface',
|
|
404
457
|
SubnetIds: [
|
|
405
458
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
406
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
407
|
-
],
|
|
408
|
-
SecurityGroupIds: [
|
|
409
|
-
{ Ref: 'FriggVPCEndpointSecurityGroup' }
|
|
459
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
410
460
|
],
|
|
411
|
-
|
|
412
|
-
|
|
461
|
+
SecurityGroupIds: [{ Ref: 'FriggVPCEndpointSecurityGroup' }],
|
|
462
|
+
PrivateDnsEnabled: true,
|
|
463
|
+
},
|
|
413
464
|
};
|
|
414
465
|
|
|
415
466
|
// Security Group for VPC Endpoints
|
|
@@ -423,14 +474,19 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
423
474
|
IpProtocol: 'tcp',
|
|
424
475
|
FromPort: 443,
|
|
425
476
|
ToPort: 443,
|
|
426
|
-
SourceSecurityGroupId: {
|
|
427
|
-
|
|
428
|
-
|
|
477
|
+
SourceSecurityGroupId: {
|
|
478
|
+
Ref: 'FriggLambdaSecurityGroup',
|
|
479
|
+
},
|
|
480
|
+
Description: 'HTTPS from Lambda',
|
|
481
|
+
},
|
|
429
482
|
],
|
|
430
483
|
Tags: [
|
|
431
|
-
{
|
|
432
|
-
|
|
433
|
-
|
|
484
|
+
{
|
|
485
|
+
Key: 'Name',
|
|
486
|
+
Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg',
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
},
|
|
434
490
|
};
|
|
435
491
|
}
|
|
436
492
|
|
|
@@ -456,7 +512,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
456
512
|
|
|
457
513
|
// Run AWS discovery if needed
|
|
458
514
|
if (shouldRunDiscovery(AppDefinition)) {
|
|
459
|
-
console.log(
|
|
515
|
+
console.log(
|
|
516
|
+
'🔍 Running AWS resource discovery for serverless template...'
|
|
517
|
+
);
|
|
460
518
|
try {
|
|
461
519
|
const region = process.env.AWS_REGION || 'us-east-1';
|
|
462
520
|
const discovery = new AWSDiscovery(region);
|
|
@@ -464,7 +522,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
464
522
|
const config = {
|
|
465
523
|
vpc: AppDefinition.vpc || {},
|
|
466
524
|
encryption: AppDefinition.encryption || {},
|
|
467
|
-
ssm: AppDefinition.ssm || {}
|
|
525
|
+
ssm: AppDefinition.ssm || {},
|
|
468
526
|
};
|
|
469
527
|
|
|
470
528
|
discoveredResources = await discovery.discoverResources(config);
|
|
@@ -473,14 +531,23 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
473
531
|
if (discoveredResources.defaultVpcId) {
|
|
474
532
|
console.log(` VPC: ${discoveredResources.defaultVpcId}`);
|
|
475
533
|
}
|
|
476
|
-
if (
|
|
477
|
-
|
|
534
|
+
if (
|
|
535
|
+
discoveredResources.privateSubnetId1 &&
|
|
536
|
+
discoveredResources.privateSubnetId2
|
|
537
|
+
) {
|
|
538
|
+
console.log(
|
|
539
|
+
` Subnets: ${discoveredResources.privateSubnetId1}, ${discoveredResources.privateSubnetId2}`
|
|
540
|
+
);
|
|
478
541
|
}
|
|
479
542
|
if (discoveredResources.defaultSecurityGroupId) {
|
|
480
|
-
console.log(
|
|
543
|
+
console.log(
|
|
544
|
+
` Security Group: ${discoveredResources.defaultSecurityGroupId}`
|
|
545
|
+
);
|
|
481
546
|
}
|
|
482
547
|
if (discoveredResources.defaultKmsKeyId) {
|
|
483
|
-
console.log(
|
|
548
|
+
console.log(
|
|
549
|
+
` KMS Key: ${discoveredResources.defaultKmsKeyId}`
|
|
550
|
+
);
|
|
484
551
|
}
|
|
485
552
|
} catch (error) {
|
|
486
553
|
console.error('❌ AWS discovery failed:', error.message);
|
|
@@ -488,12 +555,24 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
488
555
|
}
|
|
489
556
|
}
|
|
490
557
|
|
|
558
|
+
// Debug: log keys of env vars available during deploy (to verify GA -> Serverless pass-through)
|
|
559
|
+
try {
|
|
560
|
+
const envKeys = Object.keys(process.env || {}).sort();
|
|
561
|
+
console.log('Frigg deploy env keys (sample):', envKeys.slice(0, 30), `... total=${envKeys.length}`);
|
|
562
|
+
} catch (e) {
|
|
563
|
+
console.log('Frigg deploy env keys: <unavailable>', e?.message);
|
|
564
|
+
}
|
|
565
|
+
|
|
491
566
|
const definition = {
|
|
492
567
|
frameworkVersion: '>=3.17.0',
|
|
493
568
|
service: AppDefinition.name || 'create-frigg-app',
|
|
494
569
|
package: {
|
|
495
570
|
individually: true,
|
|
496
|
-
exclude: [
|
|
571
|
+
exclude: [
|
|
572
|
+
'!**/node_modules/aws-sdk/**',
|
|
573
|
+
'!**/node_modules/@aws-sdk/**',
|
|
574
|
+
'!package.json',
|
|
575
|
+
],
|
|
497
576
|
},
|
|
498
577
|
useDotenv: true,
|
|
499
578
|
provider: {
|
|
@@ -505,14 +584,36 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
505
584
|
environment: {
|
|
506
585
|
STAGE: '${opt:stage, "dev"}',
|
|
507
586
|
AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1,
|
|
587
|
+
// Pass through all environment variables from the deployment process
|
|
588
|
+
...process.env,
|
|
508
589
|
// Add discovered resources to environment if available
|
|
509
|
-
...(discoveredResources.defaultVpcId && {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
...(discoveredResources.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
590
|
+
...(discoveredResources.defaultVpcId && {
|
|
591
|
+
AWS_DISCOVERY_VPC_ID: discoveredResources.defaultVpcId,
|
|
592
|
+
}),
|
|
593
|
+
...(discoveredResources.defaultSecurityGroupId && {
|
|
594
|
+
AWS_DISCOVERY_SECURITY_GROUP_ID:
|
|
595
|
+
discoveredResources.defaultSecurityGroupId,
|
|
596
|
+
}),
|
|
597
|
+
...(discoveredResources.privateSubnetId1 && {
|
|
598
|
+
AWS_DISCOVERY_SUBNET_ID_1:
|
|
599
|
+
discoveredResources.privateSubnetId1,
|
|
600
|
+
}),
|
|
601
|
+
...(discoveredResources.privateSubnetId2 && {
|
|
602
|
+
AWS_DISCOVERY_SUBNET_ID_2:
|
|
603
|
+
discoveredResources.privateSubnetId2,
|
|
604
|
+
}),
|
|
605
|
+
...(discoveredResources.publicSubnetId && {
|
|
606
|
+
AWS_DISCOVERY_PUBLIC_SUBNET_ID:
|
|
607
|
+
discoveredResources.publicSubnetId,
|
|
608
|
+
}),
|
|
609
|
+
...(discoveredResources.defaultRouteTableId && {
|
|
610
|
+
AWS_DISCOVERY_ROUTE_TABLE_ID:
|
|
611
|
+
discoveredResources.defaultRouteTableId,
|
|
612
|
+
}),
|
|
613
|
+
...(discoveredResources.defaultKmsKeyId && {
|
|
614
|
+
AWS_DISCOVERY_KMS_KEY_ID:
|
|
615
|
+
discoveredResources.defaultKmsKeyId,
|
|
616
|
+
}),
|
|
516
617
|
},
|
|
517
618
|
iamRoleStatements: [
|
|
518
619
|
{
|
|
@@ -528,22 +629,22 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
528
629
|
'sqs:SendMessage',
|
|
529
630
|
'sqs:SendMessageBatch',
|
|
530
631
|
'sqs:GetQueueUrl',
|
|
531
|
-
'sqs:GetQueueAttributes'
|
|
632
|
+
'sqs:GetQueueAttributes',
|
|
532
633
|
],
|
|
533
634
|
Resource: [
|
|
534
635
|
{
|
|
535
|
-
'Fn::GetAtt': ['InternalErrorQueue', 'Arn']
|
|
636
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
536
637
|
},
|
|
537
638
|
{
|
|
538
639
|
'Fn::Join': [
|
|
539
640
|
':',
|
|
540
641
|
[
|
|
541
|
-
'arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue'
|
|
542
|
-
]
|
|
543
|
-
]
|
|
544
|
-
}
|
|
642
|
+
'arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue',
|
|
643
|
+
],
|
|
644
|
+
],
|
|
645
|
+
},
|
|
545
646
|
],
|
|
546
|
-
}
|
|
647
|
+
},
|
|
547
648
|
],
|
|
548
649
|
httpApi: {
|
|
549
650
|
payload: '2.0',
|
|
@@ -555,7 +656,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
555
656
|
},
|
|
556
657
|
name: '${opt:stage, "dev"}-${self:service}',
|
|
557
658
|
disableDefaultEndpoint: false,
|
|
558
|
-
}
|
|
659
|
+
},
|
|
559
660
|
},
|
|
560
661
|
plugins: [
|
|
561
662
|
'serverless-jetpack',
|
|
@@ -585,7 +686,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
585
686
|
},
|
|
586
687
|
functions: {
|
|
587
688
|
auth: {
|
|
588
|
-
handler:
|
|
689
|
+
handler:
|
|
690
|
+
'node_modules/@friggframework/core/handlers/routers/auth.handler',
|
|
589
691
|
events: [
|
|
590
692
|
{
|
|
591
693
|
httpApi: {
|
|
@@ -608,7 +710,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
608
710
|
],
|
|
609
711
|
},
|
|
610
712
|
user: {
|
|
611
|
-
handler:
|
|
713
|
+
handler:
|
|
714
|
+
'node_modules/@friggframework/core/handlers/routers/user.handler',
|
|
612
715
|
events: [
|
|
613
716
|
{
|
|
614
717
|
httpApi: {
|
|
@@ -619,7 +722,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
619
722
|
],
|
|
620
723
|
},
|
|
621
724
|
health: {
|
|
622
|
-
handler:
|
|
725
|
+
handler:
|
|
726
|
+
'node_modules/@friggframework/core/handlers/routers/health.handler',
|
|
623
727
|
events: [
|
|
624
728
|
{
|
|
625
729
|
httpApi: {
|
|
@@ -723,23 +827,28 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
723
827
|
};
|
|
724
828
|
|
|
725
829
|
// KMS Configuration based on App Definition
|
|
726
|
-
if (
|
|
830
|
+
if (
|
|
831
|
+
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true
|
|
832
|
+
) {
|
|
727
833
|
// Check if a KMS key was discovered
|
|
728
834
|
if (discoveredResources.defaultKmsKeyId) {
|
|
729
835
|
// Use the existing discovered KMS key
|
|
730
|
-
console.log(
|
|
731
|
-
|
|
836
|
+
console.log(
|
|
837
|
+
`Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`
|
|
838
|
+
);
|
|
839
|
+
|
|
732
840
|
definition.provider.iamRoleStatements.push({
|
|
733
841
|
Effect: 'Allow',
|
|
734
842
|
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
735
|
-
Resource: [discoveredResources.defaultKmsKeyId]
|
|
843
|
+
Resource: [discoveredResources.defaultKmsKeyId],
|
|
736
844
|
});
|
|
737
845
|
|
|
738
|
-
definition.provider.environment.KMS_KEY_ARN =
|
|
846
|
+
definition.provider.environment.KMS_KEY_ARN =
|
|
847
|
+
discoveredResources.defaultKmsKeyId;
|
|
739
848
|
} else {
|
|
740
849
|
// No existing key found, provision a dedicated KMS key
|
|
741
850
|
console.log('No existing KMS key found, creating a new one...');
|
|
742
|
-
|
|
851
|
+
|
|
743
852
|
definition.resources.Resources.FriggKMSKey = {
|
|
744
853
|
Type: 'AWS::KMS::Key',
|
|
745
854
|
Properties: {
|
|
@@ -750,29 +859,38 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
750
859
|
{
|
|
751
860
|
Sid: 'AllowRootAccountAdmin',
|
|
752
861
|
Effect: 'Allow',
|
|
753
|
-
Principal: {
|
|
862
|
+
Principal: {
|
|
863
|
+
AWS: {
|
|
864
|
+
'Fn::Sub':
|
|
865
|
+
'arn:aws:iam::${AWS::AccountId}:root',
|
|
866
|
+
},
|
|
867
|
+
},
|
|
754
868
|
Action: 'kms:*',
|
|
755
|
-
Resource: '*'
|
|
756
|
-
}
|
|
757
|
-
]
|
|
758
|
-
}
|
|
759
|
-
}
|
|
869
|
+
Resource: '*',
|
|
870
|
+
},
|
|
871
|
+
],
|
|
872
|
+
},
|
|
873
|
+
},
|
|
760
874
|
};
|
|
761
875
|
|
|
762
876
|
definition.provider.iamRoleStatements.push({
|
|
763
877
|
Effect: 'Allow',
|
|
764
878
|
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
765
|
-
Resource: [{ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }]
|
|
879
|
+
Resource: [{ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }],
|
|
766
880
|
});
|
|
767
881
|
|
|
768
|
-
definition.provider.environment.KMS_KEY_ARN = {
|
|
882
|
+
definition.provider.environment.KMS_KEY_ARN = {
|
|
883
|
+
'Fn::GetAtt': ['FriggKMSKey', 'Arn'],
|
|
884
|
+
};
|
|
769
885
|
}
|
|
770
886
|
|
|
771
887
|
definition.plugins.push('serverless-kms-grants');
|
|
772
888
|
|
|
773
889
|
// Configure KMS grants with discovered default key or environment variable
|
|
774
890
|
definition.custom.kmsGrants = {
|
|
775
|
-
kmsKeyId:
|
|
891
|
+
kmsKeyId:
|
|
892
|
+
discoveredResources.defaultKmsKeyId ||
|
|
893
|
+
'${env:AWS_DISCOVERY_KMS_KEY_ID}',
|
|
776
894
|
};
|
|
777
895
|
}
|
|
778
896
|
|
|
@@ -786,9 +904,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
786
904
|
'ec2:DescribeNetworkInterfaces',
|
|
787
905
|
'ec2:DeleteNetworkInterface',
|
|
788
906
|
'ec2:AttachNetworkInterface',
|
|
789
|
-
'ec2:DetachNetworkInterface'
|
|
907
|
+
'ec2:DetachNetworkInterface',
|
|
790
908
|
],
|
|
791
|
-
Resource: '*'
|
|
909
|
+
Resource: '*',
|
|
792
910
|
});
|
|
793
911
|
|
|
794
912
|
// Default approach: Use AWS Discovery to find existing VPC resources
|
|
@@ -801,7 +919,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
801
919
|
vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds;
|
|
802
920
|
} else {
|
|
803
921
|
// Use auto-created security group
|
|
804
|
-
vpcConfig.securityGroupIds = [
|
|
922
|
+
vpcConfig.securityGroupIds = [
|
|
923
|
+
{ Ref: 'FriggLambdaSecurityGroup' },
|
|
924
|
+
];
|
|
805
925
|
}
|
|
806
926
|
|
|
807
927
|
if (AppDefinition.vpc.subnetIds) {
|
|
@@ -811,7 +931,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
811
931
|
// Use auto-created private subnets
|
|
812
932
|
vpcConfig.subnetIds = [
|
|
813
933
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
814
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
934
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
815
935
|
];
|
|
816
936
|
}
|
|
817
937
|
|
|
@@ -825,16 +945,27 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
825
945
|
// Option 2: Use AWS Discovery (default behavior)
|
|
826
946
|
// VPC configuration using discovered or explicitly provided resources
|
|
827
947
|
const vpcConfig = {
|
|
828
|
-
securityGroupIds:
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
[
|
|
833
|
-
|
|
948
|
+
securityGroupIds:
|
|
949
|
+
AppDefinition.vpc.securityGroupIds ||
|
|
950
|
+
(discoveredResources.defaultSecurityGroupId
|
|
951
|
+
? [discoveredResources.defaultSecurityGroupId]
|
|
952
|
+
: []),
|
|
953
|
+
subnetIds:
|
|
954
|
+
AppDefinition.vpc.subnetIds ||
|
|
955
|
+
(discoveredResources.privateSubnetId1 &&
|
|
956
|
+
discoveredResources.privateSubnetId2
|
|
957
|
+
? [
|
|
958
|
+
discoveredResources.privateSubnetId1,
|
|
959
|
+
discoveredResources.privateSubnetId2,
|
|
960
|
+
]
|
|
961
|
+
: []),
|
|
834
962
|
};
|
|
835
963
|
|
|
836
964
|
// Set VPC config for Lambda functions only if we have valid subnet IDs
|
|
837
|
-
if (
|
|
965
|
+
if (
|
|
966
|
+
vpcConfig.subnetIds.length >= 2 &&
|
|
967
|
+
vpcConfig.securityGroupIds.length > 0
|
|
968
|
+
) {
|
|
838
969
|
definition.provider.vpc = vpcConfig;
|
|
839
970
|
|
|
840
971
|
// Check if we have an existing NAT Gateway to use
|
|
@@ -848,22 +979,35 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
848
979
|
Properties: {
|
|
849
980
|
Domain: 'vpc',
|
|
850
981
|
Tags: [
|
|
851
|
-
{
|
|
852
|
-
|
|
853
|
-
|
|
982
|
+
{
|
|
983
|
+
Key: 'Name',
|
|
984
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
985
|
+
},
|
|
986
|
+
],
|
|
987
|
+
},
|
|
854
988
|
};
|
|
855
989
|
}
|
|
856
990
|
|
|
857
991
|
definition.resources.Resources.FriggNATGateway = {
|
|
858
992
|
Type: 'AWS::EC2::NatGateway',
|
|
859
993
|
Properties: {
|
|
860
|
-
AllocationId:
|
|
861
|
-
|
|
862
|
-
|
|
994
|
+
AllocationId:
|
|
995
|
+
discoveredResources.existingElasticIpAllocationId || {
|
|
996
|
+
'Fn::GetAtt': [
|
|
997
|
+
'FriggNATGatewayEIP',
|
|
998
|
+
'AllocationId',
|
|
999
|
+
],
|
|
1000
|
+
},
|
|
1001
|
+
SubnetId:
|
|
1002
|
+
discoveredResources.publicSubnetId ||
|
|
1003
|
+
discoveredResources.privateSubnetId1, // Use first discovered subnet if no public subnet found
|
|
863
1004
|
Tags: [
|
|
864
|
-
{
|
|
865
|
-
|
|
866
|
-
|
|
1005
|
+
{
|
|
1006
|
+
Key: 'Name',
|
|
1007
|
+
Value: '${self:service}-${self:provider.stage}-nat-gateway',
|
|
1008
|
+
},
|
|
1009
|
+
],
|
|
1010
|
+
},
|
|
867
1011
|
};
|
|
868
1012
|
}
|
|
869
1013
|
|
|
@@ -871,11 +1015,16 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
871
1015
|
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
872
1016
|
Type: 'AWS::EC2::RouteTable',
|
|
873
1017
|
Properties: {
|
|
874
|
-
VpcId: discoveredResources.defaultVpcId || {
|
|
1018
|
+
VpcId: discoveredResources.defaultVpcId || {
|
|
1019
|
+
Ref: 'FriggVPC',
|
|
1020
|
+
},
|
|
875
1021
|
Tags: [
|
|
876
|
-
{
|
|
877
|
-
|
|
878
|
-
|
|
1022
|
+
{
|
|
1023
|
+
Key: 'Name',
|
|
1024
|
+
Value: '${self:service}-${self:provider.stage}-lambda-rt',
|
|
1025
|
+
},
|
|
1026
|
+
],
|
|
1027
|
+
},
|
|
879
1028
|
};
|
|
880
1029
|
|
|
881
1030
|
definition.resources.Resources.FriggNATRoute = {
|
|
@@ -883,8 +1032,11 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
883
1032
|
Properties: {
|
|
884
1033
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
885
1034
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
886
|
-
NatGatewayId:
|
|
887
|
-
|
|
1035
|
+
NatGatewayId:
|
|
1036
|
+
discoveredResources.existingNatGatewayId || {
|
|
1037
|
+
Ref: 'FriggNATGateway',
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
888
1040
|
};
|
|
889
1041
|
|
|
890
1042
|
// Associate Lambda subnets with NAT Gateway route table
|
|
@@ -892,16 +1044,16 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
892
1044
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
893
1045
|
Properties: {
|
|
894
1046
|
SubnetId: vpcConfig.subnetIds[0],
|
|
895
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
896
|
-
}
|
|
1047
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1048
|
+
},
|
|
897
1049
|
};
|
|
898
1050
|
|
|
899
1051
|
definition.resources.Resources.FriggSubnet2RouteAssociation = {
|
|
900
1052
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
901
1053
|
Properties: {
|
|
902
1054
|
SubnetId: vpcConfig.subnetIds[1],
|
|
903
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
904
|
-
}
|
|
1055
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1056
|
+
},
|
|
905
1057
|
};
|
|
906
1058
|
|
|
907
1059
|
// Add VPC endpoints for AWS service optimization (optional but recommended)
|
|
@@ -910,116 +1062,130 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
910
1062
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
911
1063
|
Properties: {
|
|
912
1064
|
VpcId: discoveredResources.defaultVpcId,
|
|
913
|
-
ServiceName:
|
|
1065
|
+
ServiceName:
|
|
1066
|
+
'com.amazonaws.${self:provider.region}.s3',
|
|
914
1067
|
VpcEndpointType: 'Gateway',
|
|
915
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
916
|
-
}
|
|
1068
|
+
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
|
|
1069
|
+
},
|
|
917
1070
|
};
|
|
918
1071
|
|
|
919
1072
|
definition.resources.Resources.VPCEndpointDynamoDB = {
|
|
920
1073
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
921
1074
|
Properties: {
|
|
922
1075
|
VpcId: discoveredResources.defaultVpcId,
|
|
923
|
-
ServiceName:
|
|
1076
|
+
ServiceName:
|
|
1077
|
+
'com.amazonaws.${self:provider.region}.dynamodb',
|
|
924
1078
|
VpcEndpointType: 'Gateway',
|
|
925
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
926
|
-
}
|
|
1079
|
+
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
|
|
1080
|
+
},
|
|
927
1081
|
};
|
|
928
1082
|
}
|
|
929
1083
|
}
|
|
930
1084
|
}
|
|
931
1085
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1086
|
+
// SSM Parameter Store Configuration based on App Definition
|
|
1087
|
+
if (AppDefinition.ssm?.enable === true) {
|
|
1088
|
+
// Add AWS Parameters and Secrets Lambda Extension layer
|
|
1089
|
+
definition.provider.layers = [
|
|
1090
|
+
'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11',
|
|
1091
|
+
];
|
|
938
1092
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1093
|
+
// Add SSM IAM permissions
|
|
1094
|
+
definition.provider.iamRoleStatements.push({
|
|
1095
|
+
Effect: 'Allow',
|
|
1096
|
+
Action: [
|
|
1097
|
+
'ssm:GetParameter',
|
|
1098
|
+
'ssm:GetParameters',
|
|
1099
|
+
'ssm:GetParametersByPath',
|
|
1100
|
+
],
|
|
1101
|
+
Resource: [
|
|
1102
|
+
'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*',
|
|
1103
|
+
],
|
|
1104
|
+
});
|
|
951
1105
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1106
|
+
// Add environment variable for SSM parameter prefix
|
|
1107
|
+
definition.provider.environment.SSM_PARAMETER_PREFIX =
|
|
1108
|
+
'/${self:service}/${self:provider.stage}';
|
|
1109
|
+
}
|
|
955
1110
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1111
|
+
// Add integration-specific functions and resources
|
|
1112
|
+
if (
|
|
1113
|
+
AppDefinition.integrations &&
|
|
1114
|
+
Array.isArray(AppDefinition.integrations)
|
|
1115
|
+
) {
|
|
1116
|
+
for (const integration of AppDefinition.integrations) {
|
|
1117
|
+
if (
|
|
1118
|
+
!integration ||
|
|
1119
|
+
!integration.Definition ||
|
|
1120
|
+
!integration.Definition.name
|
|
1121
|
+
) {
|
|
1122
|
+
throw new Error(
|
|
1123
|
+
'Invalid integration: missing Definition or name'
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
const integrationName = integration.Definition.name;
|
|
963
1127
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1128
|
+
// Add function for the integration
|
|
1129
|
+
definition.functions[integrationName] = {
|
|
1130
|
+
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
|
|
1131
|
+
events: [
|
|
1132
|
+
{
|
|
1133
|
+
httpApi: {
|
|
1134
|
+
path: `/api/${integrationName}-integration/{proxy+}`,
|
|
1135
|
+
method: 'ANY',
|
|
1136
|
+
},
|
|
972
1137
|
},
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
};
|
|
1138
|
+
],
|
|
1139
|
+
};
|
|
976
1140
|
|
|
977
|
-
|
|
978
|
-
|
|
1141
|
+
// Add SQS Queue for the integration
|
|
1142
|
+
const queueReference = `${
|
|
1143
|
+
integrationName.charAt(0).toUpperCase() +
|
|
1144
|
+
integrationName.slice(1)
|
|
979
1145
|
}Queue`;
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1146
|
+
const queueName = `\${self:service}--\${self:provider.stage}-${queueReference}`;
|
|
1147
|
+
definition.resources.Resources[queueReference] = {
|
|
1148
|
+
Type: 'AWS::SQS::Queue',
|
|
1149
|
+
Properties: {
|
|
1150
|
+
QueueName: `\${self:custom.${queueReference}}`,
|
|
1151
|
+
MessageRetentionPeriod: 60,
|
|
1152
|
+
VisibilityTimeout: 1800, // 30 minutes
|
|
1153
|
+
RedrivePolicy: {
|
|
1154
|
+
maxReceiveCount: 1,
|
|
1155
|
+
deadLetterTargetArn: {
|
|
1156
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
1157
|
+
},
|
|
991
1158
|
},
|
|
992
1159
|
},
|
|
993
|
-
}
|
|
994
|
-
};
|
|
1160
|
+
};
|
|
995
1161
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1162
|
+
// Add Queue Worker for the integration
|
|
1163
|
+
const queueWorkerName = `${integrationName}QueueWorker`;
|
|
1164
|
+
definition.functions[queueWorkerName] = {
|
|
1165
|
+
handler: `node_modules/@friggframework/core/handlers/workers/integration-defined-workers.handlers.${integrationName}.queueWorker`,
|
|
1166
|
+
reservedConcurrency: 5,
|
|
1167
|
+
events: [
|
|
1168
|
+
{
|
|
1169
|
+
sqs: {
|
|
1170
|
+
arn: {
|
|
1171
|
+
'Fn::GetAtt': [queueReference, 'Arn'],
|
|
1172
|
+
},
|
|
1173
|
+
batchSize: 1,
|
|
1006
1174
|
},
|
|
1007
|
-
batchSize: 1,
|
|
1008
1175
|
},
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
};
|
|
1176
|
+
],
|
|
1177
|
+
timeout: 600,
|
|
1178
|
+
};
|
|
1013
1179
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1180
|
+
// Add Queue URL for the integration to the ENVironment variables
|
|
1181
|
+
definition.provider.environment = {
|
|
1182
|
+
...definition.provider.environment,
|
|
1183
|
+
[`${integrationName.toUpperCase()}_QUEUE_URL`]: {
|
|
1184
|
+
Ref: queueReference,
|
|
1185
|
+
},
|
|
1186
|
+
};
|
|
1021
1187
|
|
|
1022
|
-
|
|
1188
|
+
definition.custom[queueReference] = queueName;
|
|
1023
1189
|
}
|
|
1024
1190
|
}
|
|
1025
1191
|
|
|
@@ -1029,7 +1195,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1029
1195
|
// Add websocket function if enabled
|
|
1030
1196
|
if (AppDefinition.websockets?.enable === true) {
|
|
1031
1197
|
definition.functions.defaultWebsocket = {
|
|
1032
|
-
handler:
|
|
1198
|
+
handler:
|
|
1199
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1033
1200
|
events: [
|
|
1034
1201
|
{
|
|
1035
1202
|
websocket: {
|
|
@@ -1056,7 +1223,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1056
1223
|
// Add websocket function if enabled
|
|
1057
1224
|
if (AppDefinition.websockets?.enable === true) {
|
|
1058
1225
|
definition.functions.defaultWebsocket = {
|
|
1059
|
-
handler:
|
|
1226
|
+
handler:
|
|
1227
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1060
1228
|
events: [
|
|
1061
1229
|
{
|
|
1062
1230
|
websocket: {
|
|
@@ -1084,7 +1252,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1084
1252
|
// Add websocket function if enabled
|
|
1085
1253
|
if (AppDefinition.websockets?.enable === true) {
|
|
1086
1254
|
definition.functions.defaultWebsocket = {
|
|
1087
|
-
handler:
|
|
1255
|
+
handler:
|
|
1256
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1088
1257
|
events: [
|
|
1089
1258
|
{
|
|
1090
1259
|
websocket: {
|
|
@@ -1114,4 +1283,4 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1114
1283
|
return definition;
|
|
1115
1284
|
};
|
|
1116
1285
|
|
|
1117
|
-
module.exports = { composeServerlessDefinition };
|
|
1286
|
+
module.exports = { composeServerlessDefinition };
|