@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.
@@ -17,39 +17,38 @@ These permissions are required when `aws-discovery.js` runs during the build to
17
17
 
18
18
  ```json
19
19
  {
20
- "Version": "2012-10-17",
21
- "Statement": [
22
- {
23
- "Sid": "AWSDiscoveryPermissions",
24
- "Effect": "Allow",
25
- "Action": [
26
- "sts:GetCallerIdentity",
27
- "ec2:DescribeVpcs",
28
- "ec2:DescribeSubnets",
29
- "ec2:DescribeSecurityGroups",
30
- "ec2:DescribeRouteTables",
31
- "ec2:DescribeNatGateways",
32
- "ec2:DescribeAddresses",
33
- "kms:ListKeys",
34
- "kms:DescribeKey"
35
- ],
36
- "Resource": "*"
37
- }
38
- ]
20
+ "Version": "2012-10-17",
21
+ "Statement": [
22
+ {
23
+ "Sid": "AWSDiscoveryPermissions",
24
+ "Effect": "Allow",
25
+ "Action": [
26
+ "sts:GetCallerIdentity",
27
+ "ec2:DescribeVpcs",
28
+ "ec2:DescribeSubnets",
29
+ "ec2:DescribeSecurityGroups",
30
+ "ec2:DescribeRouteTables",
31
+ "ec2:DescribeNatGateways",
32
+ "ec2:DescribeAddresses",
33
+ "kms:ListKeys",
34
+ "kms:DescribeKey"
35
+ ],
36
+ "Resource": "*"
37
+ }
38
+ ]
39
39
  }
40
40
  ```
41
41
 
42
42
  ### What Each Permission Does:
43
-
44
- - **`sts:GetCallerIdentity`** - Gets your AWS account ID for KMS key ARN construction
45
- - **`ec2:DescribeVpcs`** - Finds your default VPC or first available VPC
46
- - **`ec2:DescribeSubnets`** - Identifies private subnets within your VPC
47
- - **`ec2:DescribeSecurityGroups`** - Locates default security group or Frigg-specific security group
48
- - **`ec2:DescribeRouteTables`** - Determines which subnets are private (no direct internet gateway route)
49
- - **`ec2:DescribeNatGateways`** - Finds existing NAT Gateways to reuse (prevents duplicate resource creation)
50
- - **`ec2:DescribeAddresses`** - Finds available Elastic IPs to reuse (prevents allocation conflicts)
51
- - **`kms:ListKeys`** - Lists available KMS keys in your account
52
- - **`kms:DescribeKey`** - Gets details about KMS keys to find customer-managed keys
43
+ - **`sts:GetCallerIdentity`** - Gets your AWS account ID for KMS key ARN construction
44
+ - **`ec2:DescribeVpcs`** - Finds your default VPC or first available VPC
45
+ - **`ec2:DescribeSubnets`** - Identifies private subnets within your VPC
46
+ - **`ec2:DescribeSecurityGroups`** - Locates default security group or Frigg-specific security group
47
+ - **`ec2:DescribeRouteTables`** - Determines which subnets are private (no direct internet gateway route)
48
+ - **`ec2:DescribeNatGateways`** - Finds existing NAT Gateways to reuse (prevents duplicate resource creation)
49
+ - **`ec2:DescribeAddresses`** - Finds available Elastic IPs to reuse (prevents allocation conflicts)
50
+ - **`kms:ListKeys`** - Lists available KMS keys in your account
51
+ - **`kms:DescribeKey`** - Gets details about KMS keys to find customer-managed keys
53
52
 
54
53
  ## Core Deployment Permissions
55
54
 
@@ -57,236 +56,214 @@ Required for basic Frigg application deployment:
57
56
 
