AWSTemplateFormatVersion: '2010-09-09' Description: 'EventBuzz Console: S3 + CloudFront OAC + SPA Routing' Resources: # 1. The S3 Bucket WebsiteBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: !Sub 'console-eventbuzz-v2-${AWS::AccountId}' # Unique name PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true # 2. Origin Access Control (The "Key") CloudFrontOAC: Type: 'AWS::CloudFront::OriginAccessControl' Properties: OriginAccessControlConfig: Name: !Sub 'OAC-${AWS::StackName}' OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4 # 3. The CloudFront Distribution WebsiteDistribution: Type: 'AWS::CloudFront::Distribution' Properties: DistributionConfig: Enabled: true DefaultRootObject: index.html Origins: - Id: S3Origin DomainName: !GetAtt WebsiteBucket.RegionalDomainName OriginAccessControlId: !GetAtt CloudFrontOAC.Id S3OriginConfig: OriginAccessIdentity: "" # Leave empty for OAC DefaultCacheBehavior: TargetOriginId: S3Origin ViewerProtocolPolicy: redirect-to-https CachePolicyId: 65832739-81ee-4e30-a434-316882a20199 # Managed-CachingOptimized CustomErrorResponses: - ErrorCode: 403 # Fixes SPA Refresh Issue ResponseCode: 200 ResponsePagePath: /index.html - ErrorCode: 404 ResponseCode: 200 ResponsePagePath: /index.html # 4. The Bucket Policy (The "Lock") BucketPolicy: Type: 'AWS::S3::BucketPolicy' Properties: Bucket: !Ref WebsiteBucket PolicyDocument: Version: '2012-10-17' Statement: - Action: 's3:GetObject' Effect: Allow Resource: !Sub 'arn:aws:s3:::${WebsiteBucket}/*' Principal: Service: 'cloudfront.amazonaws.com' Condition: StringEquals: AWS:SourceArn: !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${WebsiteDistribution}' Outputs: DistributionURL: Value: !GetAtt WebsiteDistribution.DomainName BucketName: Value: !Ref WebsiteBucket