{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Stands up resources needed to support the ImageRecognition demo application.", "Parameters": { "DnsName" : { "Type" : "String", "Default" : "", "MinLength" : "0", "Description" : "Optional DNS Host name that is assigned to the load balancer." }, "LoadbalancerCertificateArn" : { "Type" : "String", "Default" : "", "MinLength" : "0", "Description" : "Optional certificate arn from ACM. If set an HTTPS listner will be configured." }, "S3BucketName":{ "Type" : "AWS::SSM::Parameter::Value", "Default" : "/ImageRecognition/AWS/BlazorS3BucketName", "Description" : "Blazor S3 Bucket." } }, "Conditions" : { "UseHttps" : { "Fn::Not" : [{ "Fn::Equals" : [ {"Ref" : "LoadbalancerCertificateArn"}, "" ] }] }, "HasDnsName" : { "Fn::Not" : [{ "Fn::Equals" : [ {"Ref" : "DnsName"}, "" ] }] } }, "Resources": { "TableAlbum": { "Type": "AWS::DynamoDB::Table", "Description": "", "Properties": { "AttributeDefinitions": [ { "AttributeName": "AlbumId", "AttributeType": "S" }, { "AttributeName": "UserId", "AttributeType": "S" } ], "KeySchema": [ { "AttributeName": "UserId", "KeyType": "HASH" }, { "AttributeName": "AlbumId", "KeyType": "RANGE" } ], "ProvisionedThroughput": { "ReadCapacityUnits": "10", "WriteCapacityUnits": "1" }, "TableName": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "Album" ] ] } } }, "TablePhoto": { "Type": "AWS::DynamoDB::Table", "Description": "", "Properties": { "AttributeDefinitions": [ { "AttributeName": "PhotoId", "AttributeType": "S" }, { "AttributeName": "AlbumId", "AttributeType": "S" }, { "AttributeName": "UploadTime", "AttributeType": "S" } ], "GlobalSecondaryIndexes": [ { "IndexName" : "albumID-uploadTime-index", "KeySchema" : [ { "AttributeName": "AlbumId", "KeyType": "HASH" }, { "AttributeName": "UploadTime", "KeyType": "RANGE" } ], "Projection" : {"ProjectionType" : "ALL"}, "ProvisionedThroughput" : { "ReadCapacityUnits": "30", "WriteCapacityUnits": "30" } } ], "KeySchema": [ { "AttributeName": "PhotoId", "KeyType": "HASH" } ], "ProvisionedThroughput": { "ReadCapacityUnits": "30", "WriteCapacityUnits": "30" }, "TableName": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "Photo" ] ] } } }, "TableCommunicationConnection": { "Type": "AWS::DynamoDB::Table", "Description": "", "Properties": { "AttributeDefinitions": [ { "AttributeName": "connectionId", "AttributeType": "S" }, { "AttributeName" : "username", "AttributeType" : "S" } ], "KeySchema": [ { "AttributeName": "connectionId", "KeyType": "HASH" } ], "GlobalSecondaryIndexes" : [ { "IndexName" : "username", "KeySchema" : [ { "AttributeName" : "username", "KeyType" : "HASH" } ], "Projection" : { "ProjectionType" : "ALL" } } ], "BillingMode" : "PAY_PER_REQUEST", "TableName": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "CommunicationConnections" ] ] } } }, "S3BucketPolicy": { "Type": "AWS::S3::BucketPolicy", "Properties": { "Bucket": { "Ref": "S3BucketName" }, "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": ["s3:GetObject"], "Effect": "Allow", "Resource": {"Fn::Sub": "arn:aws:s3:::${S3BucketName}/*" }, "Principal": { "CanonicalUser": {"Fn::GetAtt" : [ "CfOriginAccessIdentity", "S3CanonicalUserId"]} } }] } } }, "CfOriginAccessIdentity": { "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", "Properties": { "CloudFrontOriginAccessIdentityConfig": { "Comment": "Access S3 bucket content only through CloudFront" } } }, "BlazorWASMDistribution" : { "Type" : "AWS::CloudFront::Distribution", "Properties" : { "DistributionConfig" : { "DefaultCacheBehavior" : { "AllowedMethods" : [ "GET", "HEAD"], "CachedMethods": [ "GET", "HEAD"], "Compress": "false", "DefaultTTL": "86400", "TargetOriginId" : {"Fn::Sub": "s3-origin-${S3BucketName}" }, "ForwardedValues" : { "Headers": ["Origin"], "QueryString" : "false", "Cookies" : { "Forward" : "none" } }, "ViewerProtocolPolicy" : "redirect-to-https" }, "Enabled" : "true", "DefaultRootObject" : "index.html", "IPV6Enabled": "false", "PriceClass" : "PriceClass_All", "CustomErrorResponses":[ { "ErrorCachingMinTTL" : 1440, "ErrorCode" : 403, "ResponseCode" : 404, "ResponsePagePath" : "/404.html" } ], "Origins" : [ { "DomainName" : {"Fn::Sub": "${S3BucketName}.s3.amazonaws.com" }, "Id" : {"Fn::Sub": "s3-origin-${S3BucketName}" }, "S3OriginConfig" : { "OriginAccessIdentity" : { "Fn::Sub": "origin-access-identity/cloudfront/${CfOriginAccessIdentity}"} } }] } } }, "UserPool": { "Type": "AWS::Cognito::UserPool", "Properties":{ "UserPoolName": {"Fn::Join": ["-",[{"Ref": "AWS::StackName"},"user-pool"]]}, "UsernameAttributes": ["email"], "AutoVerifiedAttributes": ["email"], "Schema": [{"AttributeDataType" : "String", "Name" : "email", "Required" : false}] } }, "UserPoolClient":{ "Type": "AWS::Cognito::UserPoolClient", "Properties":{ "ClientName": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "web-client" ] ] }, "GenerateSecret": false, "AllowedOAuthFlows": ["code", "implicit"], "AllowedOAuthFlowsUserPoolClient": true, "SupportedIdentityProviders": ["COGNITO"], "AllowedOAuthScopes": ["phone","email","openid","profile"], "CallbackURLs": [{ "Fn::Sub": "https://${BlazorWASMDistribution.DomainName}/authentication/login-callback"}], "LogoutURLs":[{ "Fn::Sub": "https://${BlazorWASMDistribution.DomainName}/authentication/logout-callback"}], "UserPoolId": {"Ref": "UserPool"} } }, "UserPoolDomain": { "Type" : "AWS::Cognito::UserPoolDomain", "Properties" : { "Domain" : { "Fn::Select" : [ "2", { "Fn::Split": ["-", {"Ref": "S3BucketName"}]}] }, "UserPoolId" : {"Ref": "UserPool"} } }, "ParameterUserPool": { "Type": "AWS::SSM::Parameter", "Description": "Stores the name of the UserPool for application.", "Properties": { "Type": "String", "Value": { "Ref": "UserPool" }, "Name": "/ImageRecognition/AWS/UserPoolId" } }, "ParameterUserPoolClient": { "Type": "AWS::SSM::Parameter", "Description": "Stores the name of the UserPoolClient.", "Properties": { "Type": "String", "Value": { "Ref": "UserPoolClient" }, "Name": "/ImageRecognition/AWS/UserPoolClientId" } }, "ParameterTableAlbum": { "Type": "AWS::SSM::Parameter", "Description": "Stores the name of the DynamoDB table holding details of processed galleries to Parameter Store.", "Properties": { "Type": "String", "Value": { "Ref": "TableAlbum" }, "Name": "/ImageRecognition/AppOptions/TableAlbum" } }, "ParameterTablePhoto": { "Type": "AWS::SSM::Parameter", "Description": "Stores the name of the DynamoDB table holding gallery items to Parameter Store.", "Properties": { "Type": "String", "Value": { "Ref": "TablePhoto" }, "Name": "/ImageRecognition/AppOptions/TablePhoto" } }, "ParameterTableCommunicationConnections": { "Type": "AWS::SSM::Parameter", "Description": "Stores the connection ids for the websocket connections made in the client.", "Properties": { "Type": "String", "Value": { "Ref": "TableCommunicationConnection" }, "Name": "/ImageRecognition/AppOptions/TableCommunicationConnection" } }, "ParameterCloudFrontDistribution": { "Type": "AWS::SSM::Parameter", "Description": "Stores the Domain name of the distribution.", "Properties": { "Type": "String", "Value": {"Fn::Sub": "https://${BlazorWASMDistribution.DomainName}"}, "Name": "/ImageRecognition/AWS/CloudFrontDomain" } }, "ParameterAuthDomainPrefix": { "Type": "AWS::SSM::Parameter", "Description": "Stores the Domain name of the distribution.", "Properties": { "Type": "String", "Value": { "Ref": "UserPoolDomain" }, "Name": "/ImageRecognition/AWS/AuthDomainPrefix" } }, "ParameterCognitoAuthority": { "Type": "AWS::SSM::Parameter", "Description": ".", "Properties": { "Type": "String", "Value": { "Fn::Sub": "https://cognito-idp.${AWS::Region}.amazonaws.com/${ParameterUserPool.Value}" }, "Name": "/ImageRecognition/Cognito/Authority" } }, "ParameterCognitoClientId": { "Type": "AWS::SSM::Parameter", "Description": ".", "Properties": { "Type": "String", "Value": { "Fn::Sub": "${ParameterUserPoolClient.Value}"}, "Name": "/ImageRecognition/Cognito/ClientId" } }, "ParameterCognitoRedirectUri": { "Type": "AWS::SSM::Parameter", "Description": ".", "Properties": { "Type": "String", "Value": { "Fn::Sub": "${ParameterCloudFrontDistribution.Value}/authentication/login-callback" }, "Name": "/ImageRecognition/Cognito/RedirectUri" } }, "ParameterCognitoLogoutRedirectUri": { "Type": "AWS::SSM::Parameter", "Description": ".", "Properties": { "Type": "String", "Value": { "Fn::Sub": "${ParameterCloudFrontDistribution.Value}/authentication/logout-callback" }, "Name": "/ImageRecognition/Cognito/PostLogoutRedirectUri" } } }, "Outputs": { } }