58
57
  ```json
59
58
  {
60
- "Version": "2012-10-17",
61
- "Statement": [
62
- {
63
- "Sid": "CloudFormationFriggStacks",
64
- "Effect": "Allow",
65
- "Action": [
66
- "cloudformation:CreateStack",
67
- "cloudformation:UpdateStack",
68
- "cloudformation:DeleteStack",
69
- "cloudformation:DescribeStacks",
70
- "cloudformation:DescribeStackEvents",
71
- "cloudformation:DescribeStackResources",
72
- "cloudformation:DescribeStackResource",
73
- "cloudformation:ListStackResources",
74
- "cloudformation:GetTemplate",
75
- "cloudformation:ValidateTemplate",
76
- "cloudformation:DescribeChangeSet",
77
- "cloudformation:CreateChangeSet",
78
- "cloudformation:DeleteChangeSet",
79
- "cloudformation:ExecuteChangeSet"
80
- ],
81
- "Resource": ["arn:aws:cloudformation:*:*:stack/*frigg*/*"]
82
- },
83
- {
84
- "Sid": "S3DeploymentBucket",
85
- "Effect": "Allow",
86
- "Action": [
87
- "s3:CreateBucket",
88
- "s3:PutObject",
89
- "s3:GetObject",
90
- "s3:DeleteObject",
91
- "s3:PutBucketPolicy",
92
- "s3:PutBucketVersioning",
93
- "s3:PutBucketPublicAccessBlock",
94
- "s3:GetBucketLocation",
95
- "s3:ListBucket",
96
- "s3:PutBucketTagging",
97
- "s3:GetBucketTagging"
98
- ],
99
- "Resource": [
100
- "arn:aws:s3:::*serverless*",
101
- "arn:aws:s3:::*serverless*/*"
102
- ]
103
- },
104
- {
105
- "Sid": "LambdaFriggFunctions",
106
- "Effect": "Allow",
107
- "Action": [
108
- "lambda:CreateFunction",
109
- "lambda:UpdateFunctionCode",
110
- "lambda:UpdateFunctionConfiguration",
111
- "lambda:DeleteFunction",
112
- "lambda:GetFunction",
113
- "lambda:ListFunctions",
114
- "lambda:PublishVersion",
115
- "lambda:CreateAlias",
116
- "lambda:UpdateAlias",
117
- "lambda:DeleteAlias",
118
- "lambda:GetAlias",
119
- "lambda:AddPermission",
120
- "lambda:RemovePermission",
121
- "lambda:GetPolicy",
122
- "lambda:PutProvisionedConcurrencyConfig",
123
- "lambda:DeleteProvisionedConcurrencyConfig",
124
- "lambda:PutConcurrency",
125
- "lambda:DeleteConcurrency",
126
- "lambda:TagResource",
127
- "lambda:UntagResource",
128
- "lambda:ListVersionsByFunction"
129
- ],
130
- "Resource": ["arn:aws:lambda:*:*:function:*frigg*"]
131
- },
132
- {
133
- "Sid": "FriggLambdaEventSourceMapping",
134
- "Effect": "Allow",
135
- "Action": [
136
- "lambda:CreateEventSourceMapping",
137
- "lambda:DeleteEventSourceMapping",
138
- "lambda:GetEventSourceMapping",
139
- "lambda:UpdateEventSourceMapping",
140
- "lambda:ListEventSourceMappings"
141
- ],
142
- "Resource": ["arn:aws:lambda:*:*:event-source-mapping:*"]
143
- },
144
- {
145
- "Sid": "IAMRolesForFriggLambda",
146
- "Effect": "Allow",
147
- "Action": [
148
- "iam:CreateRole",
149
- "iam:DeleteRole",
150
- "iam:GetRole",
151
- "iam:PassRole",
152
- "iam:PutRolePolicy",
153
- "iam:DeleteRolePolicy",
154
- "iam:GetRolePolicy",
155
- "iam:AttachRolePolicy",
156
- "iam:DetachRolePolicy",
157
- "iam:TagRole",
158
- "iam:UntagRole"
159
- ],
160
- "Resource": [
161
- "arn:aws:iam::*:role/*frigg*",
162
- "arn:aws:iam::*:role/*frigg*LambdaRole*"
163
- ]
164
- },
165
- {
166
- "Sid": "IAMPolicyVersionPermissions",
167
- "Effect": "Allow",
168
- "Action": ["iam:ListPolicyVersions"],
169
- "Resource": ["arn:aws:iam::*:policy/*"]
170
- },
171
- {
172
- "Sid": "FriggMessagingServices",
173
- "Effect": "Allow",
174
- "Action": [
175
- "sqs:CreateQueue",
176
- "sqs:DeleteQueue",
177
- "sqs:GetQueueAttributes",
178
- "sqs:SetQueueAttributes",
179
- "sqs:GetQueueUrl",
180
- "sqs:TagQueue",
181
- "sqs:UntagQueue"
182
- ],
183
- "Resource": [
184
- "arn:aws:sqs:*:*:*frigg*",
185
- "arn:aws:sqs:*:*:internal-error-queue-*"
186
- ]
187
- },
188
- {
189
- "Sid": "FriggSNSTopics",
190
- "Effect": "Allow",
191
- "Action": [
192
- "sns:CreateTopic",
193
- "sns:DeleteTopic",
194
- "sns:GetTopicAttributes",
195
- "sns:SetTopicAttributes",
196
- "sns:Subscribe",
197
- "sns:Unsubscribe",
198
- "sns:TagResource",
199
- "sns:UntagResource"
200
- ],
201
- "Resource": ["arn:aws:sns:*:*:*frigg*"]
202
- },
203
- {
204
- "Sid": "FriggMonitoringAndLogs",
205
- "Effect": "Allow",
206
- "Action": [
207
- "cloudwatch:PutMetricAlarm",
208
- "cloudwatch:DeleteAlarms",
209
- "cloudwatch:DescribeAlarms",
210
- "logs:CreateLogGroup",
211
- "logs:CreateLogStream",
212
- "logs:DeleteLogGroup",
213
- "logs:DescribeLogGroups",
214
- "logs:DescribeLogStreams",
215
- "logs:FilterLogEvents",
216
- "logs:PutLogEvents",
217
- "logs:PutRetentionPolicy"
218
- ],
219
- "Resource": [
220
- "arn:aws:logs:*:*:log-group:/aws/lambda/*frigg*",
221
- "arn:aws:logs:*:*:log-group:/aws/lambda/*frigg*:*",
222
- "arn:aws:cloudwatch:*:*:alarm:*frigg*"
223
- ]
224
- },
225
- {
226
- "Sid": "FriggAPIGateway",
227
- "Effect": "Allow",
228
- "Action": [
229
- "apigateway:POST",
230
- "apigateway:PUT",
231
- "apigateway:DELETE",
232
- "apigateway:GET",
233
- "apigateway:PATCH"
234
- ],
235
- "Resource": [
236
- "arn:aws:apigateway:*::/restapis",
237
- "arn:aws:apigateway:*::/restapis/*",
238
- "arn:aws:apigateway:*::/domainnames",
239
- "arn:aws:apigateway:*::/domainnames/*"
240
- ]
241
- },
242
- {
243
- "Sid": "FriggAPIGatewayV2",
244
- "Effect": "Allow",
245
- "Action": [
246
- "apigateway:GET",
247
- "apigateway:DELETE",
248
- "apigateway:PATCH",
249
- "apigateway:POST",
250
- "apigateway:PUT"
251
- ],
252
- "Resource": [
253
- "arn:aws:apigateway:*::/apis",
254
- "arn:aws:apigateway:*::/apis/*",
255
- "arn:aws:apigateway:*::/apis/*/stages",
256
- "arn:aws:apigateway:*::/apis/*/stages/*",
257
- "arn:aws:apigateway:*::/apis/*/mappings",
258
- "arn:aws:apigateway:*::/apis/*/mappings/*"
259
- ]
260
- }
261
- ]
59
+ "Version": "2012-10-17",
60
+ "Statement": [
61
+ {
62
+ "Sid": "CloudFormationFriggStacks",
63
+ "Effect": "Allow",
64
+ "Action": [
65
+ "cloudformation:CreateStack",
66
+ "cloudformation:UpdateStack",
67
+ "cloudformation:DeleteStack",
68
+ "cloudformation:DescribeStacks",
69
+ "cloudformation:DescribeStackEvents",
70
+ "cloudformation:DescribeStackResources",
71
+ "cloudformation:DescribeStackResource",
72
+ "cloudformation:ListStackResources",
73
+ "cloudformation:GetTemplate",
74
+ "cloudformation:ValidateTemplate",
75
+ "cloudformation:DescribeChangeSet",
76
+ "cloudformation:CreateChangeSet",
77
+ "cloudformation:DeleteChangeSet",
78
+ "cloudformation:ExecuteChangeSet"
79
+ ],
80
+ "Resource": [
81
+ "arn:aws:cloudformation:*:*:stack/*frigg*/*"
82
+ ]
83
+ },
84
+ {
85
+ "Sid": "S3DeploymentBucket",
86
+ "Effect": "Allow",
87
+ "Action": [
88
+ "s3:CreateBucket",
89
+ "s3:PutObject",
90
+ "s3:GetObject",
91
+ "s3:DeleteObject",
92
+ "s3:PutBucketPolicy",
93
+ "s3:PutBucketVersioning",
94
+ "s3:PutBucketPublicAccessBlock",
95
+ "s3:GetBucketLocation",
96
+ "s3:ListBucket",
97
+ "s3:PutBucketTagging",
98
+ "s3:GetBucketTagging"
99
+ ],
100
+ "Resource": [
101
+ "arn:aws:s3:::*serverless*",
102
+ "arn:aws:s3:::*serverless*/*"
103
+ ]
104
+ },
105
+ {
106
+ "Sid": "LambdaFriggFunctions",
107
+ "Effect": "Allow",
108
+ "Action": [
109
+ "lambda:CreateFunction",
110
+ "lambda:UpdateFunctionCode",
111
+ "lambda:UpdateFunctionConfiguration",
112
+ "lambda:DeleteFunction",
113
+ "lambda:GetFunction",
114
+ "lambda:ListFunctions",
115
+ "lambda:PublishVersion",
116
+ "lambda:CreateAlias",
117
+ "lambda:UpdateAlias",
118
+ "lambda:DeleteAlias",
119
+ "lambda:GetAlias",
120
+ "lambda:AddPermission",
121
+ "lambda:RemovePermission",
122
+ "lambda:GetPolicy",
123
+ "lambda:PutProvisionedConcurrencyConfig",
124
+ "lambda:DeleteProvisionedConcurrencyConfig",
125
+ "lambda:PutConcurrency",
126
+ "lambda:DeleteConcurrency",
127
+ "lambda:TagResource",
128
+ "lambda:UntagResource",
129
+ "lambda:ListVersionsByFunction"
130
+ ],
131
+ "Resource": [
132
+ "arn:aws:lambda:*:*:function:*frigg*"
133
+ ]
134
+ },
135
+ {
136
+ "Sid": "FriggLambdaEventSourceMapping",
137
+ "Effect": "Allow",
138
+ "Action": [
139
+ "lambda:CreateEventSourceMapping",
140
+ "lambda:DeleteEventSourceMapping",
141
+ "lambda:GetEventSourceMapping",
142
+ "lambda:UpdateEventSourceMapping",
143
+ "lambda:ListEventSourceMappings"
144
+ ],
145
+ "Resource": [
146
+ "arn:aws:lambda:*:*:event-source-mapping:*"
147
+ ]
148
+ },
149
+ {
150
+ "Sid": "IAMRolesForFriggLambda",
151
+ "Effect": "Allow",
152
+ "Action": [
153
+ "iam:CreateRole",
154
+ "iam:DeleteRole",
155
+ "iam:GetRole",
156
+ "iam:PassRole",
157
+ "iam:PutRolePolicy",
158
+ "iam:DeleteRolePolicy",
159
+ "iam:GetRolePolicy",
160
+ "iam:AttachRolePolicy",
161
+ "iam:DetachRolePolicy",
162
+ "iam:TagRole",
163
+ "iam:UntagRole"
164
+ ],
165
+ "Resource": [
166
+ "arn:aws:iam::*:role/*frigg*",
167
+ "arn:aws:iam::*:role/*frigg*LambdaRole*"
168
+ ]
169
+ },
170
+ {
171
+ "Sid": "IAMPolicyVersionPermissions",
172
+ "Effect": "Allow",
173
+ "Action": [
174
+ "iam:ListPolicyVersions"
175
+ ],
176
+ "Resource": [
177
+ "arn:aws:iam::*:policy/*"
178
+ ]
179
+ },
180
+ {
181
+ "Sid": "FriggMessagingServices",
182
+ "Effect": "Allow",
183
+ "Action": [
184
+ "sqs:CreateQueue",
185
+ "sqs:DeleteQueue",
186
+ "sqs:GetQueueAttributes",
187
+ "sqs:SetQueueAttributes",
188
+ "sqs:GetQueueUrl",
189
+ "sqs:TagQueue",
190
+ "sqs:UntagQueue"
191
+ ],
192
+ "Resource": [
193
+ "arn:aws:sqs:*:*:*frigg*",
194
+ "arn:aws:sqs:*:*:internal-error-queue-*"
195
+ ]
196
+ },
197
+ {
198
+ "Sid": "FriggSNSTopics",
199
+ "Effect": "Allow",
200
+ "Action": [
201
+ "sns:CreateTopic",
202
+ "sns:DeleteTopic",
203
+ "sns:GetTopicAttributes",
204
+ "sns:SetTopicAttributes",
205
+ "sns:Subscribe",
206
+ "sns:Unsubscribe",
207
+ "sns:TagResource",
208
+ "sns:UntagResource"
209
+ ],
210
+ "Resource": [
211
+ "arn:aws:sns:*:*:*frigg*"
212
+ ]
213
+ },
214
+ {
215
+ "Sid": "FriggMonitoringAndLogs",
216
+ "Effect": "Allow",
217
+ "Action": [
218
+ "cloudwatch:PutMetricAlarm",
219
+ "cloudwatch:DeleteAlarms",
220
+ "cloudwatch:DescribeAlarms",
221
+ "logs:CreateLogGroup",
222
+ "logs:CreateLogStream",
223
+ "logs:DeleteLogGroup",
224
+ "logs:DescribeLogGroups",
225
+ "logs:DescribeLogStreams",
226
+ "logs:FilterLogEvents",
227
+ "logs:PutLogEvents",
228
+ "logs:PutRetentionPolicy"
229
+ ],
230
+ "Resource": [
231
+ "arn:aws:logs:*:*:log-group:/aws/lambda/*frigg*",
232
+ "arn:aws:logs:*:*:log-group:/aws/lambda/*frigg*:*",
233
+ "arn:aws:cloudwatch:*:*:alarm:*frigg*"
234
+ ]
235
+ },
236
+ {
237
+ "Sid": "FriggAPIGateway",
238
+ "Effect": "Allow",
239
+ "Action": [
240
+ "apigateway:POST",
241
+ "apigateway:PUT",
242
+ "apigateway:DELETE",
243
+ "apigateway:GET",
244
+ "apigateway:PATCH"
245
+ ],
246
+ "Resource": [
247
+ "arn:aws:apigateway:*::/restapis",
248
+ "arn:aws:apigateway:*::/restapis/*",
249
+ "arn:aws:apigateway:*::/domainnames",
250
+ "arn:aws:apigateway:*::/domainnames/*"
251
+ ]
252
+ }
253
+ ]
262
254
  }
263
255
  ```
