AWS CDK部署React静态S3网站遇CloudFront 403访问拒绝问题
问题描述
我正尝试通过AWS CDK将React应用部署为S3静态网站,已花费数小时排查但仍未定位问题。该应用在本地运行正常,但部署到S3后,访问CloudFront域名或自定义域名dev.mywebsite.com时均出现403访问拒绝错误。
CDK代码
from aws_cdk import ( Stack, Tags, CfnOutput, aws_iam as iam, aws_s3 as s3, aws_cloudfront as cloudfront, aws_cloudfront_origins as cloudfront_origins, aws_route53 as r53, aws_route53_targets as route53_targets, aws_certificatemanager as acm, aws_s3_deployment as s3_deployment, RemovalPolicy, ) from constructs import Construct class CFS3StaticAppStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # S3 Bucket for hosting the website site_bucket = s3.Bucket( self, "SiteBucket", bucket_name="s3-static-app", public_read_access=False, website_index_document="index.html", website_error_document="error.html", removal_policy=RemovalPolicy.DESTROY, block_public_access=s3.BlockPublicAccess.BLOCK_ALL, ) # CloudFront OAI oai = cloudfront.OriginAccessIdentity(self, "OAI") # Update the S3 bucket policy to allow access from CloudFront site_bucket.add_to_resource_policy( iam.PolicyStatement( actions=["s3:GetObject"], resources=[site_bucket.bucket_arn + "/*"], principals=[oai.grant_principal], ) ) # Add CORS configuration site_bucket.add_cors_rule( allowed_methods=[s3.HttpMethods.GET], allowed_origins=["*"], allowed_headers=["*"], ) # CloudFront distribution for the website distribution = cloudfront.Distribution( self, "SiteDistribution", default_behavior=cloudfront.BehaviorOptions( origin=cloudfront_origins.S3Origin( site_bucket, origin_access_identity=oai ), viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, ), default_root_object="index.html", error_responses=[ cloudfront.ErrorResponse( http_status=404, # Error code response_page_path="/error.html", response_http_status=404, ) ], ) # Deploy the React application to S3 s3_deployment.BucketDeployment( self, "ReactAppStaticWebsite", sources=[s3_deployment.Source.asset("./client_react/dist")], destination_bucket=site_bucket, distribution=distribution, distribution_paths=["/*"], ) # Route53 alias record for the CloudFront distribution zone = r53.HostedZone.from_lookup(self, "Zone", domain_name="mywebsite.com") acm_cert = acm.Certificate.from_certificate_arn( self, "Cert", "arn:aws:acm:region:account:certificate/your-certificate-id" ) # A record r53.ARecord( self, "SiteAliasRecord", zone=zone, target=r53.RecordTarget.from_alias( route53_targets.CloudFrontTarget(distribution) ), record_name="dev.mywebsite.com", ) # Output CloudFront URL CfnOutput( self, "DistributionDomainName", value=distribution.distribution_domain_name ) # Add tags to all resources in this stack Tags.of(self).add("Project", "Blah") Tags.of(self).add("Environment", "Blah")
错误信息
403 错误
请求无法被处理。
错误请求。目前无法连接到此应用或网站的服务器。可能是流量过大或配置错误。请稍后重试,或联系应用/网站所有者。
如果你通过CloudFront向客户提供内容,可以查看CloudFront文档获取故障排查步骤并避免此类错误。
由CloudFront生成
请求ID: xxxxxxxxxxxxxxxxxxxxx
排查与修复方案
1. 关联ACM证书到CloudFront分发
代码中已引用ACM证书,但未将其配置到CloudFront分发中。使用自定义域名时,CloudFront必须关联us-east-1区域的ACM证书,否则会导致请求被拒绝。
修改Distribution配置,添加证书和自定义域名参数:
distribution = cloudfront.Distribution( self, "SiteDistribution", default_behavior=cloudfront.BehaviorOptions( origin=cloudfront_origins.S3Origin( site_bucket, origin_access_identity=oai ), viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, ), default_root_object="index.html", error_responses=[ cloudfront.ErrorResponse( http_status=404, response_page_path="/index.html", response_http_status=200, ), cloudfront.ErrorResponse( http_status=403, response_page_path="/index.html", response_http_status=200, ) ], certificate=acm_cert, # 关联证书 domain_names=["dev.mywebsite.com"], # 绑定自定义域名 )
2. 修复SPA路由错误处理
React单页应用直接访问子路由时,CloudFront会返回404,需将404/403错误重定向到index.html,由React路由处理页面跳转。修改上述代码中的error_responses配置即可。
3. 验证S3部署内容
确认./client_react/dist目录存在且构建产物完整,检查S3 Bucket中是否已同步index.html等核心文件。若部署未成功,CloudFront请求时会因找不到资源返回403。
4. 确认ACM证书区域
ACM证书必须部署在us-east-1区域,即使Bucket和CloudFront位于其他区域。检查引用的证书ARN对应的区域是否正确。
内容的提问来源于stack exchange,提问作者Pythoner

