AWSTemplateFormatVersion: "2010-09-09" Description: Amazon Lookout for Vision Demo (uksb-1rcfob3k8) Transform: AWS::Serverless-2016-10-31 Globals: Function: Runtime: nodejs16.x MemorySize: 512 Timeout: 60 Environment: Variables: REGION: !Ref AWS::Region VERSION: "1.2" Api: EndpointConfiguration: REGIONAL Cors: AllowMethods: "'*'" AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" AllowOrigin: "'*'" Auth: DefaultAuthorizer: CognitoAuthorizer Authorizers: CognitoAuthorizer: UserPoolArn: !GetAtt CognitoUserPool.Arn AddDefaultAuthorizerToCorsPreflight: False GatewayResponses: DEFAULT_4XX: ResponseTemplates: "application/json": '{ "Message": $context.error.messageString }' ResponseParameters: Headers: Access-Control-Allow-Methods: "'*'" Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" Access-Control-Allow-Origin: "'*'" DEFAULT_5XX: ResponseTemplates: "application/json": '{ "Message": $context.error.messageString }' ResponseParameters: Headers: Access-Control-Allow-Methods: "'*'" Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" Access-Control-Allow-Origin: "'*'" BAD_REQUEST_BODY: StatusCode: 422 ResponseTemplates: "application/json": '{ "Message": $context.error.messageString }' ResponseParameters: Headers: Access-Control-Allow-Methods: "'*'" Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" Access-Control-Allow-Origin: "'*'" BAD_REQUEST_PARAMETERS: StatusCode: 422 ResponseTemplates: "application/json": '{ "Message": $context.error.messageString }' ResponseParameters: Headers: Access-Control-Allow-Methods: "'*'" Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" Access-Control-Allow-Origin: "'*'" Parameters: AdminEmail: Description: Creates a username to be used for Authentication. It needs to be an e-mail address. Type: String AllowedPattern: ^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$ ResourcePrefix: Description: AWS Resources are named based on the value of this parameter. You must customise this if you are launching more than one instance of the stack within the same account. Type: String Default: LVDemo AllowedPattern: ^[a-zA-Z0-9_]*$ CreateCloudFrontDistribution: Description: Creates a CloudFront distribution for accessing the web interface of the demo. This must be enabled if S3 Block Public Access is enabled at an account level. Type: String Default: "true" AllowedValues: - "true" - "false" Conditions: WithCloudFront: !Equals [!Ref CreateCloudFrontDistribution, "true"] Outputs: url: Value: !If - WithCloudFront - !Sub "https://${CloudFrontDistribution.DomainName}" - !Sub "https://${WebUIBucket.RegionalDomainName}/index.html" Description: Amazon Lookout for Vision Demo Url Resources: SetupWebUI: Type: Custom::Setup Properties: ServiceToken: !GetAtt LambdaSetup.Arn Region: !Ref AWS::Region WebUIBucket: Type: AWS::S3::Bucket Properties: VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 CorsConfiguration: CorsRules: - AllowedHeaders: ["*"] AllowedMethods: [GET] AllowedOrigins: ["*"] Id: !Sub ${ResourcePrefix}LVCorsRule MaxAge: 3600 WebUIBucketReadPolicy: Type: AWS::S3::BucketPolicy Condition: WithCloudFront Properties: Bucket: !Ref WebUIBucket PolicyDocument: Statement: - Action: s3:GetObject Effect: Allow Resource: !Sub arn:aws:s3:::${WebUIBucket}/* Principal: CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId CognitoIdentityPool: Type: AWS::Cognito::IdentityPool Properties: IdentityPoolName: !Sub ${ResourcePrefix}IdentityPool CognitoIdentityProviders: - ClientId: !Ref CognitoUserPoolClient ProviderName: !GetAtt CognitoUserPool.ProviderName AllowUnauthenticatedIdentities: false CognitoIdentityPoolRole: Type: AWS::Cognito::IdentityPoolRoleAttachment Properties: IdentityPoolId: !Ref CognitoIdentityPool Roles: authenticated: !GetAtt LookoutVisionInvokeRole.Arn unauthenticated: !GetAtt LookoutVisionInvokeRole.Arn CognitoUserPool: Type: AWS::Cognito::UserPool Properties: UserPoolName: !Sub ${ResourcePrefix}UsersPool AdminCreateUserConfig: AllowAdminCreateUserOnly: true InviteMessageTemplate: EmailMessage: !Sub - 'Your Amazon Lookout for Vision Demo username is {username} and the temporary password is {####}

