@friggframework/devtools 2.0.0-next.32 → 2.0.0-next.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frigg-cli/deploy-command/index.js +6 -3
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +442 -411
- package/infrastructure/GENERATE-IAM-DOCS.md +91 -66
- package/infrastructure/frigg-deployment-iam-stack.yaml +22 -0
- package/infrastructure/iam-generator.js +212 -229
- package/infrastructure/iam-policy-basic.json +2 -0
- package/infrastructure/iam-policy-full.json +2 -0
- package/infrastructure/serverless-template.js +412 -243
- package/package.json +6 -6
|
@@ -17,38 +17,39 @@ These permissions are required when `aws-discovery.js` runs during the build to
|
|
|
17
17
|
|
|
18
18
|
```json
|
|
19
19
|
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
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
|
|
52
53
|
|
|
53
54
|
## Core Deployment Permissions
|
|
54
55
|
|
|
@@ -56,214 +57,236 @@ Required for basic Frigg application deployment:
|
|
|
56
57
|
|
|
57
58
|
```json
|
|
58
59
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
+
]
|
|
254
262
|
}
|
|
255
263
|
```
|
|
256
264
|
|
|
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
|
+
|
|
257
279
|
**What the Lambda permissions enable:**
|
|
258
|
-
|
|
259
|
-
-
|
|
260
|
-
-
|
|
261
|
-
-
|
|
262
|
-
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
|
267
290
|
|
|
268
291
|
## Feature-Specific Permissions
|
|
269
292
|
|
|
@@ -273,58 +296,61 @@ Additional permissions needed when your app definition includes `vpc: { enable:
|
|
|
273
296
|
|
|
274
297
|
```json
|
|
275
298
|
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
+
}
|
|
316
343
|
}
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
]
|
|
344
|
+
]
|
|
320
345
|
}
|
|
321
346
|
```
|
|
322
347
|
|
|
323
348
|
**What this enables:**
|
|
324
|
-
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
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
|
|
328
354
|
|
|
329
355
|
### KMS Support
|
|
330
356
|
|
|
@@ -332,35 +358,31 @@ Additional permissions needed when your app definition includes `encryption: { u
|
|
|
332
358
|
|
|
333
359
|
```json
|
|
334
360
|
{
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
"lambda.*.amazonaws.com",
|
|
351
|
-
"s3.*.amazonaws.com"
|
|
352
|
-
]
|
|
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
|
+
}
|
|
353
376
|
}
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
]
|
|
377
|
+
]
|
|
357
378
|
}
|
|
358
379
|
```
|
|
359
380
|
|
|
360
381
|
**What this enables:**
|
|
361
|
-
|
|
362
|
-
-
|
|
363
|
-
-
|
|
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
|
|
364
386
|
|
|
365
387
|
### SSM Parameter Store Support
|
|
366
388
|
|
|
@@ -368,29 +390,30 @@ Additional permissions needed when your app definition includes `ssm: { enable:
|
|
|
368
390
|
|
|
369
391
|
```json
|
|
370
392
|
{
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
+
]
|
|
387
409
|
}
|
|
388
410
|
```
|
|
389
411
|
|
|
390
412
|
**What this enables:**
|
|
391
|
-
|
|
392
|
-
-
|
|
393
|
-
-
|
|
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
|
|
394
417
|
|
|
395
418
|
## Complete Policy Template
|
|
396
419
|
|
|
@@ -398,63 +421,65 @@ For convenience, here's a single IAM policy that includes all permissions needed
|
|
|
398
421
|
|
|
399
422
|
```json
|
|
400
423
|
{
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
+
]
|
|
458
483
|
}
|
|
459
484
|
```
|
|
460
485
|
|
|
@@ -465,11 +490,13 @@ For convenience, here's a single IAM policy that includes all permissions needed
|
|
|
465
490
|
This policy has been updated to follow the principle of least privilege by scoping permissions to Frigg-specific resources:
|
|
466
491
|
|
|
467
492
|
**Before (Overly Broad):**
|
|
493
|
+
|
|
468
494
|
```json
|
|
469
495
|
"Resource": "*" // ❌ Too permissive
|
|
470
496
|
```
|
|
471
497
|
|
|
472
498
|
**After (Frigg-Specific):**
|
|
499
|
+
|
|
473
500
|
```json
|
|
474
501
|
"Resource": [
|
|
475
502
|
"arn:aws:lambda:*:*:function:*frigg*" // ✅ Only functions containing "frigg"
|
|
@@ -491,15 +518,17 @@ This policy has been updated to follow the principle of least privilege by scopi
|
|
|
491
518
|
For these permissions to work properly, ensure your Frigg applications follow the naming convention of including "frigg" in resource names:
|
|
492
519
|
|
|
493
520
|
✅ **Good Examples:**
|
|
494
|
-
|
|
495
|
-
-
|
|
496
|
-
-
|
|
497
|
-
-
|
|
498
|
-
-
|
|
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)
|
|
499
527
|
|
|
500
528
|
❌ **Won't Match:**
|
|
501
|
-
|
|
502
|
-
-
|
|
529
|
+
|
|
530
|
+
- `my-integration-app-dev` (no "frigg" in name)
|
|
531
|
+
- `customer-platform-prod` (no "frigg" in name)
|
|
503
532
|
|
|
504
533
|
**Note:** The `internal-error-queue-*` pattern is specifically allowed for error handling queues.
|
|
505
534
|
|
|
@@ -519,10 +548,10 @@ You can further restrict permissions by:
|
|
|
519
548
|
|
|
520
549
|
```json
|
|
521
550
|
{
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
+
]
|
|
526
555
|
}
|
|
527
556
|
```
|
|
528
557
|
|
|
@@ -530,15 +559,15 @@ You can further restrict permissions by:
|
|
|
530
559
|
|
|
531
560
|
The discovery process sets these environment variables during build:
|
|
532
561
|
|
|
533
|
-
-
|
|
534
|
-
-
|
|
535
|
-
-
|
|
536
|
-
-
|
|
537
|
-
-
|
|
538
|
-
-
|
|
539
|
-
-
|
|
540
|
-
-
|
|
541
|
-
-
|
|
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)
|
|
542
571
|
|
|
543
572
|
## Troubleshooting
|
|
544
573
|
|
|
@@ -557,17 +586,19 @@ The discovery process sets these environment variables during build:
|
|
|
557
586
|
### Fallback Behavior
|
|
558
587
|
|
|
559
588
|
If AWS discovery fails during build, the framework will:
|
|
560
|
-
|
|
561
|
-
-
|
|
562
|
-
-
|
|
563
|
-
-
|
|
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
|
|
564
594
|
|
|
565
595
|
### Regional Considerations
|
|
566
596
|
|
|
567
597
|
Ensure your IAM policy includes permissions for the AWS region where you're deploying:
|
|
568
|
-
|
|
569
|
-
-
|
|
570
|
-
-
|
|
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
|
|
571
602
|
|
|
572
603
|
## Using with CI/CD
|
|
573
604
|
|
|
@@ -584,13 +615,13 @@ Example GitHub Actions configuration:
|
|
|
584
615
|
- name: Configure AWS credentials
|
|
585
616
|
uses: aws-actions/configure-aws-credentials@v1
|
|
586
617
|
with:
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
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
|
|
590
621
|
|
|
591
622
|
- name: Deploy Frigg App
|
|
592
623
|
run: |
|
|
593
|
-
|
|
624
|
+
frigg deploy
|
|
594
625
|
```
|
|
595
626
|
|
|
596
|
-
This policy ensures your Frigg application can successfully discover AWS resources during build time and deploy all necessary infrastructure components during deployment.
|
|
627
|
+
This policy ensures your Frigg application can successfully discover AWS resources during build time and deploy all necessary infrastructure components during deployment.
|