264
256
 
265
- **API Gateway Permissions Security Note:**
266
-
267
- The API Gateway permissions are intentionally split into two separate policies:
268
-
269
- - **FriggAPIGateway**: Covers API Gateway v1 (REST APIs) with specific CRUD operations
270
- - **FriggAPIGatewayV2**: Covers API Gateway v2 (HTTP APIs) with the same specific operations
271
-
272
- This approach follows the principle of least privilege by:
273
-
274
- - ✅ **Avoiding wildcards**: Using specific actions instead of `apigateway:*`
275
- - ✅ **Resource scoping**: Limiting to Frigg-specific API Gateway resources
276
- - ✅ **Version separation**: Maintaining clear separation between v1 and v2 APIs
277
- - ✅ **Audit-friendly**: Each permission can be individually tracked and monitored
278
-
279
257
  **What the Lambda permissions enable:**
280
-
281
- - **Function Management**: Create, update, delete, and configure Lambda functions
282
- - **Version & Alias Management**: Publish new versions and manage aliases for deployments
283
- - **Permission Management**: Add/remove function permissions for API Gateway and other services
284
- - **Concurrency Management**: Configure provisioned and reserved concurrency
285
- - **EventSourceMapping Management**: Connect Lambda functions to event sources like SQS, SNS, Kinesis, and DynamoDB streams. These permissions are crucial for:
286
- - Creating mappings between SQS queues and Lambda functions
287
- - Managing event-driven architectures
288
- - Handling queue-based processing (e.g., HubSpot integration queues)
289
- - Cleaning up event source mappings during stack deletion
258
+ - **Function Management**: Create, update, delete, and configure Lambda functions
259
+ - **Version & Alias Management**: Publish new versions and manage aliases for deployments
260
+ - **Permission Management**: Add/remove function permissions for API Gateway and other services
261
+ - **Concurrency Management**: Configure provisioned and reserved concurrency
262
+ - **EventSourceMapping Management**: Connect Lambda functions to event sources like SQS, SNS, Kinesis, and DynamoDB streams. These permissions are crucial for:
263
+ - Creating mappings between SQS queues and Lambda functions
264
+ - Managing event-driven architectures
265
+ - Handling queue-based processing (e.g., HubSpot integration queues)
266
+ - Cleaning up event source mappings during stack deletion
290
267
 
