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