commercetools CloudFormation Template
Essential knowledge
Author:
Fluent Commerce
Changed on:
31 Jan 2024
Overview
commercetools CloudFormation Template
Key points
- CloudFormation Template
1AWSTemplateFormatVersion: "2010-09-09"
2Description: "Fluentcommerce Connectors - Regional Deployment"
3
4Parameters:
5ConnectorName:
6Description: "Connector name"
7Type: String
8
9FluentAccount:
10Description: "Fluent Account name"
11Type: String
12
13RetailerId:
14Description: "Retailer Id"
15Type: Number
16
17Environment:
18Description: "Environment name"
19Type: String
20Default: test
21
22ImageURI:
23Description: "Fully qualified docker image URI to run"
24Type: String
25
26CPU:
27Description: Number of CPUs to assign to the task
28Type: Number
29Default: 512
30AllowedValues:
31- 256
32- 512
33- 1024
34
35Memory:
36Description: Amount of memory to assign to the task in GB
37Type: Number
38Default: 1024
39AllowedValues:
40- 512
41- 1024
42- 2048
43- 3072
44
45ContainerPort:
46Description: Container port to expose to load balancer
47Type: Number
48Default: 8080
49
50MinCapacity:
51Type: Number
52Default: 1
53
54MaxCapacity:
55Type: Number
56Default: 6
57
58VpcId:
59Description: VPC Id
60Type: AWS::EC2::VPC::Id
61
62VpcCidr:
63Description: VPC CIDR Block (eg 10.0.0.0/16)
64Type: String
65AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$'
66
67PublicHostedZoneName:
68Description: Public hosted zone (domain name)
69Type: String
70
71PublicHostedZoneId:
72Description: Public hosted zone id
73Type: String
74
75PublicSubnets:
76Description: Public Subnet IDs
77Type: List<AWS::EC2::Subnet::Id>
78
79PrivateSubnets:
80Description: Private Subnet IDs
81Type: List<AWS::EC2::Subnet::Id>
82
83BatchSQSQueueName:
84Description: Batch Queue Name
85Type: String
86Default: batch
87
88EventsSQSQueueName:
89Description: Events Queue Name
90Type: String
91Default: events
92
93ConnectorSQSQueueName:
94Description: Connector Queue Name
95Type: String
96Default: commercetools
97
98Mappings:
99RegionMap:
100us-east-1:
101RegionCode: use1
102us-east-2:
103RegionCode: use2
104us-west-1:
105RegionCode: usw1
106us-west-2:
107RegionCode: usw2
108af-south-1:
109RegionCode: afs1
110ap-east-1:
111RegionCode: ape1
112ap-south-1:
113RegionCode: aps1
114ap-northeast-1:
115RegionCode: apne1
116ap-northeast-2:
117RegionCode: apne2
118ap-northeast-3:
119RegionCode: apne3
120ap-southeast-1:
121RegionCode: apse1
122ap-southeast-2:
123RegionCode: apse2
124ap-southeast-3:
125RegionCode: apse3
126ca-central-1:
127RegionCode: cac1
128eu-central-1:
129RegionCode: euc1
130eu-west-1:
131RegionCode: euw1
132eu-west-2:
133RegionCode: euw2
134eu-west-3:
135RegionCode: euw3
136eu-south-1:
137RegionCode: eus1
138eu-north-1:
139RegionCode: eun1
140me-south-1:
141RegionCode: mes1
142me-central-1:
143RegionCode: mec1
144sa-east-1:
145RegionCode: sae1
146
147Resources:
148ALBSecurityGroup:
149Type: AWS::EC2::SecurityGroup
150Properties:
151GroupName: !Sub "${ConnectorName}-${Environment}-connectors-alb-sg"
152GroupDescription: !Sub "${Environment} ${AWS::Region} ${ConnectorName} connector load balancer Security Group"
153VpcId: !Ref VpcId
154SecurityGroupIngress:
155- IpProtocol: tcp
156FromPort: 443
157ToPort: 443
158CidrIp: 0.0.0.0/0
159Tags:
160- Key: Name
161Value: !Sub "${ConnectorName}-${Environment}-connectors-alb-sg"
162- Key: Region
163Value: !Ref AWS::Region
164
165ConnectorSecurityGroup:
166Type: AWS::EC2::SecurityGroup
167Properties:
168GroupName: !Sub ${Environment}-{ConnectorName}-connectors-sg
169GroupDescription: !Sub "${Environment} ${AWS::Region} ${ConnectorName} connector Security Group"
170VpcId: !Ref VpcId
171SecurityGroupIngress:
172- CidrIp: !Ref VpcCidr
173Description: "oms connectors access"
174FromPort: 443
175ToPort: 443
176IpProtocol: -1
177Tags:
178- Key: Name
179Value: !Sub "${ConnectorName}-${Environment}-connectors-sg"
180- Key: Region
181Value: !Ref AWS::Region
182
183LogGroup:
184Type: AWS::Logs::LogGroup
185Properties:
186RetentionInDays: 7
187LogGroupName: !Sub "/${ConnectorName}/${Environment}/connectors"
188
189LoadBalancer:
190Type: AWS::ElasticLoadBalancingV2::LoadBalancer
191Properties:
192Name: !Sub "${ConnectorName}-${Environment}-connect-alb"
193Scheme: internet-facing
194SecurityGroups:
195- !Ref ALBSecurityGroup
196Subnets: !Ref PublicSubnets
197
198Certificate:
199Type: "AWS::CertificateManager::Certificate"
200Properties:
201DomainName:
202Fn::Sub:
203- "${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}"
204- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
205ValidationMethod: DNS
206DomainValidationOptions:
207- DomainName:
208Fn::Sub:
209- "${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}"
210- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
211HostedZoneId: !Ref PublicHostedZoneId
212
213RecordSet:
214Type: AWS::Route53::RecordSet
215Properties:
216Name:
217Fn::Sub:
218- "${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}"
219- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
220Comment: !Sub "Alias for connectors endpoint of ${ConnectorName} in ${AWS::Region}"
221Type: CNAME
222HostedZoneId: !Ref PublicHostedZoneId
223TTL: 60
224ResourceRecords:
225- !GetAtt LoadBalancer.DNSName
226
227HttpsTargetGroup:
228Type: AWS::ElasticLoadBalancingV2::TargetGroup
229Properties:
230Name: !Sub ${ConnectorName}-${Environment}-https-tg
231HealthCheckPath: /actuator/health
232HealthCheckPort: !Ref ContainerPort
233HealthCheckIntervalSeconds: 60
234HealthCheckTimeoutSeconds: 2
235HealthyThresholdCount: 2
236UnhealthyThresholdCount: 5
237Port: 443
238Protocol: HTTP
239TargetType: ip
240TargetGroupAttributes:
241- Key: deregistration_delay.timeout_seconds
242Value: "60"
243VpcId: !Ref VpcId
244
245HttpsListener:
246Type: "AWS::ElasticLoadBalancingV2::Listener"
247Properties:
248LoadBalancerArn: !Ref LoadBalancer
249Protocol: HTTPS
250SslPolicy: ELBSecurityPolicy-TLS-1-2-2017-01
251Port: 443
252Certificates:
253- CertificateArn: !Ref Certificate
254DefaultActions:
255- Type: "forward"
256TargetGroupArn: !Ref HttpsTargetGroup
257
258ECSCluster:
259Type: AWS::ECS::Cluster
260Properties:
261ClusterName: !Sub "${ConnectorName}-${Environment}-connectors-cluster"
262
263TaskExecutionRole:
264Type: AWS::IAM::Role
265Properties:
266RoleName: !Sub "${ConnectorName}-${Environment}-connectors-task-execution-role"
267AssumeRolePolicyDocument:
268Version: 2012-10-17
269Statement:
270- Effect: Allow
271Principal:
272Service:
273- ecs-tasks.amazonaws.com
274Action:
275- "sts:AssumeRole"
276ManagedPolicyArns:
277- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
278
279TaskRole:
280Type: AWS::IAM::Role
281Properties:
282RoleName: !Sub "${ConnectorName}-${Environment}-connectors-task-role"
283AssumeRolePolicyDocument:
284Version: 2012-10-17
285Statement:
286- Effect: Allow
287Principal:
288Service:
289- ecs-tasks.amazonaws.com
290Action:
291- "sts:AssumeRole"
292Policies:
293- PolicyName: !Sub "${ConnectorName}-${Environment}-connector-logs"
294PolicyDocument:
295Version: 2012-10-17
296Statement:
297- Effect: Allow
298Action:
299- "logs:CreateLogGroup"
300- "logs:CreateLogStream"
301- "logs:PutLogEvents"
302- "cloudwatch:PutMetricData"
303Resource:
304- "*"
305- PolicyName: !Sub "${ConnectorName}-${Environment}-connector-cfn"
306PolicyDocument:
307Version: 2012-10-17
308Statement:
309- Effect: Allow
310Action:
311- "cloudformation:DescribeStacks"
312Resource:
313- "*"
314- PolicyName: !Sub "${ConnectorName}-${Environment}-connector-secrets"
315PolicyDocument:
316Version: 2012-10-17
317Statement:
318- Effect: Allow
319Action:
320- "secretsmanager:GetResourcePolicy"
321- "secretsmanager:GetSecretValue"
322- "secretsmanager:DescribeSecret"
323- "secretsmanager:ListSecretVersionIds"
324- "secretsmanager:CreateSecret"
325- "secretsmanager:DeleteSecret"
326Resource:
327- !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*"
328
329 - PolicyName: !Sub "${ConnectorName}-${Environment}-connector-sqs"
330 PolicyDocument:
331 Version: 2012-10-17
332 Statement:
333 - Effect: Allow
334 Action:
335 - "sqs:*"
336 Resource:
337 - !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:*"
338
339TaskDefinition:
340Type: AWS::ECS::TaskDefinition
341Properties:
342Family: !Sub "${ConnectorName}-${Environment}-connector"
343Cpu: !Ref CPU
344Memory: !Ref Memory
345NetworkMode: awsvpc
346ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
347TaskRoleArn: !GetAtt TaskRole.Arn
348RequiresCompatibilities:
349- FARGATE
350ContainerDefinitions:
351- Name: connector
352Image: !Ref ImageURI
353Essential: true
354PortMappings:
355- ContainerPort: !Ref ContainerPort
356Environment:
357- Name: CONNECTOR_NAME
358Value: !Ref ConnectorName
359- Name: ENVIRONMENT
360Value: !Ref Environment
361- Name: SQS_BATCH
362Value: !GetAtt BatchSQSQueue.QueueName
363- Name: SQS_EVENTS
364Value: !GetAtt EventsSQSQueue.QueueName
365- Name: SQS_CONNECTOR
366Value: !GetAtt ConnectorSQSQueue.QueueName
367- Name: REGION
368Value: !Ref AWS::Region
369LogConfiguration:
370LogDriver: awslogs
371Options:
372awslogs-group: !Ref LogGroup
373awslogs-region: !Ref AWS::Region
374awslogs-stream-prefix: connectors
375
376ECSService:
377DependsOn:
378- HttpsListener
379Type: AWS::ECS::Service
380Properties:
381ServiceName: !Sub "${ConnectorName}-${Environment}-connectors"
382Cluster: !Ref ECSCluster
383TaskDefinition: !Ref TaskDefinition
384DesiredCount: 1
385DeploymentConfiguration:
386MinimumHealthyPercent: 100
387MaximumPercent: 200
388EnableECSManagedTags: true
389LaunchType: FARGATE
390HealthCheckGracePeriodSeconds: 120
391LoadBalancers:
392- TargetGroupArn: !Ref HttpsTargetGroup
393ContainerPort: !Ref ContainerPort
394ContainerName: connector
395NetworkConfiguration:
396AwsvpcConfiguration:
397AssignPublicIp: DISABLED
398SecurityGroups:
399- !Ref ConnectorSecurityGroup
400Subnets: !Ref PrivateSubnets
401PropagateTags: SERVICE
402
403ScalingPolicy:
404Type: AWS::ApplicationAutoScaling::ScalingPolicy
405Properties:
406PolicyName: "connectors autoscaling policy"
407PolicyType: TargetTrackingScaling
408ScalingTargetId: !Ref AutoScalingTarget
409TargetTrackingScalingPolicyConfiguration:
410DisableScaleIn: False
411PredefinedMetricSpecification:
412PredefinedMetricType: ECSServiceAverageMemoryUtilization
413ScaleInCooldown: 300
414ScaleOutCooldown: 120
415TargetValue: 60.0
416
417AutoScalingTarget:
418Type: AWS::ApplicationAutoScaling::ScalableTarget
419Properties:
420MinCapacity: !Ref MinCapacity
421MaxCapacity: !Ref MaxCapacity
422ResourceId: !Sub
423- service/${ClusterName}/${ServiceName}
424- ServiceName: !GetAtt ECSService.Name
425ClusterName: !Ref ECSCluster
426ScalableDimension: ecs:service:DesiredCount
427ServiceNamespace: ecs
428RoleARN: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"
429
430
431BatchSQSQueue:
432Type: AWS::SQS::Queue
433Properties:
434QueueName: !Sub "${Environment}-${BatchSQSQueueName}"
435ReceiveMessageWaitTimeSeconds: 5
436RedrivePolicy:
437deadLetterTargetArn: !GetAtt BatchDeadLetterQueue.Arn
438maxReceiveCount: 5
439Tags:
440- Key: Name
441Value:
442Fn::Sub:
443- "${ConnectorName}-${RegionCode}-${Environment}-${BatchSQSQueueName}-sqs"
444- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
445VisibilityTimeout: 120
446
447BatchDeadLetterQueue:
448Type: AWS::SQS::Queue
449Properties:
450QueueName: !Sub "${Environment}-${BatchSQSQueueName}-dlq"
451
452EventsSQSQueue:
453Type: AWS::SQS::Queue
454Properties:
455QueueName: !Sub "${Environment}-${EventsSQSQueueName}"
456ReceiveMessageWaitTimeSeconds: 20
457RedrivePolicy:
458deadLetterTargetArn: !GetAtt EventsDeadLetterQueue.Arn
459maxReceiveCount: 5
460Tags:
461- Key: Name
462Value:
463Fn::Sub:
464- "${ConnectorName}-${RegionCode}-${Environment}-${EventsSQSQueueName}-sqs"
465- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
466VisibilityTimeout: 120
467
468EventsDeadLetterQueue:
469Type: AWS::SQS::Queue
470Properties:
471QueueName: !Sub "${Environment}-${EventsSQSQueueName}-dlq"
472
473ConnectorSQSQueue:
474Type: AWS::SQS::Queue
475Properties:
476QueueName: !Sub "${Environment}-${ConnectorSQSQueueName}"
477ReceiveMessageWaitTimeSeconds: 20
478RedrivePolicy:
479deadLetterTargetArn: !GetAtt ConnectorDeadLetterQueue.Arn
480maxReceiveCount: 5
481Tags:
482- Key: Name
483Value:
484Fn::Sub:
485- "${ConnectorName}-${RegionCode}-${Environment}-${ConnectorSQSQueueName}-sqs"
486- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
487VisibilityTimeout: 120
488
489ConnectorDeadLetterQueue:
490Type: AWS::SQS::Queue
491Properties:
492QueueName: !Sub "${Environment}-${ConnectorSQSQueueName}-dlq"
493
494ApiConnection:
495Type: AWS::Events::Connection
496Properties:
497AuthorizationType: BASIC
498Description: !Sub "Connection to ${ConnectorName} ${Environment} connector endpoint"
499AuthParameters:
500BasicAuthParameters:
501Username: admin
502Password: "pass"
503InvocationHttpParameters: {}
504
505ProductApiDestination:
506DependsOn:
507- ECSService
508Type: AWS::Events::ApiDestination
509Properties:
510ConnectionArn: !GetAtt ApiConnection.Arn
511Description: !Sub "Product Api Destination for ${ConnectorName} Scheduled Events Rule"
512HttpMethod: PUT
513InvocationEndpoint:
514Fn::Sub:
515- "https://${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}/api/v1/fluent-connect/scheduler/add/${FluentAccount}/${RetailerId}/batch-product-catalogue-sync"
516- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
517InvocationRateLimitPerSecond: 300
518Name: !Sub "${ConnectorName}.${Environment}-product-api-destination"
519
520LocationApiDestination:
521DependsOn:
522- ECSService
523Type: AWS::Events::ApiDestination
524Properties:
525ConnectionArn: !GetAtt ApiConnection.Arn
526Description: !Sub "Location Api Destination for ${ConnectorName} Scheduled Events Rule"
527HttpMethod: PUT
528InvocationEndpoint:
529Fn::Sub:
530- "https://${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}/api/v1/fluent-connect/scheduler/add/${FluentAccount}/${RetailerId}/batch-location-sync"
531- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
532InvocationRateLimitPerSecond: 300
533Name: !Sub "${ConnectorName}.${Environment}-location-api-destination"
534
535InventoryApiDestination:
536DependsOn:
537- ECSService
538Type: AWS::Events::ApiDestination
539Properties:
540ConnectionArn: !GetAtt ApiConnection.Arn
541Description: !Sub "Inventory Api Destination for ${ConnectorName} Scheduled Events Rule"
542HttpMethod: PUT
543InvocationEndpoint:
544Fn::Sub:
545- "https://${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}/api/v1/fluent-connect/scheduler/add/${FluentAccount}/${RetailerId}/batch-inventory-sync"
546- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
547InvocationRateLimitPerSecond: 300
548Name: !Sub "${ConnectorName}.${Environment}-inventory-api-destination"
549
550RuleTargetRole:
551Type: AWS::IAM::Role
552Properties:
553RoleName: !Sub "${ConnectorName}-${Environment}-invoke-api-destination"
554AssumeRolePolicyDocument:
555Version: 2012-10-17
556Statement:
557- Effect: Allow
558Principal:
559Service:
560- events.amazonaws.com
561Action:
562- "sts:AssumeRole"
563Policies:
564- PolicyName: !Sub "${ConnectorName}-${Environment}-invoke-api-destination"
565PolicyDocument:
566Version: 2012-10-17
567Statement:
568- Effect: Allow
569Action:
570- events:InvokeApiDestination
571Resource:
572- !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:api-destination/*"
573
574ProductScheduledEventsRule:
575Type: AWS::Events::Rule
576Properties:
577Description: Hits the connector endpoint on a schedule
578EventBusName: default
579Name: !Sub "${ConnectorName}-${Environment}-scheduled-product-catalogue-rule"
580ScheduleExpression: "rate(15 minutes)"
581State: ENABLED
582Targets:
583- Arn: !GetAtt ProductApiDestination.Arn
584Id: !Sub "${ConnectorName}-${Environment}-product-catalogue-target-id"
585RoleArn: !GetAtt RuleTargetRole.Arn
586RetryPolicy:
587MaximumRetryAttempts: 4
588MaximumEventAgeInSeconds: 400
589DeadLetterConfig:
590Arn: !GetAtt BatchDeadLetterQueue.Arn
591
592LocationScheduledEventsRule:
593Type: AWS::Events::Rule
594Properties:
595Description: Hits the connector endpoint on a schedule
596EventBusName: default
597Name: !Sub "${ConnectorName}-${Environment}-scheduled-batch-location-rule"
598ScheduleExpression: "rate(30 minutes)"
599State: ENABLED
600Targets:
601- Arn: !GetAtt LocationApiDestination.Arn
602Id: !Sub "${ConnectorName}-${Environment}-batch-location-target-id"
603RoleArn: !GetAtt RuleTargetRole.Arn
604RetryPolicy:
605MaximumRetryAttempts: 4
606MaximumEventAgeInSeconds: 400
607DeadLetterConfig:
608Arn: !GetAtt BatchDeadLetterQueue.Arn
609InventoryScheduledEventsRule:
610Type: AWS::Events::Rule
611Properties:
612Description: Hits the connector endpoint on a schedule
613EventBusName: default
614Name: !Sub "${ConnectorName}-${Environment}-scheduled-batch-inventory-rule"
615ScheduleExpression: "rate(5 minutes)"
616State: ENABLED
617Targets:
618- Arn: !GetAtt InventoryApiDestination.Arn
619Id: !Sub "${ConnectorName}-${Environment}-batch-inventory-target-id"
620RoleArn: !GetAtt RuleTargetRole.Arn
621RetryPolicy:
622MaximumRetryAttempts: 4
623MaximumEventAgeInSeconds: 400
624DeadLetterConfig:
625Arn: !GetAtt BatchDeadLetterQueue.Arn
626
627Outputs:
628BatchQueueURL:
629Description: URL of batch SQS queue
630Value: !Ref BatchSQSQueue
631
632EventsQueueURL:
633Description: URL of events SQS queue
634Value: !Ref EventsSQSQueue
635
636ConnectorQueueURL:
637Description: URL of connector SQS queue
638Value: !Ref ConnectorSQSQueue
639
640ConnectorsPublicURL:
641Description: "The public URL of the connectors endpoint"
642Value:
643Fn::Sub:
644- "https://${ConnectorName}.${RegionCode}.${Environment}.${PublicHostedZoneName}"
645- RegionCode: !FindInMap [RegionMap, !Ref AWS::Region, RegionCode]
Language: text
Name: CloudFormation Template
Description:
[Warning: empty required content area]