-
Notifications
You must be signed in to change notification settings - Fork 7
/
central-aggregator-cf-template.yaml
executable file
·400 lines (378 loc) · 13.1 KB
/
central-aggregator-cf-template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: >-
Deploy pipeline for support cases aggregation
#===================================================================================
# Parameters MUST be updated; bucket name MUST BE UNIQUE and AVAILABLE
#===================================================================================
Parameters:
# specifying bucket name as parameter is necessary to avoid circular dependency
CloudTrailBucketName: # provide name of your choice for bucket during CloudFormation stack creation time
Type: String
OrgSupportViewerRoleArn:
Type: String
Default: "arn:aws:iam::*:role/GetSupportInfoRole"
OrgListAccountsViewerRoleArn:
Type: String
Default: "" # If org master is separate account, provide role arn with perms to list accounts
SupportCasesDDBTableName:
Type: String
Default: "support-cases"
Conditions: # evaluated only during create stack
OrgListAccountsViewerRoleArnExists: !Not [!Equals [!Ref OrgListAccountsViewerRoleArn, "" ]]
OrgListAccountsViewerRoleArnDoesNotExists: !Equals [!Ref OrgListAccountsViewerRoleArn, "" ]
#==================================================
# Resources
#==================================================
Resources:
#==================================================
# DynamoDB
#==================================================
# Support Cases extension
SupportCasesTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain # retaining DDB after stack deletion
Properties:
AttributeDefinitions:
-
AttributeName: caseId
AttributeType: S
KeySchema:
-
AttributeName: caseId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
TableName: !Ref SupportCasesDDBTableName
#==================================================
# Managed IAM Policies
#==================================================
InvokeCoreLambdas:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Allows invoking of core Lambda functions."
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- lambda:InvokeFunction
- lambda:GetFunction
Resource: !Join ['', ['arn:aws:lambda:*:', !Ref 'AWS::AccountId', ':function:*']]
ManagedPolicyName: "InvokeCoreLambdas"
PublishToDeadLetterQueue:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Allows publishing to Dead Letter Queue."
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- sns:Publish
- sns:Subscribe
- sns:ConfirmSubscription
- sns:Unsubscribe
Resource: !Ref DefaultDeadLetterQueue
ManagedPolicyName: "PublishToDeadLetterQueue"
GetS3CloudTrailObjects:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Retrieve objects from S3 CloudTrail bucket"
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectAcl
- s3:GetBucketAcl
Resource:
- !Join ['', ['arn:aws:s3:::', !Ref 'CloudTrailBucketName']]
- !Join ['', ['arn:aws:s3:::', !Ref 'CloudTrailBucketName', '/*']]
ManagedPolicyName: "GetS3CloudTrailObjects"
AssumeOrgMasterListAccountsViewerPolicy:
Type: AWS::IAM::ManagedPolicy
Condition: OrgListAccountsViewerRoleArnExists
Properties:
Description: "Allows central aggregator account to assume org master role"
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- sts:AssumeRole
Resource: !Ref OrgListAccountsViewerRoleArn
ManagedPolicyName: "AssumeOrgMasterListAccountsViewerPolicy"
Roles:
- !Ref SupportAggregator
ListAccountsViewerPolicy:
Type: AWS::IAM::ManagedPolicy
Condition: OrgListAccountsViewerRoleArnDoesNotExists
Properties:
Description: "Allows central aggregator account to list accounts"
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "organizations:ListAccounts"
Resource: "*"
ManagedPolicyName: "ListAccountsViewerPolicy"
Roles:
- !Ref SupportAggregator
#==================================================
# IAMRoles and IAM Inline Policies
#==================================================
ProcessCloudTrailS3NotifRole:
Type: AWS::IAM::Role
Properties:
RoleName: "ProcessCloudTrailS3Notif"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- !Ref InvokeCoreLambdas
- !Ref PublishToDeadLetterQueue
- !Ref GetS3CloudTrailObjects
Path: "/"
# Support case roles
SupportAggregator:
Type: AWS::IAM::Role
Properties:
RoleName: "SupportAggregator"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
- !Ref PublishToDeadLetterQueue
Path: "/"
Policies:
-
PolicyName: "assume-org-support-viewer"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- sts:AssumeRole
Resource: !Ref OrgSupportViewerRoleArn
-
PolicyName: "manage-support-cases-table"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:DeleteItem
- dynamodb:BatchWriteItem
- dynamodb:Scan
Resource:
- !GetAtt SupportCasesTable.Arn
- !Join ['', [!GetAtt 'SupportCasesTable.Arn', '/*']]
#==================================================
# SNS Topics
#==================================================
## SNS Topic Policies hard code S3 bucket names rather than use !Ref because of this:
## https://aws.amazon.com/premiumsupport/knowledge-center/unable-validate-destination-s3/
DefaultDeadLetterQueue:
Type: AWS::SNS::Topic
Properties:
DisplayName: "SupportDLQ"
TopicName: support-dead-letter-queues
CloudTrailChangesAllAccountsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: cloud-trail-changes
CloudTrailChangesAllAccountsTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref CloudTrailChangesAllAccountsTopic
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Sid: AllowS3Publish
Effect: "Allow"
Action:
- sns:Publish
Principal:
AWS: "*"
Resource: !Ref CloudTrailChangesAllAccountsTopic
Condition:
ArnLike:
aws:SourceArn: !Join ['', ['arn:aws:s3:::', !Ref CloudTrailBucketName]]
-
Sid: AllowAccountSubscription
Effect: "Allow"
Action:
- sns:Subscribe
Principal:
AWS: !Join ['', ['arn:aws:iam::', !Ref 'AWS::AccountId', ':root']]
Resource: !Ref CloudTrailChangesAllAccountsTopic
-
Sid: "__default_statement_ID"
Effect: "Allow"
Principal:
AWS: "*"
Action:
- sns:GetTopicAttributes
- sns:SetTopicAttributes
- sns:AddPermission
- sns:RemovePermission
- sns:DeleteTopic
- sns:Subscribe
- sns:ListSubscriptionsByTopic
- sns:Publish
- sns:Receive
Resource: !Ref CloudTrailChangesAllAccountsTopic
Condition:
StringEquals:
AWS:SourceOwner: !Ref 'AWS::AccountId'
#==================================================
# S3 buckets
#==================================================
CloudTrailBucket:
Type: AWS::S3::Bucket
Properties:
# specifying bucket name is necessary to avoid circular dependency
# as the CloudTrailChangesAllAccountsTopic must allow the CloudTrail bucket to access it
BucketName: !Ref CloudTrailBucketName
NotificationConfiguration:
TopicConfigurations:
-
Event: s3:ObjectCreated:*
Topic: !Ref CloudTrailChangesAllAccountsTopic
AccessControl: Private
# Must wait for topic policy to be initialized first before topic configuration can be created
DependsOn: CloudTrailChangesAllAccountsTopicPolicy
CloudTrailBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref CloudTrailBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Sid: AllowS3Publish
Effect: "Allow"
Principal:
Service: "cloudtrail.amazonaws.com"
Action:
- s3:PutObject
- s3:PutObjectAcl
Resource: !Join ['', ['arn:aws:s3:::', !Ref 'CloudTrailBucketName', '/*']]
-
Sid: AllowS3PermissionCheck
Effect: "Allow"
Principal:
Service: "cloudtrail.amazonaws.com"
Action:
- s3:GetBucketAcl
Resource: !Join ['', ['arn:aws:s3:::', !Ref 'CloudTrailBucketName']]
#==================================================
# Lambda functions
#==================================================
cloudtrailprocess:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: cloudtrail-process
Handler: cloudtrail_process.lambda_handler
Runtime: python3.8
CodeUri: ./build/cloudtrail_process.py
Layers:
- !Ref SupportCasesAggregatorBaseLayer
Description: >-
This lambda function will take in an S3 notification from the CloudTrail bucket via SNS topic,
fetch S3 object, process it and invoke support-cases-aggregator function.
MemorySize: 128
Timeout: 180
Role: !GetAtt ProcessCloudTrailS3NotifRole.Arn
DeadLetterQueue:
Type: SNS
TargetArn: !Ref DefaultDeadLetterQueue
Events:
CloudTrailTriggerSNS:
Type: SNS
Properties:
Topic: !Ref CloudTrailChangesAllAccountsTopic
Environment:
Variables:
LOGGING_LEVEL: INFO
SUPPORT_CASES_AGGREGATOR_LAMBDA_NAME: !Ref supportupdater
supportupdater:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: support-cases-aggregator
Handler: support_cases_aggregator.lambda_handler
Runtime: python3.8
CodeUri: ./build/support_cases_aggregator.py
Layers:
- !Ref SupportCasesAggregatorBaseLayer
Description: >-
This lambda function retrieves information for a given case and dumps it into a DynamoDB table.
MemorySize: 128
Timeout: 600
Role: !GetAtt SupportAggregator.Arn
DeadLetterQueue:
Type: SNS
TargetArn: !Ref DefaultDeadLetterQueue
Events:
ScheduleTwiceWeeklySyncCheck:
Type: Schedule
Properties:
Schedule: rate(3 days)
ReservedConcurrentExecutions: 1
Environment:
Variables:
LOGGING_LEVEL: INFO
ORG_MASTER_ACCOUNT_VIEWER_ROLE: !Ref OrgListAccountsViewerRoleArn
SUPPORT_CASES_TABLE_NAME: !Ref SupportCasesDDBTableName
SupportCasesAggregatorBaseLayer:
Type: AWS::Serverless::LayerVersion
Properties:
Description: Lambda Layer for basic utilities and dependencies used by Support Cases Aggregator related functions.
ContentUri: layersbuild/
CompatibleRuntimes:
- python3.6
- python3.7
- python3.8
Outputs:
OrgListAccountsViewerRoleArnExists:
Description: Org list accounts role provided
Condition: OrgListAccountsViewerRoleArnExists
Value: "Environment setup with Central Aggregator account separate from AWS Organizations master account"
OrgListAccountsViewerRoleArnDoesNotExists:
Description: Org list accounts role not provided
Condition: OrgListAccountsViewerRoleArnDoesNotExists
Value: "Environment setup with AWS Organizations master account as Central Aggregator account"