@friggframework/devtools 2.0.0--canary.414.891364b.0 → 2.0.0--canary.414.db76eeb.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/frigg-cli/deploy-command/index.js +2 -1
- 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 +214 -131
- package/infrastructure/serverless-template.js +418 -251
- 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
|
/**
|
|
@@ -20,7 +23,7 @@ const shouldRunDiscovery = (AppDefinition) => {
|
|
|
20
23
|
*/
|
|
21
24
|
const getAppEnvironmentVars = (AppDefinition) => {
|
|
22
25
|
const envVars = {};
|
|
23
|
-
|
|
26
|
+
|
|
24
27
|
// AWS Lambda reserved environment variables that cannot be set (from official AWS docs)
|
|
25
28
|
const reservedVars = new Set([
|
|
26
29
|
'_HANDLER',
|
|
@@ -37,14 +40,14 @@ const getAppEnvironmentVars = (AppDefinition) => {
|
|
|
37
40
|
'AWS_ACCESS_KEY',
|
|
38
41
|
'AWS_ACCESS_KEY_ID',
|
|
39
42
|
'AWS_SECRET_ACCESS_KEY',
|
|
40
|
-
'AWS_SESSION_TOKEN'
|
|
43
|
+
'AWS_SESSION_TOKEN',
|
|
41
44
|
]);
|
|
42
|
-
|
|
45
|
+
|
|
43
46
|
if (AppDefinition.environment) {
|
|
44
47
|
console.log('📋 Loading environment variables from appDefinition...');
|
|
45
48
|
const envKeys = [];
|
|
46
49
|
const skippedKeys = [];
|
|
47
|
-
|
|
50
|
+
|
|
48
51
|
for (const [key, value] of Object.entries(AppDefinition.environment)) {
|
|
49
52
|
if (value === true) {
|
|
50
53
|
if (reservedVars.has(key)) {
|
|
@@ -55,15 +58,23 @@ const getAppEnvironmentVars = (AppDefinition) => {
|
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
|
-
|
|
61
|
+
|
|
59
62
|
if (envKeys.length > 0) {
|
|
60
|
-
console.log(
|
|
63
|
+
console.log(
|
|
64
|
+
` Found ${
|
|
65
|
+
envKeys.length
|
|
66
|
+
} environment variables: ${envKeys.join(', ')}`
|
|
67
|
+
);
|
|
61
68
|
}
|
|
62
69
|
if (skippedKeys.length > 0) {
|
|
63
|
-
console.log(
|
|
70
|
+
console.log(
|
|
71
|
+
` ⚠️ Skipped ${
|
|
72
|
+
skippedKeys.length
|
|
73
|
+
} reserved AWS Lambda variables: ${skippedKeys.join(', ')}`
|
|
74
|
+
);
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
|
-
|
|
77
|
+
|
|
67
78
|
return envVars;
|
|
68
79
|
};
|
|
69
80
|
|
|
@@ -86,7 +97,9 @@ const findNodeModulesPath = () => {
|
|
|
86
97
|
const potentialPath = path.join(currentDir, 'node_modules');
|
|
87
98
|
if (fs.existsSync(potentialPath)) {
|
|
88
99
|
nodeModulesPath = potentialPath;
|
|
89
|
-
console.log(
|
|
100
|
+
console.log(
|
|
101
|
+
`Found node_modules at: ${nodeModulesPath} (method 1)`
|
|
102
|
+
);
|
|
90
103
|
break;
|
|
91
104
|
}
|
|
92
105
|
// Move up one directory
|
|
@@ -103,10 +116,14 @@ const findNodeModulesPath = () => {
|
|
|
103
116
|
try {
|
|
104
117
|
// This requires child_process, so let's require it here
|
|
105
118
|
const { execSync } = require('node:child_process');
|
|
106
|
-
const npmRoot = execSync('npm root', {
|
|
119
|
+
const npmRoot = execSync('npm root', {
|
|
120
|
+
encoding: 'utf8',
|
|
121
|
+
}).trim();
|
|
107
122
|
if (fs.existsSync(npmRoot)) {
|
|
108
123
|
nodeModulesPath = npmRoot;
|
|
109
|
-
console.log(
|
|
124
|
+
console.log(
|
|
125
|
+
`Found node_modules at: ${nodeModulesPath} (method 2)`
|
|
126
|
+
);
|
|
110
127
|
}
|
|
111
128
|
} catch (npmError) {
|
|
112
129
|
console.error('Error executing npm root:', npmError);
|
|
@@ -119,10 +136,15 @@ const findNodeModulesPath = () => {
|
|
|
119
136
|
for (let i = 0; i < 5; i++) {
|
|
120
137
|
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
121
138
|
if (fs.existsSync(packageJsonPath)) {
|
|
122
|
-
const potentialNodeModules = path.join(
|
|
139
|
+
const potentialNodeModules = path.join(
|
|
140
|
+
currentDir,
|
|
141
|
+
'node_modules'
|
|
142
|
+
);
|
|
123
143
|
if (fs.existsSync(potentialNodeModules)) {
|
|
124
144
|
nodeModulesPath = potentialNodeModules;
|
|
125
|
-
console.log(
|
|
145
|
+
console.log(
|
|
146
|
+
`Found node_modules at: ${nodeModulesPath} (method 3)`
|
|
147
|
+
);
|
|
126
148
|
break;
|
|
127
149
|
}
|
|
128
150
|
}
|
|
@@ -140,7 +162,9 @@ const findNodeModulesPath = () => {
|
|
|
140
162
|
return nodeModulesPath;
|
|
141
163
|
}
|
|
142
164
|
|
|
143
|
-
console.warn(
|
|
165
|
+
console.warn(
|
|
166
|
+
'Could not find node_modules path, falling back to default'
|
|
167
|
+
);
|
|
144
168
|
return path.resolve(process.cwd(), '../node_modules');
|
|
145
169
|
} catch (error) {
|
|
146
170
|
console.error('Error finding node_modules path:', error);
|
|
@@ -173,8 +197,13 @@ const modifyHandlerPaths = (functions) => {
|
|
|
173
197
|
if (functionDef?.handler?.includes('node_modules/')) {
|
|
174
198
|
// Replace node_modules/ with the actual path to node_modules/
|
|
175
199
|
const relativePath = path.relative(process.cwd(), nodeModulesPath);
|
|
176
|
-
functionDef.handler = functionDef.handler.replace(
|
|
177
|
-
|
|
200
|
+
functionDef.handler = functionDef.handler.replace(
|
|
201
|
+
'node_modules/',
|
|
202
|
+
`${relativePath}/`
|
|
203
|
+
);
|
|
204
|
+
console.log(
|
|
205
|
+
`Updated handler for ${functionName}: ${functionDef.handler}`
|
|
206
|
+
);
|
|
178
207
|
}
|
|
179
208
|
}
|
|
180
209
|
|
|
@@ -199,9 +228,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
199
228
|
EnableDnsHostnames: true,
|
|
200
229
|
EnableDnsSupport: true,
|
|
201
230
|
Tags: [
|
|
202
|
-
{
|
|
203
|
-
|
|
204
|
-
|
|
231
|
+
{
|
|
232
|
+
Key: 'Name',
|
|
233
|
+
Value: '${self:service}-${self:provider.stage}-vpc',
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
},
|
|
205
237
|
},
|
|
206
238
|
|
|
207
239
|
// Internet Gateway
|
|
@@ -209,9 +241,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
209
241
|
Type: 'AWS::EC2::InternetGateway',
|
|
210
242
|
Properties: {
|
|
211
243
|
Tags: [
|
|
212
|
-
{
|
|
213
|
-
|
|
214
|
-
|
|
244
|
+
{
|
|
245
|
+
Key: 'Name',
|
|
246
|
+
Value: '${self:service}-${self:provider.stage}-igw',
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
},
|
|
215
250
|
},
|
|
216
251
|
|
|
217
252
|
// Attach Internet Gateway to VPC
|
|
@@ -219,8 +254,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
219
254
|
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
220
255
|
Properties: {
|
|
221
256
|
VpcId: { Ref: 'FriggVPC' },
|
|
222
|
-
InternetGatewayId: { Ref: 'FriggInternetGateway' }
|
|
223
|
-
}
|
|
257
|
+
InternetGatewayId: { Ref: 'FriggInternetGateway' },
|
|
258
|
+
},
|
|
224
259
|
},
|
|
225
260
|
|
|
226
261
|
// Public Subnet for NAT Gateway
|
|
@@ -232,9 +267,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
232
267
|
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
233
268
|
MapPublicIpOnLaunch: true,
|
|
234
269
|
Tags: [
|
|
235
|
-
{
|
|
236
|
-
|
|
237
|
-
|
|
270
|
+
{
|
|
271
|
+
Key: 'Name',
|
|
272
|
+
Value: '${self:service}-${self:provider.stage}-public-subnet',
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
238
276
|
},
|
|
239
277
|
|
|
240
278
|
// Private Subnet 1 for Lambda
|
|
@@ -245,9 +283,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
245
283
|
CidrBlock: '10.0.2.0/24',
|
|
246
284
|
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
247
285
|
Tags: [
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
286
|
+
{
|
|
287
|
+
Key: 'Name',
|
|
288
|
+
Value: '${self:service}-${self:provider.stage}-private-subnet-1',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
251
292
|
},
|
|
252
293
|
|
|
253
294
|
// Private Subnet 2 for Lambda (different AZ for redundancy)
|
|
@@ -258,9 +299,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
258
299
|
CidrBlock: '10.0.3.0/24',
|
|
259
300
|
AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
|
|
260
301
|
Tags: [
|
|
261
|
-
{
|
|
262
|
-
|
|
263
|
-
|
|
302
|
+
{
|
|
303
|
+
Key: 'Name',
|
|
304
|
+
Value: '${self:service}-${self:provider.stage}-private-subnet-2',
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
},
|
|
264
308
|
},
|
|
265
309
|
|
|
266
310
|
// Elastic IP for NAT Gateway
|
|
@@ -269,22 +313,30 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
269
313
|
Properties: {
|
|
270
314
|
Domain: 'vpc',
|
|
271
315
|
Tags: [
|
|
272
|
-
{
|
|
273
|
-
|
|
316
|
+
{
|
|
317
|
+
Key: 'Name',
|
|
318
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
319
|
+
},
|
|
320
|
+
],
|
|
274
321
|
},
|
|
275
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
322
|
+
DependsOn: 'FriggVPCGatewayAttachment',
|
|
276
323
|
},
|
|
277
324
|
|
|
278
325
|
// NAT Gateway for private subnet internet access
|
|
279
326
|
FriggNATGateway: {
|
|
280
327
|
Type: 'AWS::EC2::NatGateway',
|
|
281
328
|
Properties: {
|
|
282
|
-
AllocationId: {
|
|
329
|
+
AllocationId: {
|
|
330
|
+
'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'],
|
|
331
|
+
},
|
|
283
332
|
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
284
333
|
Tags: [
|
|
285
|
-
{
|
|
286
|
-
|
|
287
|
-
|
|
334
|
+
{
|
|
335
|
+
Key: 'Name',
|
|
336
|
+
Value: '${self:service}-${self:provider.stage}-nat-gateway',
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
},
|
|
288
340
|
},
|
|
289
341
|
|
|
290
342
|
// Public Route Table
|
|
@@ -293,9 +345,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
293
345
|
Properties: {
|
|
294
346
|
VpcId: { Ref: 'FriggVPC' },
|
|
295
347
|
Tags: [
|
|
296
|
-
{
|
|
297
|
-
|
|
298
|
-
|
|
348
|
+
{
|
|
349
|
+
Key: 'Name',
|
|
350
|
+
Value: '${self:service}-${self:provider.stage}-public-rt',
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
},
|
|
299
354
|
},
|
|
300
355
|
|
|
301
356
|
// Public Route to Internet Gateway
|
|
@@ -304,9 +359,9 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
304
359
|
Properties: {
|
|
305
360
|
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
306
361
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
307
|
-
GatewayId: { Ref: 'FriggInternetGateway' }
|
|
362
|
+
GatewayId: { Ref: 'FriggInternetGateway' },
|
|
308
363
|
},
|
|
309
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
364
|
+
DependsOn: 'FriggVPCGatewayAttachment',
|
|
310
365
|
},
|
|
311
366
|
|
|
312
367
|
// Associate Public Subnet with Public Route Table
|
|
@@ -314,8 +369,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
314
369
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
315
370
|
Properties: {
|
|
316
371
|
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
317
|
-
RouteTableId: { Ref: 'FriggPublicRouteTable' }
|
|
318
|
-
}
|
|
372
|
+
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
373
|
+
},
|
|
319
374
|
},
|
|
320
375
|
|
|
321
376
|
// Private Route Table
|
|
@@ -324,9 +379,12 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
324
379
|
Properties: {
|
|
325
380
|
VpcId: { Ref: 'FriggVPC' },
|
|
326
381
|
Tags: [
|
|
327
|
-
{
|
|
328
|
-
|
|
329
|
-
|
|
382
|
+
{
|
|
383
|
+
Key: 'Name',
|
|
384
|
+
Value: '${self:service}-${self:provider.stage}-private-rt',
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
},
|
|
330
388
|
},
|
|
331
389
|
|
|
332
390
|
// Private Route to NAT Gateway
|
|
@@ -335,8 +393,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
335
393
|
Properties: {
|
|
336
394
|
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
337
395
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
338
|
-
NatGatewayId: { Ref: 'FriggNATGateway' }
|
|
339
|
-
}
|
|
396
|
+
NatGatewayId: { Ref: 'FriggNATGateway' },
|
|
397
|
+
},
|
|
340
398
|
},
|
|
341
399
|
|
|
342
400
|
// Associate Private Subnet 1 with Private Route Table
|
|
@@ -344,8 +402,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
344
402
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
345
403
|
Properties: {
|
|
346
404
|
SubnetId: { Ref: 'FriggPrivateSubnet1' },
|
|
347
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
348
|
-
}
|
|
405
|
+
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
406
|
+
},
|
|
349
407
|
},
|
|
350
408
|
|
|
351
409
|
// Associate Private Subnet 2 with Private Route Table
|
|
@@ -353,8 +411,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
353
411
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
354
412
|
Properties: {
|
|
355
413
|
SubnetId: { Ref: 'FriggPrivateSubnet2' },
|
|
356
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
357
|
-
}
|
|
414
|
+
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
415
|
+
},
|
|
358
416
|
},
|
|
359
417
|
|
|
360
418
|
// Security Group for Lambda functions
|
|
@@ -369,35 +427,38 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
369
427
|
FromPort: 443,
|
|
370
428
|
ToPort: 443,
|
|
371
429
|
CidrIp: '0.0.0.0/0',
|
|
372
|
-
Description: 'HTTPS outbound'
|
|
430
|
+
Description: 'HTTPS outbound',
|
|
373
431
|
},
|
|
374
432
|
{
|
|
375
433
|
IpProtocol: 'tcp',
|
|
376
434
|
FromPort: 80,
|
|
377
435
|
ToPort: 80,
|
|
378
436
|
CidrIp: '0.0.0.0/0',
|
|
379
|
-
Description: 'HTTP outbound'
|
|
437
|
+
Description: 'HTTP outbound',
|
|
380
438
|
},
|
|
381
439
|
{
|
|
382
440
|
IpProtocol: 'tcp',
|
|
383
441
|
FromPort: 53,
|
|
384
442
|
ToPort: 53,
|
|
385
443
|
CidrIp: '0.0.0.0/0',
|
|
386
|
-
Description: 'DNS TCP'
|
|
444
|
+
Description: 'DNS TCP',
|
|
387
445
|
},
|
|
388
446
|
{
|
|
389
447
|
IpProtocol: 'udp',
|
|
390
448
|
FromPort: 53,
|
|
391
449
|
ToPort: 53,
|
|
392
450
|
CidrIp: '0.0.0.0/0',
|
|
393
|
-
Description: 'DNS UDP'
|
|
394
|
-
}
|
|
451
|
+
Description: 'DNS UDP',
|
|
452
|
+
},
|
|
395
453
|
],
|
|
396
454
|
Tags: [
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
455
|
+
{
|
|
456
|
+
Key: 'Name',
|
|
457
|
+
Value: '${self:service}-${self:provider.stage}-lambda-sg',
|
|
458
|
+
},
|
|
459
|
+
],
|
|
460
|
+
},
|
|
461
|
+
},
|
|
401
462
|
};
|
|
402
463
|
|
|
403
464
|
// Add VPC Endpoints for cost optimization
|
|
@@ -409,10 +470,8 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
409
470
|
VpcId: { Ref: 'FriggVPC' },
|
|
410
471
|
ServiceName: 'com.amazonaws.${self:provider.region}.s3',
|
|
411
472
|
VpcEndpointType: 'Gateway',
|
|
412
|
-
RouteTableIds: [
|
|
413
|
-
|
|
414
|
-
]
|
|
415
|
-
}
|
|
473
|
+
RouteTableIds: [{ Ref: 'FriggPrivateRouteTable' }],
|
|
474
|
+
},
|
|
416
475
|
};
|
|
417
476
|
|
|
418
477
|
// DynamoDB Gateway Endpoint (free)
|
|
@@ -422,14 +481,15 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
422
481
|
VpcId: { Ref: 'FriggVPC' },
|
|
423
482
|
ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
|
|
424
483
|
VpcEndpointType: 'Gateway',
|
|
425
|
-
RouteTableIds: [
|
|
426
|
-
|
|
427
|
-
]
|
|
428
|
-
}
|
|
484
|
+
RouteTableIds: [{ Ref: 'FriggPrivateRouteTable' }],
|
|
485
|
+
},
|
|
429
486
|
};
|
|
430
487
|
|
|
431
488
|
// KMS Interface Endpoint (paid, but useful if using KMS)
|
|
432
|
-
if (
|
|
489
|
+
if (
|
|
490
|
+
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption ===
|
|
491
|
+
true
|
|
492
|
+
) {
|
|
433
493
|
vpcResources.FriggKMSVPCEndpoint = {
|
|
434
494
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
435
495
|
Properties: {
|
|
@@ -438,13 +498,13 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
438
498
|
VpcEndpointType: 'Interface',
|
|
439
499
|
SubnetIds: [
|
|
440
500
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
441
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
501
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
442
502
|
],
|
|
443
503
|
SecurityGroupIds: [
|
|
444
|
-
{ Ref: 'FriggVPCEndpointSecurityGroup' }
|
|
504
|
+
{ Ref: 'FriggVPCEndpointSecurityGroup' },
|
|
445
505
|
],
|
|
446
|
-
PrivateDnsEnabled: true
|
|
447
|
-
}
|
|
506
|
+
PrivateDnsEnabled: true,
|
|
507
|
+
},
|
|
448
508
|
};
|
|
449
509
|
}
|
|
450
510
|
|
|
@@ -453,17 +513,16 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
453
513
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
454
514
|
Properties: {
|
|
455
515
|
VpcId: { Ref: 'FriggVPC' },
|
|
456
|
-
ServiceName:
|
|
516
|
+
ServiceName:
|
|
517
|
+
'com.amazonaws.${self:provider.region}.secretsmanager',
|
|
457
518
|
VpcEndpointType: 'Interface',
|
|
458
519
|
SubnetIds: [
|
|
459
520
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
460
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
521
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
461
522
|
],
|
|
462
|
-
SecurityGroupIds: [
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
PrivateDnsEnabled: true
|
|
466
|
-
}
|
|
523
|
+
SecurityGroupIds: [{ Ref: 'FriggVPCEndpointSecurityGroup' }],
|
|
524
|
+
PrivateDnsEnabled: true,
|
|
525
|
+
},
|
|
467
526
|
};
|
|
468
527
|
|
|
469
528
|
// Security Group for VPC Endpoints
|
|
@@ -477,14 +536,19 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
477
536
|
IpProtocol: 'tcp',
|
|
478
537
|
FromPort: 443,
|
|
479
538
|
ToPort: 443,
|
|
480
|
-
SourceSecurityGroupId: {
|
|
481
|
-
|
|
482
|
-
|
|
539
|
+
SourceSecurityGroupId: {
|
|
540
|
+
Ref: 'FriggLambdaSecurityGroup',
|
|
541
|
+
},
|
|
542
|
+
Description: 'HTTPS from Lambda',
|
|
543
|
+
},
|
|
483
544
|
],
|
|
484
545
|
Tags: [
|
|
485
|
-
{
|
|
486
|
-
|
|
487
|
-
|
|
546
|
+
{
|
|
547
|
+
Key: 'Name',
|
|
548
|
+
Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg',
|
|
549
|
+
},
|
|
550
|
+
],
|
|
551
|
+
},
|
|
488
552
|
};
|
|
489
553
|
}
|
|
490
554
|
|
|
@@ -510,7 +574,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
510
574
|
|
|
511
575
|
// Run AWS discovery if needed
|
|
512
576
|
if (shouldRunDiscovery(AppDefinition)) {
|
|
513
|
-
console.log(
|
|
577
|
+
console.log(
|
|
578
|
+
'🔍 Running AWS resource discovery for serverless template...'
|
|
579
|
+
);
|
|
514
580
|
try {
|
|
515
581
|
const region = process.env.AWS_REGION || 'us-east-1';
|
|
516
582
|
const discovery = new AWSDiscovery(region);
|
|
@@ -518,7 +584,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
518
584
|
const config = {
|
|
519
585
|
vpc: AppDefinition.vpc || {},
|
|
520
586
|
encryption: AppDefinition.encryption || {},
|
|
521
|
-
ssm: AppDefinition.ssm || {}
|
|
587
|
+
ssm: AppDefinition.ssm || {},
|
|
522
588
|
};
|
|
523
589
|
|
|
524
590
|
discoveredResources = await discovery.discoverResources(config);
|
|
@@ -527,14 +593,23 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
527
593
|
if (discoveredResources.defaultVpcId) {
|
|
528
594
|
console.log(` VPC: ${discoveredResources.defaultVpcId}`);
|
|
529
595
|
}
|
|
530
|
-
if (
|
|
531
|
-
|
|
596
|
+
if (
|
|
597
|
+
discoveredResources.privateSubnetId1 &&
|
|
598
|
+
discoveredResources.privateSubnetId2
|
|
599
|
+
) {
|
|
600
|
+
console.log(
|
|
601
|
+
` Subnets: ${discoveredResources.privateSubnetId1}, ${discoveredResources.privateSubnetId2}`
|
|
602
|
+
);
|
|
532
603
|
}
|
|
533
604
|
if (discoveredResources.defaultSecurityGroupId) {
|
|
534
|
-
console.log(
|
|
605
|
+
console.log(
|
|
606
|
+
` Security Group: ${discoveredResources.defaultSecurityGroupId}`
|
|
607
|
+
);
|
|
535
608
|
}
|
|
536
609
|
if (discoveredResources.defaultKmsKeyId) {
|
|
537
|
-
console.log(
|
|
610
|
+
console.log(
|
|
611
|
+
` KMS Key: ${discoveredResources.defaultKmsKeyId}`
|
|
612
|
+
);
|
|
538
613
|
}
|
|
539
614
|
} catch (error) {
|
|
540
615
|
console.error('❌ AWS discovery failed:', error.message);
|
|
@@ -544,13 +619,17 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
544
619
|
|
|
545
620
|
// Get environment variables from appDefinition
|
|
546
621
|
const appEnvironmentVars = getAppEnvironmentVars(AppDefinition);
|
|
547
|
-
|
|
622
|
+
|
|
548
623
|
const definition = {
|
|
549
624
|
frameworkVersion: '>=3.17.0',
|
|
550
625
|
service: AppDefinition.name || 'create-frigg-app',
|
|
551
626
|
package: {
|
|
552
627
|
individually: true,
|
|
553
|
-
exclude: [
|
|
628
|
+
exclude: [
|
|
629
|
+
'!**/node_modules/aws-sdk/**',
|
|
630
|
+
'!**/node_modules/@aws-sdk/**',
|
|
631
|
+
'!package.json',
|
|
632
|
+
],
|
|
554
633
|
},
|
|
555
634
|
useDotenv: true,
|
|
556
635
|
provider: {
|
|
@@ -565,13 +644,33 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
565
644
|
// Add environment variables from appDefinition
|
|
566
645
|
...appEnvironmentVars,
|
|
567
646
|
// Add discovered resources to environment if available
|
|
568
|
-
...(discoveredResources.defaultVpcId && {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
...(discoveredResources.
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
647
|
+
...(discoveredResources.defaultVpcId && {
|
|
648
|
+
AWS_DISCOVERY_VPC_ID: discoveredResources.defaultVpcId,
|
|
649
|
+
}),
|
|
650
|
+
...(discoveredResources.defaultSecurityGroupId && {
|
|
651
|
+
AWS_DISCOVERY_SECURITY_GROUP_ID:
|
|
652
|
+
discoveredResources.defaultSecurityGroupId,
|
|
653
|
+
}),
|
|
654
|
+
...(discoveredResources.privateSubnetId1 && {
|
|
655
|
+
AWS_DISCOVERY_SUBNET_ID_1:
|
|
656
|
+
discoveredResources.privateSubnetId1,
|
|
657
|
+
}),
|
|
658
|
+
...(discoveredResources.privateSubnetId2 && {
|
|
659
|
+
AWS_DISCOVERY_SUBNET_ID_2:
|
|
660
|
+
discoveredResources.privateSubnetId2,
|
|
661
|
+
}),
|
|
662
|
+
...(discoveredResources.publicSubnetId && {
|
|
663
|
+
AWS_DISCOVERY_PUBLIC_SUBNET_ID:
|
|
664
|
+
discoveredResources.publicSubnetId,
|
|
665
|
+
}),
|
|
666
|
+
...(discoveredResources.defaultRouteTableId && {
|
|
667
|
+
AWS_DISCOVERY_ROUTE_TABLE_ID:
|
|
668
|
+
discoveredResources.defaultRouteTableId,
|
|
669
|
+
}),
|
|
670
|
+
...(discoveredResources.defaultKmsKeyId && {
|
|
671
|
+
AWS_DISCOVERY_KMS_KEY_ID:
|
|
672
|
+
discoveredResources.defaultKmsKeyId,
|
|
673
|
+
}),
|
|
575
674
|
},
|
|
576
675
|
iamRoleStatements: [
|
|
577
676
|
{
|
|
@@ -587,22 +686,22 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
587
686
|
'sqs:SendMessage',
|
|
588
687
|
'sqs:SendMessageBatch',
|
|
589
688
|
'sqs:GetQueueUrl',
|
|
590
|
-
'sqs:GetQueueAttributes'
|
|
689
|
+
'sqs:GetQueueAttributes',
|
|
591
690
|
],
|
|
592
691
|
Resource: [
|
|
593
692
|
{
|
|
594
|
-
'Fn::GetAtt': ['InternalErrorQueue', 'Arn']
|
|
693
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
595
694
|
},
|
|
596
695
|
{
|
|
597
696
|
'Fn::Join': [
|
|
598
697
|
':',
|
|
599
698
|
[
|
|
600
|
-
'arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue'
|
|
601
|
-
]
|
|
602
|
-
]
|
|
603
|
-
}
|
|
699
|
+
'arn:aws:sqs:${self:provider.region}:*:${self:service}--${self:provider.stage}-*Queue',
|
|
700
|
+
],
|
|
701
|
+
],
|
|
702
|
+
},
|
|
604
703
|
],
|
|
605
|
-
}
|
|
704
|
+
},
|
|
606
705
|
],
|
|
607
706
|
httpApi: {
|
|
608
707
|
payload: '2.0',
|
|
@@ -614,7 +713,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
614
713
|
},
|
|
615
714
|
name: '${opt:stage, "dev"}-${self:service}',
|
|
616
715
|
disableDefaultEndpoint: false,
|
|
617
|
-
}
|
|
716
|
+
},
|
|
618
717
|
},
|
|
619
718
|
plugins: [
|
|
620
719
|
'serverless-jetpack',
|
|
@@ -644,7 +743,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
644
743
|
},
|
|
645
744
|
functions: {
|
|
646
745
|
auth: {
|
|
647
|
-
handler:
|
|
746
|
+
handler:
|
|
747
|
+
'node_modules/@friggframework/core/handlers/routers/auth.handler',
|
|
648
748
|
events: [
|
|
649
749
|
{
|
|
650
750
|
httpApi: {
|
|
@@ -667,7 +767,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
667
767
|
],
|
|
668
768
|
},
|
|
669
769
|
user: {
|
|
670
|
-
handler:
|
|
770
|
+
handler:
|
|
771
|
+
'node_modules/@friggframework/core/handlers/routers/user.handler',
|
|
671
772
|
events: [
|
|
672
773
|
{
|
|
673
774
|
httpApi: {
|
|
@@ -678,7 +779,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
678
779
|
],
|
|
679
780
|
},
|
|
680
781
|
health: {
|
|
681
|
-
handler:
|
|
782
|
+
handler:
|
|
783
|
+
'node_modules/@friggframework/core/handlers/routers/health.handler',
|
|
682
784
|
events: [
|
|
683
785
|
{
|
|
684
786
|
httpApi: {
|
|
@@ -782,23 +884,28 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
782
884
|
};
|
|
783
885
|
|
|
784
886
|
// KMS Configuration based on App Definition
|
|
785
|
-
if (
|
|
887
|
+
if (
|
|
888
|
+
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true
|
|
889
|
+
) {
|
|
786
890
|
// Check if a KMS key was discovered
|
|
787
891
|
if (discoveredResources.defaultKmsKeyId) {
|
|
788
892
|
// Use the existing discovered KMS key
|
|
789
|
-
console.log(
|
|
790
|
-
|
|
893
|
+
console.log(
|
|
894
|
+
`Using existing KMS key: ${discoveredResources.defaultKmsKeyId}`
|
|
895
|
+
);
|
|
896
|
+
|
|
791
897
|
definition.provider.iamRoleStatements.push({
|
|
792
898
|
Effect: 'Allow',
|
|
793
899
|
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
794
|
-
Resource: [discoveredResources.defaultKmsKeyId]
|
|
900
|
+
Resource: [discoveredResources.defaultKmsKeyId],
|
|
795
901
|
});
|
|
796
902
|
|
|
797
|
-
definition.provider.environment.KMS_KEY_ARN =
|
|
903
|
+
definition.provider.environment.KMS_KEY_ARN =
|
|
904
|
+
discoveredResources.defaultKmsKeyId;
|
|
798
905
|
} else {
|
|
799
906
|
// No existing key found, provision a dedicated KMS key
|
|
800
907
|
console.log('No existing KMS key found, creating a new one...');
|
|
801
|
-
|
|
908
|
+
|
|
802
909
|
definition.resources.Resources.FriggKMSKey = {
|
|
803
910
|
Type: 'AWS::KMS::Key',
|
|
804
911
|
Properties: {
|
|
@@ -809,29 +916,38 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
809
916
|
{
|
|
810
917
|
Sid: 'AllowRootAccountAdmin',
|
|
811
918
|
Effect: 'Allow',
|
|
812
|
-
Principal: {
|
|
919
|
+
Principal: {
|
|
920
|
+
AWS: {
|
|
921
|
+
'Fn::Sub':
|
|
922
|
+
'arn:aws:iam::${AWS::AccountId}:root',
|
|
923
|
+
},
|
|
924
|
+
},
|
|
813
925
|
Action: 'kms:*',
|
|
814
|
-
Resource: '*'
|
|
815
|
-
}
|
|
816
|
-
]
|
|
817
|
-
}
|
|
818
|
-
}
|
|
926
|
+
Resource: '*',
|
|
927
|
+
},
|
|
928
|
+
],
|
|
929
|
+
},
|
|
930
|
+
},
|
|
819
931
|
};
|
|
820
932
|
|
|
821
933
|
definition.provider.iamRoleStatements.push({
|
|
822
934
|
Effect: 'Allow',
|
|
823
935
|
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
824
|
-
Resource: [{ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }]
|
|
936
|
+
Resource: [{ 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }],
|
|
825
937
|
});
|
|
826
938
|
|
|
827
|
-
definition.provider.environment.KMS_KEY_ARN = {
|
|
939
|
+
definition.provider.environment.KMS_KEY_ARN = {
|
|
940
|
+
'Fn::GetAtt': ['FriggKMSKey', 'Arn'],
|
|
941
|
+
};
|
|
828
942
|
}
|
|
829
943
|
|
|
830
944
|
definition.plugins.push('serverless-kms-grants');
|
|
831
945
|
|
|
832
946
|
// Configure KMS grants with discovered default key or environment variable
|
|
833
947
|
definition.custom.kmsGrants = {
|
|
834
|
-
kmsKeyId:
|
|
948
|
+
kmsKeyId:
|
|
949
|
+
discoveredResources.defaultKmsKeyId ||
|
|
950
|
+
'${env:AWS_DISCOVERY_KMS_KEY_ID}',
|
|
835
951
|
};
|
|
836
952
|
}
|
|
837
953
|
|
|
@@ -845,9 +961,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
845
961
|
'ec2:DescribeNetworkInterfaces',
|
|
846
962
|
'ec2:DeleteNetworkInterface',
|
|
847
963
|
'ec2:AttachNetworkInterface',
|
|
848
|
-
'ec2:DetachNetworkInterface'
|
|
964
|
+
'ec2:DetachNetworkInterface',
|
|
849
965
|
],
|
|
850
|
-
Resource: '*'
|
|
966
|
+
Resource: '*',
|
|
851
967
|
});
|
|
852
968
|
|
|
853
969
|
// Default approach: Use AWS Discovery to find existing VPC resources
|
|
@@ -860,7 +976,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
860
976
|
vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds;
|
|
861
977
|
} else {
|
|
862
978
|
// Use auto-created security group
|
|
863
|
-
vpcConfig.securityGroupIds = [
|
|
979
|
+
vpcConfig.securityGroupIds = [
|
|
980
|
+
{ Ref: 'FriggLambdaSecurityGroup' },
|
|
981
|
+
];
|
|
864
982
|
}
|
|
865
983
|
|
|
866
984
|
if (AppDefinition.vpc.subnetIds) {
|
|
@@ -870,7 +988,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
870
988
|
// Use auto-created private subnets
|
|
871
989
|
vpcConfig.subnetIds = [
|
|
872
990
|
{ Ref: 'FriggPrivateSubnet1' },
|
|
873
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
991
|
+
{ Ref: 'FriggPrivateSubnet2' },
|
|
874
992
|
];
|
|
875
993
|
}
|
|
876
994
|
|
|
@@ -884,16 +1002,27 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
884
1002
|
// Option 2: Use AWS Discovery (default behavior)
|
|
885
1003
|
// VPC configuration using discovered or explicitly provided resources
|
|
886
1004
|
const vpcConfig = {
|
|
887
|
-
securityGroupIds:
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
[
|
|
892
|
-
|
|
1005
|
+
securityGroupIds:
|
|
1006
|
+
AppDefinition.vpc.securityGroupIds ||
|
|
1007
|
+
(discoveredResources.defaultSecurityGroupId
|
|
1008
|
+
? [discoveredResources.defaultSecurityGroupId]
|
|
1009
|
+
: []),
|
|
1010
|
+
subnetIds:
|
|
1011
|
+
AppDefinition.vpc.subnetIds ||
|
|
1012
|
+
(discoveredResources.privateSubnetId1 &&
|
|
1013
|
+
discoveredResources.privateSubnetId2
|
|
1014
|
+
? [
|
|
1015
|
+
discoveredResources.privateSubnetId1,
|
|
1016
|
+
discoveredResources.privateSubnetId2,
|
|
1017
|
+
]
|
|
1018
|
+
: []),
|
|
893
1019
|
};
|
|
894
1020
|
|
|
895
1021
|
// Set VPC config for Lambda functions only if we have valid subnet IDs
|
|
896
|
-
if (
|
|
1022
|
+
if (
|
|
1023
|
+
vpcConfig.subnetIds.length >= 2 &&
|
|
1024
|
+
vpcConfig.securityGroupIds.length > 0
|
|
1025
|
+
) {
|
|
897
1026
|
definition.provider.vpc = vpcConfig;
|
|
898
1027
|
|
|
899
1028
|
// Check if we have an existing NAT Gateway to use
|
|
@@ -907,22 +1036,35 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
907
1036
|
Properties: {
|
|
908
1037
|
Domain: 'vpc',
|
|
909
1038
|
Tags: [
|
|
910
|
-
{
|
|
911
|
-
|
|
912
|
-
|
|
1039
|
+
{
|
|
1040
|
+
Key: 'Name',
|
|
1041
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
1042
|
+
},
|
|
1043
|
+
],
|
|
1044
|
+
},
|
|
913
1045
|
};
|
|
914
1046
|
}
|
|
915
1047
|
|
|
916
1048
|
definition.resources.Resources.FriggNATGateway = {
|
|
917
1049
|
Type: 'AWS::EC2::NatGateway',
|
|
918
1050
|
Properties: {
|
|
919
|
-
AllocationId:
|
|
920
|
-
|
|
921
|
-
|
|
1051
|
+
AllocationId:
|
|
1052
|
+
discoveredResources.existingElasticIpAllocationId || {
|
|
1053
|
+
'Fn::GetAtt': [
|
|
1054
|
+
'FriggNATGatewayEIP',
|
|
1055
|
+
'AllocationId',
|
|
1056
|
+
],
|
|
1057
|
+
},
|
|
1058
|
+
SubnetId:
|
|
1059
|
+
discoveredResources.publicSubnetId ||
|
|
1060
|
+
discoveredResources.privateSubnetId1, // Use first discovered subnet if no public subnet found
|
|
922
1061
|
Tags: [
|
|
923
|
-
{
|
|
924
|
-
|
|
925
|
-
|
|
1062
|
+
{
|
|
1063
|
+
Key: 'Name',
|
|
1064
|
+
Value: '${self:service}-${self:provider.stage}-nat-gateway',
|
|
1065
|
+
},
|
|
1066
|
+
],
|
|
1067
|
+
},
|
|
926
1068
|
};
|
|
927
1069
|
}
|
|
928
1070
|
|
|
@@ -930,11 +1072,16 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
930
1072
|
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
931
1073
|
Type: 'AWS::EC2::RouteTable',
|
|
932
1074
|
Properties: {
|
|
933
|
-
VpcId: discoveredResources.defaultVpcId || {
|
|
1075
|
+
VpcId: discoveredResources.defaultVpcId || {
|
|
1076
|
+
Ref: 'FriggVPC',
|
|
1077
|
+
},
|
|
934
1078
|
Tags: [
|
|
935
|
-
{
|
|
936
|
-
|
|
937
|
-
|
|
1079
|
+
{
|
|
1080
|
+
Key: 'Name',
|
|
1081
|
+
Value: '${self:service}-${self:provider.stage}-lambda-rt',
|
|
1082
|
+
},
|
|
1083
|
+
],
|
|
1084
|
+
},
|
|
938
1085
|
};
|
|
939
1086
|
|
|
940
1087
|
definition.resources.Resources.FriggNATRoute = {
|
|
@@ -942,8 +1089,11 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
942
1089
|
Properties: {
|
|
943
1090
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
944
1091
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
945
|
-
NatGatewayId:
|
|
946
|
-
|
|
1092
|
+
NatGatewayId:
|
|
1093
|
+
discoveredResources.existingNatGatewayId || {
|
|
1094
|
+
Ref: 'FriggNATGateway',
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
947
1097
|
};
|
|
948
1098
|
|
|
949
1099
|
// Associate Lambda subnets with NAT Gateway route table
|
|
@@ -951,16 +1101,16 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
951
1101
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
952
1102
|
Properties: {
|
|
953
1103
|
SubnetId: vpcConfig.subnetIds[0],
|
|
954
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
955
|
-
}
|
|
1104
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1105
|
+
},
|
|
956
1106
|
};
|
|
957
1107
|
|
|
958
1108
|
definition.resources.Resources.FriggSubnet2RouteAssociation = {
|
|
959
1109
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
960
1110
|
Properties: {
|
|
961
1111
|
SubnetId: vpcConfig.subnetIds[1],
|
|
962
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
963
|
-
}
|
|
1112
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1113
|
+
},
|
|
964
1114
|
};
|
|
965
1115
|
|
|
966
1116
|
// Add VPC endpoints for AWS service optimization (optional but recommended)
|
|
@@ -969,116 +1119,130 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
969
1119
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
970
1120
|
Properties: {
|
|
971
1121
|
VpcId: discoveredResources.defaultVpcId,
|
|
972
|
-
ServiceName:
|
|
1122
|
+
ServiceName:
|
|
1123
|
+
'com.amazonaws.${self:provider.region}.s3',
|
|
973
1124
|
VpcEndpointType: 'Gateway',
|
|
974
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
975
|
-
}
|
|
1125
|
+
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
|
|
1126
|
+
},
|
|
976
1127
|
};
|
|
977
1128
|
|
|
978
1129
|
definition.resources.Resources.VPCEndpointDynamoDB = {
|
|
979
1130
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
980
1131
|
Properties: {
|
|
981
1132
|
VpcId: discoveredResources.defaultVpcId,
|
|
982
|
-
ServiceName:
|
|
1133
|
+
ServiceName:
|
|
1134
|
+
'com.amazonaws.${self:provider.region}.dynamodb',
|
|
983
1135
|
VpcEndpointType: 'Gateway',
|
|
984
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
985
|
-
}
|
|
1136
|
+
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }],
|
|
1137
|
+
},
|
|
986
1138
|
};
|
|
987
1139
|
}
|
|
988
1140
|
}
|
|
989
1141
|
}
|
|
990
1142
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1143
|
+
// SSM Parameter Store Configuration based on App Definition
|
|
1144
|
+
if (AppDefinition.ssm?.enable === true) {
|
|
1145
|
+
// Add AWS Parameters and Secrets Lambda Extension layer
|
|
1146
|
+
definition.provider.layers = [
|
|
1147
|
+
'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11',
|
|
1148
|
+
];
|
|
997
1149
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1150
|
+
// Add SSM IAM permissions
|
|
1151
|
+
definition.provider.iamRoleStatements.push({
|
|
1152
|
+
Effect: 'Allow',
|
|
1153
|
+
Action: [
|
|
1154
|
+
'ssm:GetParameter',
|
|
1155
|
+
'ssm:GetParameters',
|
|
1156
|
+
'ssm:GetParametersByPath',
|
|
1157
|
+
],
|
|
1158
|
+
Resource: [
|
|
1159
|
+
'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*',
|
|
1160
|
+
],
|
|
1161
|
+
});
|
|
1010
1162
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1163
|
+
// Add environment variable for SSM parameter prefix
|
|
1164
|
+
definition.provider.environment.SSM_PARAMETER_PREFIX =
|
|
1165
|
+
'/${self:service}/${self:provider.stage}';
|
|
1166
|
+
}
|
|
1014
1167
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1168
|
+
// Add integration-specific functions and resources
|
|
1169
|
+
if (
|
|
1170
|
+
AppDefinition.integrations &&
|
|
1171
|
+
Array.isArray(AppDefinition.integrations)
|
|
1172
|
+
) {
|
|
1173
|
+
for (const integration of AppDefinition.integrations) {
|
|
1174
|
+
if (
|
|
1175
|
+
!integration ||
|
|
1176
|
+
!integration.Definition ||
|
|
1177
|
+
!integration.Definition.name
|
|
1178
|
+
) {
|
|
1179
|
+
throw new Error(
|
|
1180
|
+
'Invalid integration: missing Definition or name'
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
const integrationName = integration.Definition.name;
|
|
1022
1184
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1185
|
+
// Add function for the integration
|
|
1186
|
+
definition.functions[integrationName] = {
|
|
1187
|
+
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
|
|
1188
|
+
events: [
|
|
1189
|
+
{
|
|
1190
|
+
httpApi: {
|
|
1191
|
+
path: `/api/${integrationName}-integration/{proxy+}`,
|
|
1192
|
+
method: 'ANY',
|
|
1193
|
+
},
|
|
1031
1194
|
},
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
};
|
|
1195
|
+
],
|
|
1196
|
+
};
|
|
1035
1197
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1198
|
+
// Add SQS Queue for the integration
|
|
1199
|
+
const queueReference = `${
|
|
1200
|
+
integrationName.charAt(0).toUpperCase() +
|
|
1201
|
+
integrationName.slice(1)
|
|
1038
1202
|
}Queue`;
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1203
|
+
const queueName = `\${self:service}--\${self:provider.stage}-${queueReference}`;
|
|
1204
|
+
definition.resources.Resources[queueReference] = {
|
|
1205
|
+
Type: 'AWS::SQS::Queue',
|
|
1206
|
+
Properties: {
|
|
1207
|
+
QueueName: `\${self:custom.${queueReference}}`,
|
|
1208
|
+
MessageRetentionPeriod: 60,
|
|
1209
|
+
VisibilityTimeout: 1800, // 30 minutes
|
|
1210
|
+
RedrivePolicy: {
|
|
1211
|
+
maxReceiveCount: 1,
|
|
1212
|
+
deadLetterTargetArn: {
|
|
1213
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
1214
|
+
},
|
|
1050
1215
|
},
|
|
1051
1216
|
},
|
|
1052
|
-
}
|
|
1053
|
-
};
|
|
1217
|
+
};
|
|
1054
1218
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1219
|
+
// Add Queue Worker for the integration
|
|
1220
|
+
const queueWorkerName = `${integrationName}QueueWorker`;
|
|
1221
|
+
definition.functions[queueWorkerName] = {
|
|
1222
|
+
handler: `node_modules/@friggframework/core/handlers/workers/integration-defined-workers.handlers.${integrationName}.queueWorker`,
|
|
1223
|
+
reservedConcurrency: 5,
|
|
1224
|
+
events: [
|
|
1225
|
+
{
|
|
1226
|
+
sqs: {
|
|
1227
|
+
arn: {
|
|
1228
|
+
'Fn::GetAtt': [queueReference, 'Arn'],
|
|
1229
|
+
},
|
|
1230
|
+
batchSize: 1,
|
|
1065
1231
|
},
|
|
1066
|
-
batchSize: 1,
|
|
1067
1232
|
},
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
};
|
|
1233
|
+
],
|
|
1234
|
+
timeout: 600,
|
|
1235
|
+
};
|
|
1072
1236
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1237
|
+
// Add Queue URL for the integration to the ENVironment variables
|
|
1238
|
+
definition.provider.environment = {
|
|
1239
|
+
...definition.provider.environment,
|
|
1240
|
+
[`${integrationName.toUpperCase()}_QUEUE_URL`]: {
|
|
1241
|
+
Ref: queueReference,
|
|
1242
|
+
},
|
|
1243
|
+
};
|
|
1080
1244
|
|
|
1081
|
-
|
|
1245
|
+
definition.custom[queueReference] = queueName;
|
|
1082
1246
|
}
|
|
1083
1247
|
}
|
|
1084
1248
|
|
|
@@ -1088,7 +1252,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1088
1252
|
// Add websocket function if enabled
|
|
1089
1253
|
if (AppDefinition.websockets?.enable === true) {
|
|
1090
1254
|
definition.functions.defaultWebsocket = {
|
|
1091
|
-
handler:
|
|
1255
|
+
handler:
|
|
1256
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1092
1257
|
events: [
|
|
1093
1258
|
{
|
|
1094
1259
|
websocket: {
|
|
@@ -1115,7 +1280,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1115
1280
|
// Add websocket function if enabled
|
|
1116
1281
|
if (AppDefinition.websockets?.enable === true) {
|
|
1117
1282
|
definition.functions.defaultWebsocket = {
|
|
1118
|
-
handler:
|
|
1283
|
+
handler:
|
|
1284
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1119
1285
|
events: [
|
|
1120
1286
|
{
|
|
1121
1287
|
websocket: {
|
|
@@ -1143,7 +1309,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1143
1309
|
// Add websocket function if enabled
|
|
1144
1310
|
if (AppDefinition.websockets?.enable === true) {
|
|
1145
1311
|
definition.functions.defaultWebsocket = {
|
|
1146
|
-
handler:
|
|
1312
|
+
handler:
|
|
1313
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
1147
1314
|
events: [
|
|
1148
1315
|
{
|
|
1149
1316
|
websocket: {
|