Click here to access the web interface: ${UIUrl}' - { UIUrl: !If [ WithCloudFront, !Sub "https://${CloudFrontDistribution.DomainName}", !Sub "https://${WebUIBucket.RegionalDomainName}/index.html", ], } EmailSubject: 'Your temporary password for Amazon Lookout for Vision Demo' SMSMessage: 'Your Amazon Lookout for Vision Demo username is {username} and the temporary password is {####}' AutoVerifiedAttributes: - email Policies: PasswordPolicy: MinimumLength: 8 RequireLowercase: true RequireNumbers: true RequireSymbols: true RequireUppercase: true CognitoUserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: UserPoolId: !Ref CognitoUserPool ClientName: !Sub ${ResourcePrefix}UsersPoolClient GenerateSecret: false RefreshTokenValidity: 1 PreventUserExistenceErrors: ENABLED CognitoUserPoolUser: Type: AWS::Cognito::UserPoolUser Properties: Username: !Ref AdminEmail UserPoolId: !Ref CognitoUserPool DesiredDeliveryMediums: - EMAIL UserAttributes: - Name: email Value: !Ref AdminEmail - Name: email_verified Value: "true" LookoutVisionInvokeRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Federated: - cognito-identity.amazonaws.com Action: - sts:AssumeRole - sts:AssumeRoleWithWebIdentity Condition: StringEquals: "cognito-identity.amazonaws.com:aud": !Ref CognitoIdentityPool CustomResourceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: LVDemo-setup-S3-fc PolicyDocument: Statement: - Effect: Allow Action: - s3:DeleteObject - s3:ListBucket - s3:PutObject - s3:PutObjectAcl Resource: - !GetAtt WebUIBucket.Arn - !Sub ${WebUIBucket.Arn}/* - Effect: Allow Action: s3:GetObject Resource: !Sub "arn:aws:s3:::solution-builders-${AWS::Region}/*" - PolicyName: LVDemo-cloudwatch-logs PolicyDocument: Statement: - Resource: "*" Effect: Allow Action: logs:CreateLogGroup - Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:* Effect: Allow Action: logs:CreateLogStream LambdaSetup: Type: AWS::Serverless::Function Properties: FunctionName: !Sub ${ResourcePrefix}Setup Handler: index.handler CodeUri: ../backend/functions/setup/ Description: Custom Lambda resource for the Amazon Lookout for Vision Demo Cloudformation Stack Role: !GetAtt CustomResourceRole.Arn Environment: Variables: API_GATEWAY: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/ COGNITO_IDENTITY_POOL: !Ref CognitoIdentityPool COGNITO_USER_POOL_ID: !Ref CognitoUserPool COGNITO_USER_POOL_CLIENT_ID: !Ref CognitoUserPoolClient FROM_BUCKET: !Sub solution-builders-${AWS::Region} CREATE_CLOUDFRONT_DISTRIBUTION: !Ref CreateCloudFrontDistribution TO_BUCKET: !Ref WebUIBucket CloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Condition: WithCloudFront Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref WebUIBucket CloudFrontDistribution: Type: AWS::CloudFront::Distribution Condition: WithCloudFront Properties: DistributionConfig: Origins: - DomainName: !GetAtt WebUIBucket.RegionalDomainName Id: !Sub ${ResourcePrefix}-myS3Origin S3OriginConfig: OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity} Enabled: true HttpVersion: http2 Comment: The Distribution for the Lookout for Video Demo DefaultRootObject: index.html DefaultCacheBehavior: AllowedMethods: - HEAD - GET - OPTIONS TargetOriginId: !Sub ${ResourcePrefix}-myS3Origin ForwardedValues: QueryString: false Cookies: Forward: none ViewerProtocolPolicy: redirect-to-https PriceClass: PriceClass_All ViewerCertificate: CloudFrontDefaultCertificate: true DetectHandlerFunction: Type: AWS::Serverless::Function Properties: Handler: index.detectHandler CodeUri: ../backend/functions/api/ Events: Get: Type: Api Properties: Path: /detect Method: post Policies: - Version: "2012-10-17" Statement: - Effect: Allow Action: lookoutvision:DetectAnomalies Resource: "*" ListProjectsHandlerFunction: Type: AWS::Serverless::Function Properties: Handler: index.listProjectsHandler CodeUri: ../backend/functions/api/ Events: Get: Type: Api Properties: Path: /projects Method: get Policies: - Version: "2012-10-17" Statement: - Effect: Allow Action: lookoutvision:ListProjects Resource: "*" ListModelsHandlerFunction: Type: AWS::Serverless::Function Properties: Handler: index.listModelsHandler CodeUri: ../backend/functions/api/ Events: Get: Type: Api Properties: Path: /projects/{projectName}/models Method: get Policies: - Version: "2012-10-17" Statement: - Effect: Allow Action: lookoutvision:ListModels Resource: "*" StartModelHandlerFunction: Type: AWS::Serverless::Function Properties: Handler: index.startModelHandler CodeUri: ../backend/functions/api/ Events: Get: Type: Api Properties: Path: /projects/{projectName}/models/{modelVersion}/start Method: post Policies: - Version: "2012-10-17" Statement: - Effect: Allow Action: lookoutvision:StartModel Resource: "*" StopModelHandlerFunction: Type: AWS::Serverless::Function Properties: Handler: index.stopModelHandler CodeUri: ../backend/functions/api/ Events: Get: Type: Api Properties: Path: /projects/{projectName}/models/{modelVersion}/stop Method: post Policies: - Version: "2012-10-17" Statement: - Effect: Allow Action: lookoutvision:StopModel Resource: "*"