On AWS, is it possible to have CloudFront proxy requests to API Gateway while maintaining the request's query string?

Solution 1:

This caught me out too, with both the query string and headers such as Authorization.

However, the docs state that to pass the Authorization header to the origin it must be used as a cache key:

Cache key settings specify the values in viewer requests that CloudFront includes in the cache key. The values can include URL query strings, HTTP headers, and cookies. The values that you include in the cache key are automatically included in requests that CloudFront sends to the origin, known as origin requests.

and

Note: You can't use an origin request policy to forward the Authorization header. The header must be a part of the cache key to prevent the cache from satisfying unauthorized requests. CloudFront returns an HTTP 400 error if you try to create an origin request policy that forwards the Authorization header.

Additionally, note that in relation to the Origin Request Policy Managed-AllViewer, the issue looks to be the forwarding of the Host header to API Gateway; see https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/571#issuecomment-792051286 i.e. we can't use the Managed-AllViewer for API Gateway origins.

See

  1. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html
  2. https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-authorization-header/

As part of a CDK cloudfront.Distribution() construct:

const apiCachePolicy = new cloudfront.CachePolicy(this, 'ApiCachePolicy', {
        headerBehavior: cloudfront.CacheHeaderBehavior.allowList('authorization'),
        queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
        cookieBehavior: cloudfront.CacheCookieBehavior.none(),
        minTtl: Duration.minutes(0),
        maxTtl: Duration.minutes(1),
        defaultTtl: Duration.minutes(0),
        enableAcceptEncodingGzip: true,
        enableAcceptEncodingBrotli: true,
    });