AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: 'Lab1 - Basic Serverless Application' Parameters: EEAssetsBucket: Description: "Region-specific assets S3 bucket name (e.g. ee-assets-prod-us-east-1)" Type: String Default: "aws-sam-cli-managed-default-samclisourcebucket-8tf6bmi4rdcx" EEAssetsKeyPrefix: Description: "S3 key prefix where this modules assets are stored. (e.g. modules/my_module/v1/)" Type: String Default: "serverless-saas/" StageName: Type: String Default: prod Description: Stage Name for the api Globals: Function: Timeout: 29 Layers: - Fn::Sub: arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14 Environment: Variables: LOG_LEVEL: DEBUG Resources: ApiGatewayCloudWatchPublishRole: Type: AWS::IAM::Role Properties: Path: '/' AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - apigateway.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs AttachCloudWatchRoleToApiGateway: Type: AWS::ApiGateway::Account Properties: CloudWatchRoleArn: !GetAtt ApiGatewayCloudWatchPublishRole.Arn ServerlessSaaSLayers: Type: AWS::Serverless::LayerVersion Properties: LayerName: serverless-saas-workshoplab1 Description: Utilities for project ContentUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}1b6d1796b5948e393749602691c77e44 CompatibleRuntimes: - python3.9 LicenseInfo: MIT RetentionPolicy: Retain Metadata: BuildMethod: python3.9 ProductTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: productId AttributeType: S KeySchema: - AttributeName: productId KeyType: HASH BillingMode: PAY_PER_REQUEST TableName: Product-Lab1 OrderTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: orderId AttributeType: S KeySchema: - AttributeName: orderId KeyType: HASH BillingMode: PAY_PER_REQUEST TableName: Order-Lab1 ProductFunctionExecutionRole: Type: AWS::IAM::Role Properties: RoleName: product-function-execution-role-lab1 Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess Policies: - PolicyName: product-function-policy-lab1 PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - dynamodb:GetItem - dynamodb:UpdateItem - dynamodb:PutItem - dynamodb:DeleteItem - dynamodb:Query - dynamodb:Scan Resource: - Fn::GetAtt: - ProductTable - Arn GetProductFunction: Type: AWS::Serverless::Function DependsOn: ProductFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}3f9284a8b1fb9547d59e56cc8560b94c Handler: product_service.get_product Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - ProductFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: ProductService PRODUCT_TABLE_NAME: Ref: ProductTable GetProductsFunction: Type: AWS::Serverless::Function DependsOn: ProductFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}3f9284a8b1fb9547d59e56cc8560b94c Handler: product_service.get_products Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - ProductFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: ProductService PRODUCT_TABLE_NAME: Ref: ProductTable CreateProductFunction: Type: AWS::Serverless::Function DependsOn: ProductFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}3f9284a8b1fb9547d59e56cc8560b94c Handler: product_service.create_product Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - ProductFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: ProductService PRODUCT_TABLE_NAME: Ref: ProductTable UpdateProductFunction: Type: AWS::Serverless::Function DependsOn: ProductFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}3f9284a8b1fb9547d59e56cc8560b94c Handler: product_service.update_product Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - ProductFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: ProductService PRODUCT_TABLE_NAME: Ref: ProductTable DeleteProductFunction: Type: AWS::Serverless::Function DependsOn: ProductFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}3f9284a8b1fb9547d59e56cc8560b94c Handler: product_service.delete_product Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - ProductFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: ProductService PRODUCT_TABLE_NAME: Ref: ProductTable OrderFunctionExecutionRole: Type: AWS::IAM::Role Properties: RoleName: order-function-execution-role-lab1 Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess Policies: - PolicyName: order-function-policy-lab1 PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - dynamodb:GetItem - dynamodb:UpdateItem - dynamodb:PutItem - dynamodb:DeleteItem - dynamodb:Query - dynamodb:Scan Resource: - Fn::GetAtt: - OrderTable - Arn GetOrdersFunction: Type: AWS::Serverless::Function DependsOn: OrderFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}ac28465dbac64f71e4739d551119c420 Handler: order_service.get_orders Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - OrderFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: OrderService ORDER_TABLE_NAME: Ref: OrderTable GetOrderFunction: Type: AWS::Serverless::Function DependsOn: OrderFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}ac28465dbac64f71e4739d551119c420 Handler: order_service.get_order Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - OrderFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: OrderService ORDER_TABLE_NAME: Ref: OrderTable CreateOrderFunction: Type: AWS::Serverless::Function DependsOn: OrderFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}ac28465dbac64f71e4739d551119c420 Handler: order_service.create_order Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - OrderFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: OrderService ORDER_TABLE_NAME: Ref: OrderTable UpdateOrderFunction: Type: AWS::Serverless::Function DependsOn: OrderFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}ac28465dbac64f71e4739d551119c420 Handler: order_service.update_order Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - OrderFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: OrderService ORDER_TABLE_NAME: Ref: OrderTable DeleteOrderFunction: Type: AWS::Serverless::Function DependsOn: OrderFunctionExecutionRole Properties: CodeUri: Bucket: !Ref EEAssetsBucket Key: !Sub ${EEAssetsKeyPrefix}ac28465dbac64f71e4739d551119c420 Handler: order_service.delete_order Runtime: python3.9 Tracing: Active Role: Fn::GetAtt: - OrderFunctionExecutionRole - Arn Layers: - Ref: ServerlessSaaSLayers Environment: Variables: POWERTOOLS_SERVICE_NAME: OrderService ORDER_TABLE_NAME: Ref: OrderTable ApiGatewayAccessLogs: Type: AWS::Logs::LogGroup Properties: LogGroupName: /aws/api-gateway/access-logs-serverless-saas-workshop-lab1-api RetentionInDays: 30 ApiGatewayApi: Type: AWS::Serverless::Api Properties: MethodSettings: - DataTraceEnabled: true LoggingLevel: INFO MetricsEnabled: true ResourcePath: /* HttpMethod: '*' AccessLogSetting: DestinationArn: Fn::GetAtt: - ApiGatewayAccessLogs - Arn Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "caller":"$context.identity.caller", "user":"$context.identity.user","requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }' TracingEnabled: true DefinitionBody: openapi: 3.0.1 info: title: serverless-saas-workshop-lab1 basePath: Fn::Join: - '' - - / - Ref: StageName schemes: - https paths: /order/{id}: get: summary: Returns a order description: Return a order by a order id. produces: - application/json parameters: - name: id in: path required: true type: string responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - GetOrderFunction - Arn - /invocations httpMethod: POST type: aws_proxy put: produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - UpdateOrderFunction - Arn - /invocations httpMethod: POST type: aws_proxy delete: summary: Deletes a order description: Deletes a order by a order id. produces: - application/json parameters: - name: id in: path required: true type: string responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - DeleteOrderFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock /orders: get: summary: Returns all orders description: Returns all orders. produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - GetOrdersFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock /order: post: produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - CreateOrderFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock /product/{id}: get: summary: Returns a product description: Return a product by a product id. produces: - application/json parameters: - name: id in: path required: true type: string responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - GetProductFunction - Arn - /invocations httpMethod: POST type: aws_proxy put: produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - UpdateProductFunction - Arn - /invocations httpMethod: POST type: aws_proxy delete: summary: Deletes a product description: Deletes a product by a product id. produces: - application/json parameters: - name: id in: path required: true type: string responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - DeleteProductFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock /products: get: summary: Returns all products description: Returns all products. produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - GetProductsFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock /product: post: produces: - application/json responses: {} x-amazon-apigateway-integration: uri: Fn::Join: - '' - - Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/ - Fn::GetAtt: - CreateProductFunction - Arn - /invocations httpMethod: POST type: aws_proxy options: consumes: - application/json produces: - application/json responses: '200': description: 200 response schema: $ref: '#/definitions/Empty' headers: Access-Control-Allow-Origin: type: string Access-Control-Allow-Methods: type: string Access-Control-Allow-Headers: type: string x-amazon-apigateway-integration: responses: default: statusCode: 200 responseParameters: method.response.header.Access-Control-Allow-Methods: '''DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT''' method.response.header.Access-Control-Allow-Headers: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token''' method.response.header.Access-Control-Allow-Origin: '''*''' passthroughBehavior: when_no_match requestTemplates: application/json: '{"statusCode": 200}' type: mock StageName: Ref: StageName GetProductsLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - GetProductsFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* GetProductLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - GetProductFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* CreateProductLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - CreateProductFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* UpdateProductLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - UpdateProductFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* DeleteProductLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - DeleteProductFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* GetOrdersLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - GetOrdersFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* GetOrderLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - GetOrderFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* CreateOrderLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - CreateOrderFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* UpdateOrderLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - UpdateOrderFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* DeleteOrderLambdaApiGatewayExecutionPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - DeleteOrderFunction - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - '' - - 'arn:aws:execute-api:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - ':' - Ref: ApiGatewayApi - /*/*/* CloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: Origin Access Identity for CloudFront Distribution AppBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: 'AES256' PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true AppSiteReadPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: AppBucket PolicyDocument: Statement: - Action: s3:GetObject Effect: Allow Resource: Fn::Sub: arn:aws:s3:::${AppBucket}/* Principal: CanonicalUser: Fn::GetAtt: - CloudFrontOriginAccessIdentity - S3CanonicalUserId ApplicationSite: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: CustomErrorResponses: - ErrorCode: 403 ResponseCode: 200 ResponsePagePath: /index.html - ErrorCode: 404 ResponseCode: 200 ResponsePagePath: /index.html DefaultCacheBehavior: AllowedMethods: - DELETE - GET - HEAD - OPTIONS - PATCH - POST - PUT Compress: true DefaultTTL: 3600 ForwardedValues: Cookies: Forward: none QueryString: false MaxTTL: 86400 MinTTL: 60 TargetOriginId: lab1-tenantapp-s3origin ViewerProtocolPolicy: allow-all DefaultRootObject: index.html Enabled: true HttpVersion: http2 Origins: - DomainName: Fn::GetAtt: - AppBucket - RegionalDomainName Id: lab1-tenantapp-s3origin S3OriginConfig: OriginAccessIdentity: Fn::Join: - '' - - origin-access-identity/cloudfront/ - Ref: CloudFrontOriginAccessIdentity PriceClass: PriceClass_All Outputs: APIGatewayURL: Description: API Gateway endpoint URL for API Value: Fn::Join: - '' - - Fn::Sub: https://${ApiGatewayApi}.execute-api.${AWS::Region}.amazonaws.com/ - Ref: StageName - / ApplicationSite: Description: The name of the CloudFront url for Tenant Management site Value: Fn::GetAtt: - ApplicationSite - DomainName AppBucket: Description: The name of the bucket for uploading the Tenant Management site to Value: Ref: AppBucket