AWS CloudFront访问API Gateway时出现IncompleteSignatureException问题排查
问题描述
我正尝试配置AWS CloudFront与API Gateway:CloudFront配置了两个源指向同一API Gateway,默认行为/*路由到API Gateway的/dev/react路径(对应SSR Lambda渲染React页面),/api/*行为路由到/dev/api路径(对应受Cognito Authorizer保护的API Lambda,请求均携带Authorization头)。
直接通过API Gateway域名访问时一切正常,但通过CloudFront访问时,React应用可正常加载,但调用API接口时出现IncompleteSignatureException错误。尝试转发Host头等配置后问题仍未解决。查阅AWS文档得知该错误可能是携带Authorization头的请求发送到了不存在的API资源路径,但无法明确该解释在当前场景中的具体含义。
疑问点:
- 是否是路由配置有误?
- 是否缺少API Gateway的别名域名?
- 是什么原因导致CloudFront无法找到该路径下的资源?
附上CloudFront分发配置:
Resources: CloudFrontDistribution: Type: AWS::CloudFront::Distribution Properties: Description: DistributionConfig: Origins: - Id: Frontend DomainName: Fn::Join: - "" - - Ref: ApiGatewayRestApi - .execute-api. - Ref: AWS::Region - .amazonaws.com OriginPath: /${self:custom.stage} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 OriginProtocolPolicy: https-only - Id: Backend DomainName: Fn::Join: - "" - - 'Fn::ImportValue': 'eventkraefte-portal-backend-${self:custom.stage}-ApiGatewayRestApiId' - .execute-api. - Ref: AWS::Region - .amazonaws.com OriginPath: /${self:custom.stage} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 OriginProtocolPolicy: https-only Enabled: "true" Comment: CDN for frontend and backend Lambdas. DefaultCacheBehavior: AllowedMethods: - DELETE - GET - HEAD - OPTIONS - PATCH - POST - PUT TargetOriginId: Frontend ForwardedValues: QueryString: "false" Cookies: Forward: none DefaultTTL: 1 ViewerProtocolPolicy: redirect-to-https CacheBehaviors: - PathPattern: "/api/*" AllowedMethods: - DELETE - GET - HEAD - OPTIONS - PATCH - POST - PUT TargetOriginId: Backend ForwardedValues: Headers: - Authorization QueryString: "false" Cookies: Forward: none DefaultTTL: 1 ViewerProtocolPolicy: redirect-to-https Aliases: - ${self:custom.domain} ViewerCertificate: AcmCertificateArn: ${self:custom.certificate} SslSupportMethod: sni-only
问题分析与解决方案
核心问题:Host头缺失导致签名验证失败
IncompleteSignatureException的本质不是路径不存在,而是API Gateway无法通过Cognito的签名验证——因为CloudFront默认不会转发原始请求的Host头,而是把自己的域名作为Host头发送给API Gateway。而API Gateway的签名验证要求Host头必须匹配它自身的execute-api域名(比如xxxx.execute-api.us-east-1.amazonaws.com),不匹配的话签名直接验证失败,就会抛出这个错误。
修复步骤
修改Backend缓存行为的转发头配置
在CacheBehaviors中对应/api/*的规则里,把Host头加入转发列表:CacheBehaviors: - PathPattern: "/api/*" # 其他配置保持不变 ForwardedValues: Headers: - Authorization - Host # 新增该行,转发Host头 QueryString: "false" Cookies: Forward: none验证路径拼接逻辑
当前配置中,Backend源的OriginPath是/${self:custom.stage}(即/dev),当用户请求https://你的域名/api/xxx时,CloudFront会把路径拼接成/dev/api/xxx发送给API Gateway。你需要确认API Gateway在dev阶段下的资源路径确实是/api/xxx——API Gateway的请求格式就是/{stage}/{resource},所以这个拼接逻辑是正确的,如果你的API资源路径配置没问题,这一步无需调整。关于API Gateway别名域名
你的场景完全不需要额外配置API Gateway的别名域名,只要CloudFront能正确转发请求到API Gateway的execute-api域名即可。
额外验证建议
- 打开API Gateway的访问日志,查看实际接收到的
Host头和请求路径,能快速确认问题是否解决。 - 用curl测试:
如果这个请求能正常响应,说明Host头转发是关键修复点。curl -H "Authorization: Bearer 你的令牌" -H "Host: 你的API Gateway execute-api域名" https://你的CloudFront域名/api/测试接口路径
内容的提问来源于stack exchange,提问作者Jakob

