cloudformation/cloudformation.yaml (664 lines of code) (raw):

AWSTemplateFormatVersion: "2010-09-09" Description: "fulfilment step functions." Parameters: Stage: Description: Stage name Type: String AllowedValues: - PROD - CODE Default: CODE Conditions: CreateProdResources: !Equals [!Ref "Stage", "PROD"] Mappings: EnvironmentBucketMap: CODE: "logs": "fulfilment-s3-logs-code" "export": "fulfilment-export-code" PROD: "logs": "fulfilment-s3-logs-prod" "export": "fulfilment-export-prod" Constants: Alarm: Process: Follow the process in https://docs.google.com/document/d/1_3El3cly9d7u_jPgTcRjLxmdG2e919zCLvmcFCLOYAk/edit Urgent: URGENT 9-5 - Resources: FulfilmentAccessLogBucket: Type: "AWS::S3::Bucket" Properties: BucketName: Fn::FindInMap: - EnvironmentBucketMap - Ref: Stage - "logs" PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true AccessControl: LogDeliveryWrite LoggingConfiguration: DestinationBucketName: Fn::FindInMap: - EnvironmentBucketMap - Ref: Stage - "logs" LogFilePrefix: "logs-logs/" VersioningConfiguration: Status: "Enabled" FulfilmentBucket: Type: "AWS::S3::Bucket" Properties: BucketName: Fn::FindInMap: - EnvironmentBucketMap - Ref: Stage - "export" PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true AccessControl: Private LifecycleConfiguration: Rules: - Id: DeleteAllOldFiles Prefix: "" Status: Enabled ExpirationInDays: 365 - Id: DeleteOldFilesZuora Prefix: "zuora" Status: Enabled ExpirationInDays: 14 LoggingConfiguration: DestinationBucketName: Fn::FindInMap: - EnvironmentBucketMap - Ref: Stage - "logs" LogFilePrefix: !Sub fulfilment-salesforce-backup-_${Stage}/ VersioningConfiguration: Status: "Enabled" EncryptBucketPolicy: Type: AWS::S3::BucketPolicy DependsOn: FulfilmentBucket Properties: Bucket: !Sub ${FulfilmentBucket} PolicyDocument: Version: '2012-10-17' Statement: - Sid: DenyIncorrectEncryptionHeader Effect: Deny Principal: "*" Action: s3:PutObject Resource: !Sub arn:aws:s3:::${FulfilmentBucket}/* Condition: StringNotEquals: s3:x-amz-server-side-encryption: - AES256 - aws:kms - Sid: DenyUnEncryptedObjectUploads Effect: Deny Principal: "*" Action: s3:PutObject Resource: !Sub arn:aws:s3:::${FulfilmentBucket}/* Condition: 'Null': s3:x-amz-server-side-encryption: 'true' FulfilmentWorkersLambdaRole: Type: AWS::IAM::Role DependsOn: FulfilmentBucket Properties: RoleName: !Sub FulfilmentWorkers-${Stage} AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: LambdaPolicy PolicyDocument: Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - lambda:InvokeFunction Resource: "*" - PolicyName: PrivateBucket PolicyDocument: Statement: - Effect: Allow Action: s3:GetObject Resource: !Sub arn:aws:s3:::gu-reader-revenue-private/membership/fulfilment-lambdas/${Stage}/* - PolicyName: WorkBucket PolicyDocument: Statement: - Effect: Allow Action: - s3:AbortMultipartUpload - s3:DeleteObject - s3:GetObject - s3:GetObjectAcl - s3:GetBucketAcl - s3:ListBucket - s3:PutObject - s3:GetObjectVersion - s3:DeleteObjectVersion Resource: !Sub arn:aws:s3:::${FulfilmentBucket}/* - PolicyName: ListWorkBucket PolicyDocument: Statement: - Effect: Allow Action: - s3:ListBucket Resource: !Sub arn:aws:s3:::${FulfilmentBucket} SalesforceUploaderLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub salesforce_uploader-${Stage} Description: "Upload Home Delivery fulfilment files to Salesforce document Home_Delivery_Pipeline_Fulfilment" Handler: "salesforce_uploader.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} 'StateMachine': !Ref FulfilmentStateMachine DependsOn: FulfilmentStateMachine ZuoraQuerierLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub zuora_fulfilment_querier-${Stage} Description: "Trigger zuora export" Handler: "querier.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} ResultsFetcherLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub zuora_fulfilment_fetcher-${Stage} Description: "Fetch zuora export results" Handler: "fetcher.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} SalesforceDownloaderLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub zuora_fulfilment_salesforce_downloader-${Stage} Description: "Fetch salesforce fulfilment files" Handler: "salesforce_downloader.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} WeeklyUploaderLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub weekly-fulfilmentUploader-${Stage} Description: "upload Guardian Weekly fulfilment files to salesforce" Handler: "weekly_salesforce_uploader.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} FulfilmentExporterLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub zuora_fulfilment_exporter-${Stage} Description: "Fetch generate fulfilment file" Handler: "exporter.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 512 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} StatesExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: Effect: "Allow" Principal: Service: !Sub states.${AWS::Region}.amazonaws.com Action: "sts:AssumeRole" Path: "/" Policies: - PolicyName: StatesExecutionPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "lambda:InvokeFunction" Resource: "*" FulfilmentStateMachine: Type: "AWS::StepFunctions::StateMachine" Properties: StateMachineName: !Sub 'fulfilment-state-machine-${Stage}' DefinitionString: !Sub - |- { "Comment": "State machine for Fulfilment", "TimeoutSeconds": 64800, "StartAt": "QueryZuora", "States": { "QueryZuora": { "Type": "Task", "Resource": "${querierArn}", "Next": "WaitSomeTime", "Retry": [ { "ErrorEquals": ["States.ALL"], "IntervalSeconds": 30, "MaxAttempts": 3 }] }, "WaitSomeTime": { "Type": "Wait", "Seconds": 180, "Next": "FetchResults" }, "FetchResults": { "Type": "Task", "Resource": "${fetcherArn}", "Next": "GenerateFulfilmentFile", "Retry": [ { "ErrorEquals": ["States.ALL"], "IntervalSeconds": 30, "MaxAttempts": 50, "BackoffRate": 1.15 }] }, "GenerateFulfilmentFile": { "Type": "Task", "Resource": "${exporterArn}", "End": true, "Retry": [ { "ErrorEquals": ["States.ALL"], "IntervalSeconds": 30, "MaxAttempts": 3 }] } } } - { querierArn: !GetAtt [ ZuoraQuerierLambda, Arn ], fetcherArn: !GetAtt [ ResultsFetcherLambda, Arn ], exporterArn: !GetAtt [ FulfilmentExporterLambda, Arn ] } RoleArn: !GetAtt [ StatesExecutionRole, Arn ] FulfilmentAPIPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub salesforce_uploader-${Stage} Principal: apigateway.amazonaws.com DependsOn: SalesforceUploaderLambda FulfilmentAPI: Type: "AWS::ApiGateway::RestApi" Properties: Description: Upload Home Delivery fulfilment files to Salesforce document Home_Delivery_Pipeline_Fulfilment Name: !Sub fulfilment-api-${Stage} FulfilmentProxyResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref FulfilmentAPI ParentId: !GetAtt [FulfilmentAPI, RootResourceId] PathPart: fulfilment DependsOn: FulfilmentAPI FulfilmentMethod: Type: AWS::ApiGateway::Method Properties: AuthorizationType: NONE RestApiId: !Ref FulfilmentAPI ResourceId: !Ref FulfilmentProxyResource HttpMethod: POST Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SalesforceUploaderLambda.Arn}/invocations DependsOn: - FulfilmentAPI - SalesforceUploaderLambda - FulfilmentProxyResource FulfilmentAPIStage: Type: AWS::ApiGateway::Stage Properties: Description: Stage for fulfilment-api RestApiId: !Ref FulfilmentAPI DeploymentId: !Ref FulfilmentAPIDeployment StageName: !Sub ${Stage} DependsOn: FulfilmentMethod FulfilmentAPIDeployment: Type: AWS::ApiGateway::Deployment Properties: Description: Deploys fulfilment-api into an environment/stage RestApiId: !Ref FulfilmentAPI DependsOn: FulfilmentMethod ScheduledRule: Type: "AWS::Events::Rule" Properties: Description: "TriggerFulfilment" ScheduleExpression: "cron(0 7 ? * mon-fri *)" State: "ENABLED" Targets: - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-1 Input: | { "deliveryDateDaysFromNow": 1, "type":"homedelivery" } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-2 Input: | { "deliveryDateDaysFromNow": 2, "type":"homedelivery" } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-3 Input: | { "deliveryDateDaysFromNow": 3, "type":"homedelivery" } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-4 Input: | { "deliveryDateDaysFromNow": 4, "type":"homedelivery" } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-5 Input: | { "deliveryDateDaysFromNow": 5, "type":"homedelivery" } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] DependsOn: FulfilmentStateMachine WeeklyScheduledRule: Type: "AWS::Events::Rule" Properties: Description: "TriggerWeeklyFulfilment" ScheduleExpression: "cron(00 2 ? * * *)" State: "ENABLED" Targets: - Arn: !Ref FulfilmentStateMachine Id: !Sub trigger_state_machine-${Stage}-1 Input: | { "type":"weekly", "deliveryDayOfWeek": "friday", "minDaysInAdvance" : 8 } RoleArn: !GetAtt [ fulfilmentTriggerRole, Arn ] WeeklyScheduledUploadRule: Type: "AWS::Events::Rule" Properties: Description: "TriggerWeeklyFulfilmentUpload" ScheduleExpression: "cron(00 11 ? * THU *)" State: "ENABLED" Targets: - Arn: !GetAtt WeeklyUploaderLambda.Arn Id: !Sub weeklySfUploader Input: | { "type":"weekly", "deliveryDayOfWeek": "friday", "minDaysInAdvance" : 8 } SFDownloadScheduledRule: Type: "AWS::Events::Rule" Properties: Description: "Download fulfilment files from Salesforce" ScheduleExpression: "cron(50 14 ? * mon-fri *)" State: "ENABLED" Targets: - Arn: !GetAtt SalesforceDownloaderLambda.Arn Id: !Sub salesforceDownloader DependsOn: FulfilmentStateMachine fulfilmentTriggerRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: TriggerStateMchine PolicyDocument: Version : "2012-10-17" Statement: - Effect: Allow Action: - states:StartExecution Resource: !Ref FulfilmentStateMachine checkerLambda: Type: "AWS::Lambda::Function" Properties: FunctionName: !Sub zuora_fulfilment_checker-${Stage} Description: "daily check to verify fulfilment files have been generated" Handler: "checker.handler" Role: !GetAtt [ FulfilmentWorkersLambdaRole, Arn ] Code: S3Bucket: fulfilment-lambdas-dist S3Key: !Sub membership/${Stage}/fulfilment-lambdas/fulfilment-lambdas.zip MemorySize: 128 Runtime: nodejs20.x Timeout: 300 Environment: Variables: 'Stage': !Sub ${Stage} fulfilmentCheckerMetricFilter: Type: AWS::Logs::MetricFilter Properties: LogGroupName: !Sub "/aws/lambda/${checkerLambda}" FilterPattern: '"CHECK:PASSED"' MetricTransformations: - MetricNamespace: !Sub "${Stage}/fulfilment" MetricName: "fulfilmentFileUpdated" MetricValue: 1 DependsOn: checkerLambda CheckerScheduledRule: Type: "AWS::Events::Rule" Properties: Description: "trigger fulfilment file check" ScheduleExpression: "cron(30 11 * * ? *)" State: "ENABLED" Targets: - Id: !Sub fulfilmentChecker_${Stage} Arn: !GetAtt checkerLambda.Arn DependsOn: fulfilmentCheckerMetricFilter checkerSchedulePermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !GetAtt checkerLambda.Arn Principal: events.amazonaws.com SourceArn: !GetAtt CheckerScheduledRule.Arn weeklyScheduledUploadPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !GetAtt WeeklyUploaderLambda.Arn Principal: events.amazonaws.com SourceArn: !GetAtt WeeklyScheduledUploadRule.Arn sfDownloadSchedulePermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !GetAtt SalesforceDownloaderLambda.Arn Principal: events.amazonaws.com SourceArn: !GetAtt SFDownloadScheduledRule.Arn CheckerAlarm: Type: "AWS::CloudWatch::Alarm" Condition: CreateProdResources Properties: AlarmDescription: "alarm when fulfilment file has not been generated" AlarmName: !Sub "fulfilment_check_alarm_${Stage}" MetricName: fulfilmentFileUpdated Namespace: !Sub "${Stage}/fulfilment" TreatMissingData: breaching Statistic: Sum Period: 86400 EvaluationPeriods: 1 Threshold: 1 ComparisonOperator: LessThanThreshold DependsOn: fulfilmentCheckerMetricFilter FulfilmentStateMachineAlarm: Type: AWS::CloudWatch::Alarm Condition: CreateProdResources Properties: AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: !Join - ' ' - - !FindInMap [ Constants, Alarm, Urgent ] - !Ref 'Stage' - 'Failed to generate GW and HD fulfilment files' AlarmDescription: !Join - ' ' - - 'Impact - Guardian Weekly and Home Delivery subscribes will not get their paper. Fix FulfilmentStateMachine ASAP!' - !FindInMap [ Constants, Alarm, Process ] MetricName: ExecutionsFailed Namespace: AWS/States Dimensions: - Name: StateMachineArn Value: !Ref FulfilmentStateMachine ComparisonOperator: GreaterThanOrEqualToThreshold Threshold: 1 Period: 60 EvaluationPeriods: 1 Statistic: Sum TreatMissingData: ignore DependsOn: FulfilmentStateMachine HomeDeliveryUploadToSalesforceApiAlarm: Type: AWS::CloudWatch::Alarm Condition: CreateProdResources Properties: AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: !Join - ' ' - - !FindInMap [ Constants, Alarm, Urgent ] - !Ref 'Stage' - 'Failed to upload Home Delivery fulfilment files to Salesforce' AlarmDescription: !Join - ' ' - - 'Impact - Home Delivery subscribers will not get their paper. Investigate fulfilment-api Gateway ASAP! ' - !FindInMap [ Constants, Alarm, Process ] MetricName: 5XXError Namespace: AWS/ApiGateway Dimensions: - Name: ApiName Value: !Sub fulfilment-api-${Stage} - Name: Stage Value: !Sub ${Stage} ComparisonOperator: GreaterThanOrEqualToThreshold Threshold: 1 Period: 60 EvaluationPeriods: 1 Statistic: Sum TreatMissingData: notBreaching DependsOn: FulfilmentAPI GuardianWeeklyUploadToSalesforceLambdaAlarm: Type: AWS::CloudWatch::Alarm Condition: CreateProdResources Properties: AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: !Join - ' ' - - !FindInMap [ Constants, Alarm, Urgent ] - !Ref 'Stage' - 'Failed to upload Guardian Weekly fulfilment files to Salesforce' AlarmDescription: !Join - ' ' - - 'Impact - Guardian Weekly subscribers will not get their paper. Investigate weekly-fulfilmentUploader ASAP! ' - !FindInMap [ Constants, Alarm, Process ] MetricName: Errors Namespace: AWS/Lambda Dimensions: - Name: FunctionName Value: !Ref WeeklyUploaderLambda ComparisonOperator: GreaterThanOrEqualToThreshold Threshold: 1 Period: 60 EvaluationPeriods: 1 Statistic: Sum TreatMissingData: notBreaching DependsOn: WeeklyUploaderLambda