@friggframework/devtools 2.0.0--canary.428.ade056e.0 → 2.0.0--canary.428.3bab734.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/infrastructure/serverless-template.js +183 -112
- package/package.json +6 -6
|
@@ -372,7 +372,7 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
372
372
|
},
|
|
373
373
|
},
|
|
374
374
|
|
|
375
|
-
// Private Route Table
|
|
375
|
+
// Private Route Table for Private Subnets
|
|
376
376
|
FriggPrivateRouteTable: {
|
|
377
377
|
Type: 'AWS::EC2::RouteTable',
|
|
378
378
|
Properties: {
|
|
@@ -976,7 +976,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
976
976
|
|
|
977
977
|
// Configure KMS grants to reference the created key
|
|
978
978
|
definition.custom.kmsGrants = {
|
|
979
|
-
kmsKeyId: { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] }
|
|
979
|
+
kmsKeyId: { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] },
|
|
980
980
|
};
|
|
981
981
|
} else {
|
|
982
982
|
// No key found and createIfNoneFound is not enabled - error
|
|
@@ -1086,54 +1086,70 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1086
1086
|
// ALWAYS manage NAT Gateway through CloudFormation for self-healing
|
|
1087
1087
|
// This ensures NAT Gateway is always in the correct subnet with proper configuration
|
|
1088
1088
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1089
|
+
const natGatewayMethod =
|
|
1090
|
+
AppDefinition.vpc.natGateway?.method || 'useExisting';
|
|
1091
|
+
const needsNewNatGateway =
|
|
1092
|
+
natGatewayMethod === 'createAndManage';
|
|
1093
|
+
|
|
1094
|
+
// Helper function to validate discovered public subnet
|
|
1095
|
+
const isValidPublicSubnet = (subnetId, discoveredResources) => {
|
|
1096
|
+
// Basic validation - in production, AWSDiscovery should check route tables for IGW routes
|
|
1097
|
+
return (
|
|
1098
|
+
discoveredResources.publicSubnetHasIgwRoute !== false
|
|
1099
|
+
);
|
|
1100
|
+
};
|
|
1091
1101
|
|
|
1092
1102
|
if (needsNewNatGateway) {
|
|
1093
|
-
|
|
1094
|
-
console.log(
|
|
1103
|
+
// Always create new dedicated resources in create mode to avoid confusion with existing ones
|
|
1104
|
+
console.log(
|
|
1105
|
+
'Create mode: Creating dedicated EIP, public subnet, and NAT Gateway...'
|
|
1106
|
+
);
|
|
1095
1107
|
|
|
1096
|
-
//
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
};
|
|
1110
|
-
}
|
|
1108
|
+
// Create EIP (ignore any discovered)
|
|
1109
|
+
definition.resources.Resources.FriggNATGatewayEIP = {
|
|
1110
|
+
Type: 'AWS::EC2::EIP',
|
|
1111
|
+
Properties: {
|
|
1112
|
+
Domain: 'vpc',
|
|
1113
|
+
Tags: [
|
|
1114
|
+
{
|
|
1115
|
+
Key: 'Name',
|
|
1116
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
1117
|
+
},
|
|
1118
|
+
],
|
|
1119
|
+
},
|
|
1120
|
+
};
|
|
1111
1121
|
|
|
1112
|
-
//
|
|
1122
|
+
// Create public subnet (ignore any discovered; ensure it's in a matching AZ)
|
|
1113
1123
|
if (!discoveredResources.publicSubnetId) {
|
|
1114
|
-
console.log(
|
|
1124
|
+
console.log(
|
|
1125
|
+
'No public subnet found, creating one for NAT Gateway placement...'
|
|
1126
|
+
);
|
|
1115
1127
|
|
|
1116
1128
|
// Check if Internet Gateway exists or create one
|
|
1117
1129
|
if (!discoveredResources.internetGatewayId) {
|
|
1118
|
-
definition.resources.Resources.FriggInternetGateway =
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1130
|
+
definition.resources.Resources.FriggInternetGateway =
|
|
1131
|
+
{
|
|
1132
|
+
Type: 'AWS::EC2::InternetGateway',
|
|
1133
|
+
Properties: {
|
|
1134
|
+
Tags: [
|
|
1135
|
+
{
|
|
1136
|
+
Key: 'Name',
|
|
1137
|
+
Value: '${self:service}-${self:provider.stage}-igw',
|
|
1138
|
+
},
|
|
1139
|
+
],
|
|
1140
|
+
},
|
|
1141
|
+
};
|
|
1129
1142
|
|
|
1130
|
-
definition.resources.Resources.FriggIGWAttachment =
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1143
|
+
definition.resources.Resources.FriggIGWAttachment =
|
|
1144
|
+
{
|
|
1145
|
+
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
1146
|
+
Properties: {
|
|
1147
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1148
|
+
InternetGatewayId: {
|
|
1149
|
+
Ref: 'FriggInternetGateway',
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
};
|
|
1137
1153
|
}
|
|
1138
1154
|
|
|
1139
1155
|
// Create a small public subnet for NAT Gateway
|
|
@@ -1141,8 +1157,12 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1141
1157
|
Type: 'AWS::EC2::Subnet',
|
|
1142
1158
|
Properties: {
|
|
1143
1159
|
VpcId: discoveredResources.defaultVpcId,
|
|
1144
|
-
CidrBlock:
|
|
1145
|
-
|
|
1160
|
+
CidrBlock:
|
|
1161
|
+
AppDefinition.vpc.natGateway
|
|
1162
|
+
?.publicSubnetCidr || '172.31.250.0/24',
|
|
1163
|
+
AvailabilityZone: {
|
|
1164
|
+
'Fn::Select': [0, { 'Fn::GetAZs': '' }],
|
|
1165
|
+
},
|
|
1146
1166
|
MapPublicIpOnLaunch: true,
|
|
1147
1167
|
Tags: [
|
|
1148
1168
|
{
|
|
@@ -1174,36 +1194,45 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1174
1194
|
// Add route to Internet Gateway
|
|
1175
1195
|
definition.resources.Resources.FriggPublicRoute = {
|
|
1176
1196
|
Type: 'AWS::EC2::Route',
|
|
1177
|
-
DependsOn: discoveredResources.internetGatewayId
|
|
1197
|
+
DependsOn: discoveredResources.internetGatewayId
|
|
1198
|
+
? []
|
|
1199
|
+
: 'FriggIGWAttachment',
|
|
1178
1200
|
Properties: {
|
|
1179
1201
|
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
1180
1202
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
1181
|
-
GatewayId:
|
|
1203
|
+
GatewayId:
|
|
1204
|
+
discoveredResources.internetGatewayId || {
|
|
1205
|
+
Ref: 'FriggInternetGateway',
|
|
1206
|
+
},
|
|
1182
1207
|
},
|
|
1183
1208
|
};
|
|
1184
1209
|
|
|
1185
1210
|
// Associate public subnet with public route table
|
|
1186
|
-
definition.resources.Resources.FriggPublicSubnetRouteTableAssociation =
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1211
|
+
definition.resources.Resources.FriggPublicSubnetRouteTableAssociation =
|
|
1212
|
+
{
|
|
1213
|
+
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1214
|
+
Properties: {
|
|
1215
|
+
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
1216
|
+
RouteTableId: {
|
|
1217
|
+
Ref: 'FriggPublicRouteTable',
|
|
1218
|
+
},
|
|
1219
|
+
},
|
|
1220
|
+
};
|
|
1193
1221
|
}
|
|
1194
1222
|
|
|
1195
|
-
//
|
|
1223
|
+
// Create NAT Gateway using the new resources
|
|
1196
1224
|
definition.resources.Resources.FriggNATGateway = {
|
|
1197
1225
|
Type: 'AWS::EC2::NatGateway',
|
|
1198
1226
|
Properties: {
|
|
1199
|
-
AllocationId:
|
|
1200
|
-
|
|
1201
|
-
'
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1227
|
+
AllocationId: {
|
|
1228
|
+
'Fn::GetAtt': [
|
|
1229
|
+
'FriggNATGatewayEIP',
|
|
1230
|
+
'AllocationId',
|
|
1231
|
+
],
|
|
1232
|
+
},
|
|
1233
|
+
SubnetId: discoveredResources.publicSubnetId || {
|
|
1234
|
+
Ref: 'FriggPublicSubnet',
|
|
1235
|
+
},
|
|
1207
1236
|
Tags: [
|
|
1208
1237
|
{
|
|
1209
1238
|
Key: 'Name',
|
|
@@ -1216,15 +1245,32 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1216
1245
|
],
|
|
1217
1246
|
},
|
|
1218
1247
|
};
|
|
1248
|
+
} else if (discoveredResources.existingNatGatewayId) {
|
|
1249
|
+
// Reuse mode: Use existing NAT, but validate first
|
|
1250
|
+
if (
|
|
1251
|
+
discoveredResources.publicSubnetId &&
|
|
1252
|
+
isValidPublicSubnet(
|
|
1253
|
+
discoveredResources.publicSubnetId,
|
|
1254
|
+
discoveredResources
|
|
1255
|
+
)
|
|
1256
|
+
) {
|
|
1257
|
+
console.log(
|
|
1258
|
+
'Reuse mode: Valid existing NAT found; adding routes...'
|
|
1259
|
+
);
|
|
1260
|
+
// No new NAT creation; just add routes referencing existingNatGatewayId
|
|
1261
|
+
} else {
|
|
1262
|
+
throw new Error(
|
|
1263
|
+
'Existing NAT discovered but public subnet is invalid or missing. Set method to "createAndManage" or fix subnet configuration.'
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1219
1266
|
} else {
|
|
1220
|
-
//
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
// and will adopt it rather than creating a duplicate
|
|
1267
|
+
// No NAT and not in create mode: Error out to prevent isolated subnets
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
'No existing NAT Gateway found and createAndManage not enabled. Update appDefinition.vpc.natGateway.method or ensure discovery finds a valid NAT.'
|
|
1270
|
+
);
|
|
1225
1271
|
}
|
|
1226
1272
|
|
|
1227
|
-
//
|
|
1273
|
+
// Always add route table and routes (referencing the NAT, whether new or existing)
|
|
1228
1274
|
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
1229
1275
|
Type: 'AWS::EC2::RouteTable',
|
|
1230
1276
|
Properties: {
|
|
@@ -1240,14 +1286,26 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1240
1286
|
},
|
|
1241
1287
|
};
|
|
1242
1288
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1289
|
+
if (needsNewNatGateway) {
|
|
1290
|
+
definition.resources.Resources.FriggNATRoute = {
|
|
1291
|
+
Type: 'AWS::EC2::Route',
|
|
1292
|
+
Properties: {
|
|
1293
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1294
|
+
DestinationCidrBlock: '0.0.0.0/0',
|
|
1295
|
+
NatGatewayId: { Ref: 'FriggNATGateway' },
|
|
1296
|
+
},
|
|
1297
|
+
};
|
|
1298
|
+
} else {
|
|
1299
|
+
definition.resources.Resources.FriggNATRoute = {
|
|
1300
|
+
Type: 'AWS::EC2::Route',
|
|
1301
|
+
Properties: {
|
|
1302
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1303
|
+
DestinationCidrBlock: '0.0.0.0/0',
|
|
1304
|
+
NatGatewayId:
|
|
1305
|
+
discoveredResources.existingNatGatewayId,
|
|
1306
|
+
},
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1251
1309
|
|
|
1252
1310
|
// Associate Lambda subnets with NAT Gateway route table
|
|
1253
1311
|
// Note: This will only work if the subnets aren't already associated with another route table
|
|
@@ -1295,37 +1353,48 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1295
1353
|
};
|
|
1296
1354
|
|
|
1297
1355
|
// Add KMS VPC endpoint if using KMS encryption
|
|
1298
|
-
if (
|
|
1356
|
+
if (
|
|
1357
|
+
AppDefinition.encryption?.fieldLevelEncryptionMethod ===
|
|
1358
|
+
'kms'
|
|
1359
|
+
) {
|
|
1299
1360
|
// Create security group for VPC endpoints if it doesn't exist
|
|
1300
|
-
if (
|
|
1301
|
-
definition.resources.Resources
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1361
|
+
if (
|
|
1362
|
+
!definition.resources.Resources
|
|
1363
|
+
.VPCEndpointSecurityGroup
|
|
1364
|
+
) {
|
|
1365
|
+
definition.resources.Resources.VPCEndpointSecurityGroup =
|
|
1366
|
+
{
|
|
1367
|
+
Type: 'AWS::EC2::SecurityGroup',
|
|
1368
|
+
Properties: {
|
|
1369
|
+
GroupDescription:
|
|
1370
|
+
'Security group for VPC endpoints',
|
|
1371
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1372
|
+
SecurityGroupIngress: [
|
|
1373
|
+
{
|
|
1374
|
+
IpProtocol: 'tcp',
|
|
1375
|
+
FromPort: 443,
|
|
1376
|
+
ToPort: 443,
|
|
1377
|
+
CidrIp:
|
|
1378
|
+
discoveredResources.vpcCidr ||
|
|
1379
|
+
'10.0.0.0/16', // Dynamic VPC CIDR
|
|
1380
|
+
},
|
|
1381
|
+
],
|
|
1382
|
+
Tags: [
|
|
1383
|
+
{
|
|
1384
|
+
Key: 'Name',
|
|
1385
|
+
Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg',
|
|
1386
|
+
},
|
|
1387
|
+
],
|
|
1388
|
+
},
|
|
1389
|
+
};
|
|
1322
1390
|
}
|
|
1323
1391
|
|
|
1324
1392
|
definition.resources.Resources.VPCEndpointKMS = {
|
|
1325
1393
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
1326
1394
|
Properties: {
|
|
1327
1395
|
VpcId: discoveredResources.defaultVpcId,
|
|
1328
|
-
ServiceName:
|
|
1396
|
+
ServiceName:
|
|
1397
|
+
'com.amazonaws.${self:provider.region}.kms',
|
|
1329
1398
|
VpcEndpointType: 'Interface',
|
|
1330
1399
|
SubnetIds: vpcConfig.subnetIds,
|
|
1331
1400
|
SecurityGroupIds: [
|
|
@@ -1337,19 +1406,21 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1337
1406
|
|
|
1338
1407
|
// Also add Secrets Manager endpoint if using Secrets Manager
|
|
1339
1408
|
if (AppDefinition.secretsManager?.enable === true) {
|
|
1340
|
-
definition.resources.Resources.VPCEndpointSecretsManager =
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1409
|
+
definition.resources.Resources.VPCEndpointSecretsManager =
|
|
1410
|
+
{
|
|
1411
|
+
Type: 'AWS::EC2::VPCEndpoint',
|
|
1412
|
+
Properties: {
|
|
1413
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1414
|
+
ServiceName:
|
|
1415
|
+
'com.amazonaws.${self:provider.region}.secretsmanager',
|
|
1416
|
+
VpcEndpointType: 'Interface',
|
|
1417
|
+
SubnetIds: vpcConfig.subnetIds,
|
|
1418
|
+
SecurityGroupIds: [
|
|
1419
|
+
{ Ref: 'VPCEndpointSecurityGroup' },
|
|
1420
|
+
],
|
|
1421
|
+
PrivateDnsEnabled: true,
|
|
1422
|
+
},
|
|
1423
|
+
};
|
|
1353
1424
|
}
|
|
1354
1425
|
}
|
|
1355
1426
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.428.
|
|
4
|
+
"version": "2.0.0--canary.428.3bab734.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"@babel/eslint-parser": "^7.18.9",
|
|
10
10
|
"@babel/parser": "^7.25.3",
|
|
11
11
|
"@babel/traverse": "^7.25.3",
|
|
12
|
-
"@friggframework/schemas": "2.0.0--canary.428.
|
|
13
|
-
"@friggframework/test": "2.0.0--canary.428.
|
|
12
|
+
"@friggframework/schemas": "2.0.0--canary.428.3bab734.0",
|
|
13
|
+
"@friggframework/test": "2.0.0--canary.428.3bab734.0",
|
|
14
14
|
"@hapi/boom": "^10.0.1",
|
|
15
15
|
"@inquirer/prompts": "^5.3.8",
|
|
16
16
|
"axios": "^1.7.2",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"serverless-http": "^2.7.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@friggframework/eslint-config": "2.0.0--canary.428.
|
|
36
|
-
"@friggframework/prettier-config": "2.0.0--canary.428.
|
|
35
|
+
"@friggframework/eslint-config": "2.0.0--canary.428.3bab734.0",
|
|
36
|
+
"@friggframework/prettier-config": "2.0.0--canary.428.3bab734.0",
|
|
37
37
|
"jest": "^30.1.3",
|
|
38
38
|
"prettier": "^2.7.1",
|
|
39
39
|
"serverless": "3.39.0",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "3bab734d2f509d43177d80959ac59df495b3df7b"
|
|
70
70
|
}
|