291
268
  ## Feature-Specific Permissions
292
269
 
@@ -296,61 +273,58 @@ Additional permissions needed when your app definition includes `vpc: { enable:
296
273
 
297
274
  ```json
298
275
  {
299
- "Version": "2012-10-17",
300
- "Statement": [
301
- {
302
- "Sid": "FriggVPCEndpointManagement",
303
- "Effect": "Allow",
304
- "Action": [
305
- "ec2:CreateVpcEndpoint",
306
- "ec2:DeleteVpcEndpoint",
307
- "ec2:DescribeVpcEndpoints",
308
- "ec2:ModifyVpcEndpoint",
309
- "ec2:CreateNatGateway",
310
- "ec2:DeleteNatGateway",
311
- "ec2:DescribeNatGateways",
312
- "ec2:AllocateAddress",
313
- "ec2:ReleaseAddress",
314
- "ec2:DescribeAddresses",
315
- "ec2:CreateRouteTable",
316
- "ec2:DeleteRouteTable",
317
- "ec2:DescribeRouteTables",
318
- "ec2:CreateRoute",
319
- "ec2:DeleteRoute",
320
- "ec2:AssociateRouteTable",
321
- "ec2:DisassociateRouteTable",
322
- "ec2:CreateSecurityGroup",
323
- "ec2:DeleteSecurityGroup",
324
- "ec2:AuthorizeSecurityGroupEgress",
325
- "ec2:AuthorizeSecurityGroupIngress",
326
- "ec2:RevokeSecurityGroupEgress",
327
- "ec2:RevokeSecurityGroupIngress",
328
- "ec2:DeleteSubnet",
329
- "ec2:DetachInternetGateway"
330
- ],
331
- "Resource": "*",
332
- "Condition": {
333
- "StringLike": {
334
- "ec2:CreateAction": [
335
- "CreateVpcEndpoint",
336
- "CreateNatGateway",
337
- "CreateRouteTable",
338
- "CreateRoute",
339
- "CreateSecurityGroup"
340
- ]
341
- }
342
- }
276
+ "Version": "2012-10-17",
277
+ "Statement": [
278
+ {
279
+ "Sid": "FriggVPCEndpointManagement",
280
+ "Effect": "Allow",
281
+ "Action": [
282
+ "ec2:CreateVpcEndpoint",
283
+ "ec2:DeleteVpcEndpoint",
284
+ "ec2:DescribeVpcEndpoints",
285
+ "ec2:ModifyVpcEndpoint",
286
+ "ec2:CreateNatGateway",
287
+ "ec2:DeleteNatGateway",
288
+ "ec2:DescribeNatGateways",
289
+ "ec2:AllocateAddress",
290
+ "ec2:ReleaseAddress",
291
+ "ec2:DescribeAddresses",
292
+ "ec2:CreateRouteTable",
293
+ "ec2:DeleteRouteTable",
294
+ "ec2:DescribeRouteTables",
295
+ "ec2:CreateRoute",
296
+ "ec2:DeleteRoute",
297
+ "ec2:AssociateRouteTable",
298
+ "ec2:DisassociateRouteTable",
299
+ "ec2:CreateSecurityGroup",
300
+ "ec2:DeleteSecurityGroup",
301
+ "ec2:AuthorizeSecurityGroupEgress",
302
+ "ec2:AuthorizeSecurityGroupIngress",
303
+ "ec2:RevokeSecurityGroupEgress",
304
+ "ec2:RevokeSecurityGroupIngress"
305
+ ],
306
+ "Resource": "*",
307
+ "Condition": {
308
+ "StringLike": {
309
+ "ec2:CreateAction": [
310
+ "CreateVpcEndpoint",
311
+ "CreateNatGateway",
312
+ "CreateRouteTable",
313
+ "CreateRoute",
314
+ "CreateSecurityGroup"
315
+ ]
343
316
  }
344
- ]
317
+ }
318
+ }
319
+ ]
345
320
  }
346
321
  ```
347
322
 
348
323
  **What this enables:**
349
-
350
- - Creates NAT Gateway for Lambda internet access to external APIs (Salesforce, HubSpot, etc.)
351
- - Creates VPC endpoints for AWS services (S3, DynamoDB, KMS, SSM) to reduce NAT Gateway costs
352
- - Creates route tables and subnet associations for proper Lambda networking
353
- - Automatically configures your Lambda functions to run in your default VPC with full internet access
324
+ - Creates NAT Gateway for Lambda internet access to external APIs (Salesforce, HubSpot, etc.)
325
+ - Creates VPC endpoints for AWS services (S3, DynamoDB, KMS, SSM) to reduce NAT Gateway costs
326
+ - Creates route tables and subnet associations for proper Lambda networking
327
+ - Automatically configures your Lambda functions to run in your default VPC with full internet access
354
328
 
355
329
  ### KMS Support
356
330
 
@@ -358,31 +332,35 @@ Additional permissions needed when your app definition includes `encryption: { u
358
332
 
359
333
  ```json
360
334
  {
361
- "Version": "2012-10-17",
362
- "Statement": [
363
- {
364
- "Sid": "FriggKMSEncryptionRuntime",
365
- "Effect": "Allow",
366
- "Action": ["kms:GenerateDataKey", "kms:Decrypt"],
367
- "Resource": ["arn:aws:kms:*:*:key/*"],
368
- "Condition": {
369
- "StringEquals": {
370
- "kms:ViaService": [
371
- "lambda.*.amazonaws.com",
372
- "s3.*.amazonaws.com"
373
- ]
374
- }
375
- }
335
+ "Version": "2012-10-17",
336
+ "Statement": [
337
+ {
338
+ "Sid": "FriggKMSEncryptionRuntime",
339
+ "Effect": "Allow",
340
+ "Action": [
341
+ "kms:GenerateDataKey",
342
+ "kms:Decrypt"
343
+ ],
344
+ "Resource": [
345
+ "arn:aws:kms:*:*:key/*"
346
+ ],
347
+ "Condition": {
348
+ "StringEquals": {
349
+ "kms:ViaService": [
350
+ "lambda.*.amazonaws.com",
351
+ "s3.*.amazonaws.com"
352
+ ]
376
353
  }
377
- ]
354
+ }
355
+ }
356
+ ]
378
357
  }
379
358
  ```
380
359
 
381
360
  **What this enables:**
382
-
383
- - Lambda functions can encrypt and decrypt data using your default KMS key
384
- - Automatic discovery and configuration of customer-managed KMS keys
385
- - Fallback to AWS-managed keys if no customer keys are available
361
+ - Lambda functions can encrypt and decrypt data using your default KMS key
362
+ - Automatic discovery and configuration of customer-managed KMS keys
363
+ - Fallback to AWS-managed keys if no customer keys are available
386
364
 
387
365
  ### SSM Parameter Store Support
388
366
 
@@ -390,30 +368,29 @@ Additional permissions needed when your app definition includes `ssm: { enable:
390
368
 
391
369
  ```json
392
370
  {
393
- "Version": "2012-10-17",
394
- "Statement": [
395
- {
396
- "Sid": "FriggSSMParameterAccess",
397
- "Effect": "Allow",
398
- "Action": [
399
- "ssm:GetParameter",
400
- "ssm:GetParameters",
401
- "ssm:GetParametersByPath"
402
- ],
403
- "Resource": [
404
- "arn:aws:ssm:*:*:parameter/*frigg*",
405
- "arn:aws:ssm:*:*:parameter/*frigg*/*"
406
- ]
407
- }
408
- ]
371
+ "Version": "2012-10-17",
372
+ "Statement": [
373
+ {
374
+ "Sid": "FriggSSMParameterAccess",
375
+ "Effect": "Allow",
376
+ "Action": [
377
+ "ssm:GetParameter",
378
+ "ssm:GetParameters",
379
+ "ssm:GetParametersByPath"
380
+ ],
381
+ "Resource": [
382
+ "arn:aws:ssm:*:*:parameter/*frigg*",
383
+ "arn:aws:ssm:*:*:parameter/*frigg*/*"
384
+ ]
385
+ }
386
+ ]
409
387
  }
410
388
  ```
411
389
 
412
390
  **What this enables:**
413
-
414
- - Lambda functions can retrieve configuration from SSM Parameter Store
415
- - Automatic configuration of AWS Parameters and Secrets Lambda Extension layer
416
- - Secure environment variable management through SSM
391
+ - Lambda functions can retrieve configuration from SSM Parameter Store
392
+ - Automatic configuration of AWS Parameters and Secrets Lambda Extension layer
393
+ - Secure environment variable management through SSM
417
394
 
418
395
  ## Complete Policy Template
419
396
 
@@ -421,65 +398,63 @@ For convenience, here's a single IAM policy that includes all permissions needed
421
398
 
422
399
  ```json
423
400
  {
424
- "Version": "2012-10-17",
425
- "Statement": [
426
- {
427
- "Sid": "FriggCorePermissions",
428
- "Effect": "Allow",
429
- "Action": [
430
- "sts:GetCallerIdentity",
431
- "cloudformation:*",
432
- "lambda:*",
433
- "apigateway:GET",
434
- "apigateway:POST",
435
- "apigateway:PUT",
436
- "apigateway:DELETE",
437
- "apigateway:PATCH",
438
- "logs:*",
439
- "sqs:*",
440
- "sns:*",
441
- "cloudwatch:*",
442
- "ec2:Describe*",
443
- "ec2:CreateVpcEndpoint",
444
- "ec2:DeleteVpcEndpoint",
445
- "ec2:ModifyVpcEndpoint",
446
- "kms:ListKeys",
447
- "kms:DescribeKey",
448
- "kms:GenerateDataKey",
449
- "kms:Decrypt",
450
- "ssm:GetParameter*"
451
- ],
452
- "Resource": "*"
453
- },
454
- {
455
- "Sid": "S3DeploymentBuckets",
456
- "Effect": "Allow",
457
- "Action": ["s3:*"],
458
- "Resource": [
459
- "arn:aws:s3:::*serverless*",
460
- "arn:aws:s3:::*serverless*/*"
461
- ]
462
- },
463
- {
464
- "Sid": "IAMRoleManagement",
465
- "Effect": "Allow",
466
- "Action": [
467
- "iam:CreateRole",
468
- "iam:DeleteRole",
469
- "iam:GetRole",
470
- "iam:PassRole",
471
- "iam:PutRolePolicy",
472
- "iam:DeleteRolePolicy",
473
- "iam:GetRolePolicy",
474
- "iam:AttachRolePolicy",
475
- "iam:DetachRolePolicy",
476
- "iam:TagRole",
477
- "iam:UntagRole",
478
- "iam:ListPolicyVersions"
479
- ],
480
- "Resource": "arn:aws:iam::*:role/*"
481
- }
482
- ]
401
+ "Version": "2012-10-17",
402
+ "Statement": [
403
+ {
404
+ "Sid": "FriggCorePermissions",
405
+ "Effect": "Allow",
406
+ "Action": [
407
+ "sts:GetCallerIdentity",
408
+ "cloudformation:*",
409
+ "lambda:*",
410
+ "apigateway:*",
411
+ "logs:*",
412
+ "sqs:*",
413
+ "sns:*",
414
+ "cloudwatch:*",
415
+ "ec2:Describe*",
416
+ "ec2:CreateVpcEndpoint",
417
+ "ec2:DeleteVpcEndpoint",
418
+ "ec2:ModifyVpcEndpoint",
419
+ "kms:ListKeys",
420
+ "kms:DescribeKey",
421
+ "kms:GenerateDataKey",
422
+ "kms:Decrypt",
423
+ "ssm:GetParameter*"
424
+ ],
425
+ "Resource": "*"
426
+ },
427
+ {
428
+ "Sid": "S3DeploymentBuckets",
429
+ "Effect": "Allow",
430
+ "Action": [
431
+ "s3:*"
432
+ ],
433
+ "Resource": [
434
+ "arn:aws:s3:::*serverless*",
435
+ "arn:aws:s3:::*serverless*/*"
436
+ ]
437
+ },
438
+ {
439
+ "Sid": "IAMRoleManagement",
440
+ "Effect": "Allow",
441
+ "Action": [
442
+ "iam:CreateRole",
443
+ "iam:DeleteRole",
444
+ "iam:GetRole",
445
+ "iam:PassRole",
446
+ "iam:PutRolePolicy",
447
+ "iam:DeleteRolePolicy",
448
+ "iam:GetRolePolicy",
449
+ "iam:AttachRolePolicy",
450
+ "iam:DetachRolePolicy",
451
+ "iam:TagRole",
452
+ "iam:UntagRole",
453
+ "iam:ListPolicyVersions"
454
+ ],
455
+ "Resource": "arn:aws:iam::*:role/*"
456
+ }
457
+ ]
483
458
  }
484
459
  ```
485
460
 
@@ -490,13 +465,11 @@ For convenience, here's a single IAM policy that includes all permissions needed
490
465
  This policy has been updated to follow the principle of least privilege by scoping permissions to Frigg-specific resources:
491
466
 
492
467
  **Before (Overly Broad):**
493
-
494
468
  ```json
495
469
  "Resource": "*" // ❌ Too permissive
496
470
  ```
497
471
 
498
472
  **After (Frigg-Specific):**
499
-
500
473
  ```json
501
474
  "Resource": [
502
475
  "arn:aws:lambda:*:*:function:*frigg*" // ✅ Only functions containing "frigg"
@@ -518,17 +491,15 @@ This policy has been updated to follow the principle of least privilege by scopi
518
491
  For these permissions to work properly, ensure your Frigg applications follow the naming convention of including "frigg" in resource names:
519
492
 
520
493
  ✅ **Good Examples:**
521
-
522
- - `my-frigg-app-dev` (CloudFormation stack)
523
- - `integration-frigg-service-auth` (Lambda function)
524
- - `customer-frigg-platform-prod-auth` (Lambda function)
525
- - `/my-frigg-app/prod/database-url` (SSM parameter)
526
- - `internal-error-queue-dev` (SQS queue - special pattern for error queues)
494
+ - `my-frigg-app-dev` (CloudFormation stack)
495
+ - `integration-frigg-service-auth` (Lambda function)
496
+ - `customer-frigg-platform-prod-auth` (Lambda function)
497
+ - `/my-frigg-app/prod/database-url` (SSM parameter)
498
+ - `internal-error-queue-dev` (SQS queue - special pattern for error queues)
527
499
 
528
500
  ❌ **Won't Match:**
529
-
530
- - `my-integration-app-dev` (no "frigg" in name)
531
- - `customer-platform-prod` (no "frigg" in name)
501
+ - `my-integration-app-dev` (no "frigg" in name)
502
+ - `customer-platform-prod` (no "frigg" in name)
532
503
 
533
504
  **Note:** The `internal-error-queue-*` pattern is specifically allowed for error handling queues.
534
505
 
@@ -548,10 +519,10 @@ You can further restrict permissions by:
548
519
 
549
520
  ```json
550
521
  {
551
- "Resource": [
552
- "arn:aws:cloudformation:us-east-1:YOUR-ACCOUNT-ID:stack/your-app-*/*",
553
- "arn:aws:lambda:us-east-1:YOUR-ACCOUNT-ID:function:your-app-*"
554
- ]
522
+ "Resource": [
523
+ "arn:aws:cloudformation:us-east-1:YOUR-ACCOUNT-ID:stack/your-app-*/*",
524
+ "arn:aws:lambda:us-east-1:YOUR-ACCOUNT-ID:function:your-app-*"
525
+ ]
555
526
  }
556
527
  ```
557
528
 
@@ -559,15 +530,15 @@ You can further restrict permissions by:
559
530
 
560
531
  The discovery process sets these environment variables during build:
561
532
 
562
- - `AWS_DISCOVERY_VPC_ID` - Your default VPC ID
563
- - `AWS_DISCOVERY_SECURITY_GROUP_ID` - Default security group ID
564
- - `AWS_DISCOVERY_SUBNET_ID_1` - First private subnet ID (for Lambda functions)
565
- - `AWS_DISCOVERY_SUBNET_ID_2` - Second private subnet ID (for Lambda functions, or same as first if only one exists)
566
- - `AWS_DISCOVERY_PUBLIC_SUBNET_ID` - Public subnet ID (for NAT Gateway placement)
567
- - `AWS_DISCOVERY_ROUTE_TABLE_ID` - Private route table ID for VPC endpoints
568
- - `AWS_DISCOVERY_KMS_KEY_ID` - Default KMS key ARN
569
- - `AWS_DISCOVERY_NAT_GATEWAY_ID` - Existing NAT Gateway ID (if found)
570
- - `AWS_DISCOVERY_ELASTIC_IP_ALLOCATION_ID` - Existing Elastic IP allocation ID (if found)
533
+ - `AWS_DISCOVERY_VPC_ID` - Your default VPC ID
534
+ - `AWS_DISCOVERY_SECURITY_GROUP_ID` - Default security group ID
535
+ - `AWS_DISCOVERY_SUBNET_ID_1` - First private subnet ID (for Lambda functions)
536
+ - `AWS_DISCOVERY_SUBNET_ID_2` - Second private subnet ID (for Lambda functions, or same as first if only one exists)
537
+ - `AWS_DISCOVERY_PUBLIC_SUBNET_ID` - Public subnet ID (for NAT Gateway placement)
538
+ - `AWS_DISCOVERY_ROUTE_TABLE_ID` - Private route table ID for VPC endpoints
539
+ - `AWS_DISCOVERY_KMS_KEY_ID` - Default KMS key ARN
540
+ - `AWS_DISCOVERY_NAT_GATEWAY_ID` - Existing NAT Gateway ID (if found)
541
+ - `AWS_DISCOVERY_ELASTIC_IP_ALLOCATION_ID` - Existing Elastic IP allocation ID (if found)
571
542
 
572
543
  ## Troubleshooting
573
544
 
@@ -586,19 +557,17 @@ The discovery process sets these environment variables during build:
586
557
  ### Fallback Behavior
587
558
 
588
559
  If AWS discovery fails during build, the framework will:
589
-
590
- - Log a warning message
591
- - Set fallback environment variables
592
- - Continue with deployment using safe default values
593
- - Not fail the build process
560
+ - Log a warning message
561
+ - Set fallback environment variables
562
+ - Continue with deployment using safe default values
563
+ - Not fail the build process
594
564
 
595
565
  ### Regional Considerations
596
566
 
597
567
  Ensure your IAM policy includes permissions for the AWS region where you're deploying:
598
-
599
- - Discovery permissions work across all regions (use `*` in resource ARNs)
600
- - Deployment permissions should match your target region
601
- - Some services like IAM are global, others are region-specific
568
+ - Discovery permissions work across all regions (use `*` in resource ARNs)
569
+ - Deployment permissions should match your target region
570
+ - Some services like IAM are global, others are region-specific
602
571
 
603
572
  ## Using with CI/CD
604
573
 
@@ -615,13 +584,13 @@ Example GitHub Actions configuration:
615
584
  - name: Configure AWS credentials
616
585
  uses: aws-actions/configure-aws-credentials@v1
617
586
  with:
618
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
619
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
620
- aws-region: us-east-1
587
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
588
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
589
+ aws-region: us-east-1
621
590
 
622
591
  - name: Deploy Frigg App
623
592
  run: |
624
- frigg deploy
593
+ frigg deploy
625
594
  ```
626
595
 
627
- This policy ensures your Frigg application can successfully discover AWS resources during build time and deploy all necessary infrastructure components during deployment.
596
+ This policy ensures your Frigg application can successfully discover AWS resources during build time and deploy all necessary infrastructure components during deployment.