-
Notifications
You must be signed in to change notification settings - Fork 0
/
cloudformation.yaml
249 lines (230 loc) · 9.35 KB
/
cloudformation.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
AWSTemplateFormatVersion: '2010-09-09'
Description:
AWS CloudFormation Template for the eReefs Download Manager.
Parameters:
Environment:
Type: String
Default: "test"
Description: >
A unique name for the environment within the target account. This could be generic, such as "test" or "prod",
or it could be specific to a developer, such as "asmith".
EcrUserId:
Type: String
Default: "jenkins-ereefs-test-download_manager" # This value is changed by the Jenkinsfile when pushing to production
Description: >
The id of the user that will push Docker images to the AWS ECR.
LambdaMd5sum:
Type: String
Default: ""
Description: >
MD5sum of the zip archive containing the lambda function for the SNS listener.
Conditions:
IsProdEnv: {
"Fn::Equals": [ { "Ref": "Environment" }, "prod" ]
}
Resources:
JobDefinitionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: downloadManagerPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:*
Resource: "*"
- Effect: Allow
Action:
- "ssm:Describe*"
- "ssm:Get*"
- "ssm:List*"
Resource: "*"
- Effect: Allow
Action:
- sns:*
Resource:
- Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadCompletedTopic"
- Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsAllDownloadCompletedTopic"
- Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsAdministration"
JobDefinition:
Type: 'AWS::Batch::JobDefinition'
Properties:
Type: container
JobDefinitionName: !Sub 'ereefs-download_manager-${Environment}'
ContainerProperties:
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/ereefs-download_manager-${Environment}'
JobRoleArn: !Ref JobDefinitionRole
Vcpus: 1
Memory: 15000
Environment:
-
Name: 'EXECUTION_ENVIRONMENT'
Value: !Ref Environment
-
Name: 'DOWNLOAD_COMPLETE_TOPIC_ARN'
Value:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadCompletedTopic"
-
Name: 'ALL_DOWNLOAD_COMPLETE_TOPIC_ARN'
Value:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsAllDownloadCompletedTopic"
-
Name: 'ADMINISTRATION_TOPIC_ARN'
Value:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsAdministration"
RetryStrategy:
Attempts: 1
ElasticContainerRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Sub 'ereefs-download_manager-${Environment}'
RepositoryPolicyText:
Version: '2012-10-17'
Statement:
- Sid: AllowPush
Effect: Allow
Principal:
AWS:
- 'Fn::Join':
- ':'
- - 'arn:aws:iam:'
- Ref: 'AWS::AccountId'
- !Sub 'user/${EcrUserId}'
Action:
- 'ecr:PutImage'
- 'ecr:InitiateLayerUpload'
- 'ecr:UploadLayerPart'
- 'ecr:CompleteLayerUpload'
# Call workflow
# 1. A SNS message is sent to the ereefs-download_request
# 2. The Lambda function DownloadManagerSNSListener listen to the event sent to that topic
# 3. When a request message is sent, the Lambda function create a new Job
# Create the role for the Lambda Function ereefs-download-manager-sns-listener
LambdaSNSListenerRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: downloadManagerSNSListenerPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:*
Resource:
- "arn:aws:logs:*:*:*"
- Effect: Allow
Action:
- "batch:*"
Resource: "*"
# Create the Lambda Function ereefs-download-manager-sns-listener (empty container) which will be filled by Jenkins
# NOTE: It seems like it's not possible to create a "test event" through CloudFormation
# https://stackoverflow.com/questions/51783194/how-to-describe-aws-lambda-function-test-events-in-cloudformation-template
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
LambdaSNSListener:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: !Sub "ereefs-download-manager-${Environment}-sns-listener"
Handler: "index.handler"
Role: !GetAtt [ LambdaSNSListenerRole, Arn ]
Environment:
Variables:
JOB_QUEUE_ARN:
Fn::ImportValue:
!Sub "definitions-batch-${Environment}-ManagementJobQueue"
JOB_DEFINITION_ARN: !Ref JobDefinition
Code:
S3Bucket:
Fn::ImportValue: !Sub "definitions-s3-${Environment}-PrivateBucketName"
S3Key: !Sub "deploy/download-manager/lambda/sns-listener-deploy-${LambdaMd5sum}.zip"
Runtime: "nodejs18.x"
Timeout: 25
# Create an alias for the Lambda function (for the SNS subscription)
# NOTE: It's good practice to subscribe function aliases to SNS Topics instead of the function itself,
# in case we want to switch it to a different version of the function.
# It's a feature that we will probably never use (our versioning is done in Git),
# and aliases hides the SNS association in the user interface, which creates confusion.
# https://stackoverflow.com/questions/48898995/triggering-a-lambda-from-sns-using-cloud-formation
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-alias.html
# NOTE: Alias are found in AWS console > Services > Compute > Lambda, menu Qualifiers, tab Aliases
#LambdaSNSListenerAlias:
# Type: AWS::Lambda::Alias
# Properties:
# FunctionName: !Ref LambdaSNSListener
# FunctionVersion: '$LATEST'
# Name: lambdaSNSListenerAlias
# Add permission to trigger a Lambda function from a SNS topic
# https://aws.amazon.com/premiumsupport/knowledge-center/lambda-subscribe-push-cloudformation/
LambdaSNSListenerInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadRequestTopic"
FunctionName: !GetAtt [ LambdaSNSListener, Arn ]
# SNS subscription - Register LambdaSNSListener Lambda function to download-request SNS (defined in ereefs-definitions project)
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-subscription.html
LambdaSNSListenerSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadRequestTopic"
Protocol: lambda
Endpoint: !GetAtt [ LambdaSNSListener, Arn ]
# CloudWatch rule to publish messages to the SNS topic "download-request"
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html
CloudWatchCronJob:
Type: AWS::Events::Rule
Properties:
Name: !Sub "ereefs-download_manager-lambda-sns-listener-rule-${Environment}"
Description: "CloudWatch rule which periodically create SNS message to trigger the SNS listener Lambda function which trigger the ereefs-download_manager docker container image"
ScheduleExpression: "cron(0 14 ? * 3 *)" # Trigger every Tuesday at 14:00UTC
State: "DISABLED"
Targets:
-
Id: "ereefs-download_manager-cron-job"
Arn:
Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadRequestTopic"
Input: !If [ IsProdEnv, '{ "limit": -1, "dryRun": false }', '{ "limit": 2, "dryRun": false }' ]
# Give permission to CloudWatch (in general) to publish to the SNS topic "download-request"
CloudWatchCronJobPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: 'sns:Publish'
Resource: '*'
Topics:
- Fn::ImportValue:
!Sub "definitions-sns-${Environment}-SNSTopicEReefsDownloadRequestTopic"