--- AWSTemplateFormatVersion: 2010-09-09 Description: > This template deploys the Retail Demo Store deployment support resources such as custom resources and misc lambda functions. Parameters: ResourceBucket: Type: String Description: > S3 bucket name where the Retail Demo Store deployment resources are staged (product images, nested CloudFormation templates, source code snapshot, notebooks, deployment Lambda code, etc). ResourceBucketRelativePath: Type: String Description: > Optional path in the Deployment Resources Staging bucket where the deployment resources are stored (e.g. path/path2/). Leave blank if resources are at the root of the Staging Resource Bucket. If specified, MUST end with '/'. PreIndexOpenSearch: Type: String Description: > Automatically index the Retail Demo Store products in OpenSearch. Otherwise, select 'No' if you would prefer to complete this process yourself by stepping through the Search workshop included in this deployment as a Jupyter notebook in SageMaker. AllowedValues: - 'Yes' - 'No' Default: 'No' PreCreatePersonalizeResources: Type: String Description: > Automatically trigger the background creation of Amazon Personalize resources such as solutions, campaigns, and recommenders at deployment time. Otherwise, select 'No' if you would prefer to complete this process yourself by stepping through the Personalization workshops included in this deployment. Note that the background create process runs after deployment finishes and can take 2+ hours to complete. AllowedValues: - 'Yes' - 'No' Default: 'No' PreCreatePinpointWorkshop: Type: String Description: > Automatically configure Pinpoint with messaging templates, segments, and campaigns. Otherwise, select 'No' if you would prefer to complete this process yourself by stepping through the Messaging workshop included in your deployment as a Jupyter notebook in SageMaker. AllowedValues: - 'Yes' - 'No' Default: 'No' Subnet1: Type: String Subnet2: Type: String OpenSearchSecurityGroupId: Type: String OpenSearchDomainArn: Type: String OpenSearchDomainEndpoint: Type: String ParameterIVSVideoChannelMap: Type: String Uid: Type: String PinpointAppId: Type: String PinpointEmailFromAddress: Type: String PinpointEmailFromName: Type: String Default: "AWS Retail Demo Store" PinpointPersonalizeRoleArn: Type: String CustomizeRecommendationsFunctionArn: Type: String CustomizeOffersRecommendationsFunctionArn: Type: String UseDefaultIVSStreams: Type: String Default: Yes ProductsServiceExternalUrl: Type: String DeployPersonalizedOffersCampaign: Type: String Default: No PersonalizeRoleArn: Type: String Conditions: DeployPreIndexOpenSearch: !Equals - !Ref PreIndexOpenSearch - 'Yes' AutoCreatePinpointWorkshop: !Equals - !Ref PreCreatePinpointWorkshop - 'Yes' AutoCreatePersonalizedOffersCampaign: !Equals - !Ref DeployPersonalizedOffersCampaign - 'Yes' # If the Personalize offers campaign isn't being pre-created then we can invoke the pinpoint-auto-workshop lambda immediately, # otherwise we have to wait until it completes. See personalize_pre_create_resources.py. When all the personalize resources are # created it writes the resource arn's in SSM parameter store. To wait for the offers campaign we setup an eventbridge rule to # trigger the pinpoint-auto-workshop lambda when create/updates events are received for the respective SSM parameter. DeployPreCreatePinpointWorkshop: !And - !Condition AutoCreatePinpointWorkshop - !Not [!Condition AutoCreatePersonalizedOffersCampaign] WaitForOffersCampaignCreationAndDeployPreCreatePinpointWorkshop: !And - !Condition AutoCreatePinpointWorkshop - !Condition AutoCreatePersonalizedOffersCampaign CreateIVSResources: !Equals - !Ref UseDefaultIVSStreams - 'No' Resources: ####################### Pre-Create Personalize Resources ####################### PersonalizePreCreateLambdaFunction: Type: 'AWS::Lambda::Function' Properties: Description: 'Retail Demo Store deployment utility function that uploads datasets, builds solutions, and creates campaigns in Amazon Personalize' Handler: personalize_pre_create_resources.lambda_handler Role: !GetAtt PersonalizePreCreateLambdaExecutionRole.Arn Code: S3Bucket: !Ref ResourceBucket S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/personalize-pre-create-resources.zip' Runtime: python3.8 Timeout: 900 FunctionName: RetailDemoStorePersonalizePreCreateResources Environment: Variables: csv_bucket: !Ref ResourceBucket csv_path: !Sub '${ResourceBucketRelativePath}csvs/' lambda_event_rule_name: 'RetailDemoStore-PersonalizePreCreateScheduledRule' Uid: !Ref Uid DeployPersonalizedOffersCampaign: !Ref DeployPersonalizedOffersCampaign ProductsServiceExternalUrl: !Ref ProductsServiceExternalUrl PersonalizeRoleArn: !Ref PersonalizeRoleArn PreCreatePersonalizeResources: !Ref PreCreatePersonalizeResources PersonalizePreCreateLambdaExecutionRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStorePersonalizePreCreateResources:log-stream:*' - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStorePersonalizePreCreateResources' - Effect: Allow Action: - ssm:PutParameter - ssm:GetParameter Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/retaildemostore*' - Effect: Allow Action: - logs:CreateLogGroup Resource: '*' - Effect: Allow Action: - iam:PassRole Resource: - !Sub 'arn:aws:iam::${AWS::AccountId}:role/${Uid}-PersonalizeS3' - Effect: Allow Action: - events:ListTargetsByRule - events:DisableRule - events:EnableRule Resource: !Sub 'arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/RetailDemoStore-PersonalizePreCreateScheduledRule' - Effect: Allow Action: - events:PutRule - events:PutTargets - events:RemoveTargets - events:DeleteRule Resource: '*' - Effect: Allow Action: - lambda:AddPermission - lambda:RemovePermission Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:RetailDemoStorePersonalizePreCreateResources' - Effect: Allow Action: - personalize:List* Resource: '*' - Effect: Allow Action: - personalize:Create* - personalize:Delete* - personalize:Describe* Resource: - !Sub 'arn:aws:personalize:${AWS::Region}:${AWS::AccountId}:*/retaildemo*' - Effect: Allow Action: - personalize:DescribeEventTracker - personalize:DeleteEventTracker Resource: - !Sub 'arn:aws:personalize:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - codepipeline:ListPipelines - codepipeline:ListTagsForResource Resource: - !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - codepipeline:StartPipelineExecution Resource: - !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:*' Condition: StringEquals: aws:ResourceTag/RetailDemoStoreServiceName: 'web-ui' PersonalizePreCreateScheduledRule: Type: 'AWS::Events::Rule' Properties: Name: 'RetailDemoStore-PersonalizePreCreateScheduledRule' Description: Calls Personalize pre-create Lambda function every 5 minutes until Personalize reaches desired state ScheduleExpression: rate(5 minutes) State: DISABLED Targets: - Arn: !GetAtt PersonalizePreCreateLambdaFunction.Arn Id: TargetFunctionV1 PersonalizePreCreatePermissionToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt PersonalizePreCreateLambdaFunction.Arn Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: !GetAtt PersonalizePreCreateScheduledRule.Arn CustomLaunchPersonalizePreCreateLambdaFunction: Type: Custom::CustomLambdaPersonalize Properties: ServiceToken: !GetAtt PersonalizePreCreateLambdaFunction.Arn ####################### Create IVS Channels ####################### IVSCreateChannelsLambdaFunction: Type: 'AWS::Lambda::Function' Condition: CreateIVSResources Properties: Description: 'Retail Demo Store deployment utility function that creates IVS channels.' Handler: ivs-create-channels.lambda_handler Role: !GetAtt IVSCreateChannelsLambdaExecutionRole.Arn Code: S3Bucket: !Ref ResourceBucket S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/ivs-create-channels.zip' Runtime: python3.8 Timeout: 900 FunctionName: RetailDemoStoreIVSCreateChannels Environment: Variables: bucket: !Ref ResourceBucket videos_path: !Sub '${ResourceBucketRelativePath}videos/' ssm_video_channel_map_param: !Ref ParameterIVSVideoChannelMap Uid: !Ref Uid IVSCreateChannelsLambdaExecutionRole: Type: 'AWS::IAM::Role' Condition: CreateIVSResources Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStoreIVSCreateChannels:log-stream:*' - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStoreIVSCreateChannels' - Effect: Allow Action: - ssm:PutParameter - ssm:GetParameter Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/retaildemostore*' - Effect: Allow Action: - ivs:CreateChannel - ivs:CreateStreamKey - ivs:ListStreamKeys - ivs:DeleteChannel Resource: !Sub 'arn:aws:ivs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - ivs:StopStream - ivs:GetChannel Resource: !Sub 'arn:aws:ivs:${AWS::Region}:${AWS::AccountId}:channel/*' - Effect: Allow Action: - ivs:DeleteStreamKey Resource: !Sub 'arn:aws:ivs:${AWS::Region}:${AWS::AccountId}:stream-key/*' - Effect: Allow Action: - s3:ListBucket Resource: - !Sub "arn:aws:s3:::${ResourceBucket}/*" - !Sub "arn:aws:s3:::${ResourceBucket}" - Effect: Allow Action: - logs:CreateLogGroup Resource: '*' # Custom resource to launch IVS create channels function CustomLaunchIVSCreateChannelsLambdaFunction: Type: Custom::CustomLambdaIVS Condition: CreateIVSResources Properties: ServiceToken: !GetAtt IVSCreateChannelsLambdaFunction.Arn ####################### Pre-Index OpenSearch ####################### OpenSearchPreIndexLambdaFunction: Condition: DeployPreIndexOpenSearch Type: 'AWS::Lambda::Function' Properties: Description: 'Retail Demo Store deployment utility function that indexes product catalog in Amazon OpenSearch' Handler: opensearch-pre-index.lambda_handler Role: !GetAtt OpenSearchPreIndexLambdaExecutionRole.Arn Code: S3Bucket: !Ref ResourceBucket S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/opensearch-pre-index.zip' Runtime: python3.9 Timeout: 300 VpcConfig: SecurityGroupIds: - !Ref OpenSearchSecurityGroupId SubnetIds: - !Ref Subnet1 - !Ref Subnet2 OpenSearchPreIndexLambdaExecutionRole: Condition: DeployPreIndexOpenSearch Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: /service-role/ ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup - ec2:CreateNetworkInterface - ec2:DeleteNetworkInterface - ec2:DescribeNetworkInterfaces Resource: '*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*OpenSearch*:log-stream:*' - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*OpenSearch*' - Effect: Allow Action: - es:ESHttpDelete - es:ESHttpGet - es:ESHttpPost - es:ESHttpPut Resource: !Ref OpenSearchDomainArn # Custom resource to launch opensearch preindex function CustomLaunchOpenSearchPreIndexLambdaFunction: Condition: DeployPreIndexOpenSearch Type: Custom::CustomLambdaOpenSearch Properties: ServiceToken: !GetAtt OpenSearchPreIndexLambdaFunction.Arn OpenSearchDomainEndpoint: !Ref OpenSearchDomainEndpoint Bucket: !Ref ResourceBucket File: !Sub '${ResourceBucketRelativePath}data/products.yaml' ####################### Pre-Create Pinpoint Workshop ####################### PinpointPreCreateLambdaFunction: Condition: AutoCreatePinpointWorkshop Type: 'AWS::Lambda::Function' Properties: Description: 'Retail Demo Store deployment utility function that configures messaging templates, segments, and campaigns in Amazon Pinpoint' Handler: pinpoint-auto-workshop.lambda_handler Role: !GetAtt PinpointPreCreateLambdaExecutionRole.Arn Code: S3Bucket: !Ref ResourceBucket S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/pinpoint-auto-workshop.zip' Runtime: python3.8 Timeout: 900 FunctionName: RetailDemoStorePinpointAutoWorkshop Environment: Variables: pinpoint_app_id: !Ref PinpointAppId pinpoint_recommender_arn: !Ref CustomizeRecommendationsFunctionArn pinpoint_offers_recommender_arn: !Ref CustomizeOffersRecommendationsFunctionArn pinpoint_personalize_role_arn: !Ref PinpointPersonalizeRoleArn email_from_address: !Ref PinpointEmailFromAddress email_from_name: !Ref PinpointEmailFromName lambda_event_rule_name: 'RetailDemoStore-PinpointPreCreateRule' DeployPersonalizedOffersCampaign: !Ref DeployPersonalizedOffersCampaign PinpointPreCreateLambdaExecutionRole: Condition: AutoCreatePinpointWorkshop Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup Resource: '*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStorePinpointAutoWorkshop:log-stream:*' - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RetailDemoStorePinpointAutoWorkshop' - Effect: Allow Action: - ssm:GetParameter Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/retaildemostore*' - Effect: Allow Action: - mobiletargeting:* Resource: "*" - Effect: Allow Action: - events:ListTargetsByRule - events:RemoveTargets - events:DeleteRule Resource: - !Sub 'arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/RetailDemoStore-PinpointPreCreateRule' - Effect: Allow Action: - iam:PassRole Resource: - !Sub 'arn:aws:iam::${AWS::AccountId}:role/${Uid}-PinptP9e' PinpointPreCreateRule: Condition: WaitForOffersCampaignCreationAndDeployPreCreatePinpointWorkshop Type: 'AWS::Events::Rule' Properties: Name: 'RetailDemoStore-PinpointPreCreateRule' Description: Calls Pinpoint workshop pre-create Lambda function when the Personalize campaign ARN SSM parameter is updated EventPattern: source: - "aws.ssm" detail-type: - "Parameter Store Change" detail: name: - "/retaildemostore/personalize/personalized-offers-arn" operation: - "Update" - "Create" State: ENABLED Targets: - Arn: !GetAtt PinpointPreCreateLambdaFunction.Arn Id: TargetFunctionV1 PinpointPreCreatePermissionToInvokeLambda: Condition: WaitForOffersCampaignCreationAndDeployPreCreatePinpointWorkshop Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt PinpointPreCreateLambdaFunction.Arn Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: !GetAtt PinpointPreCreateRule.Arn # Custom resource to launch pinpoint auto workshop CustomLaunchPinpointPreCreateLambdaFunction: Condition: DeployPreCreatePinpointWorkshop Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt PinpointPreCreateLambdaFunction.Arn