serverless-nextjs / serverless-next.js

⚡ Deploy your Next.js apps on AWS Lambda@Edge via Serverless Components
MIT License
4.46k stars 457 forks source link

Public asset throws 403 SignatureDoesNotMatch when bucket region is not N. Virginia #496

Closed botond-veress closed 4 years ago

botond-veress commented 4 years ago

Describe the bug I use this lib for a while now, and it always worked like a charm. Good job guys!

But lately, I noticed on new projects that public assets (favicon, robots.txt, basically anything in the public folder) cannot be loaded because I get a Cloudfront/S3 SignatureDoesNotMatch error. I couldn't find anybody reporting the same issue so I started digging deeper.

To Reproduce Steps to reproduce the behavior:

  1. Set a bucket region other than N. Virginia
  2. Deploy
  3. Any file that was placed in the /public directory cannot be loaded.

P.S I could reproduce the issue in "@sls-next/serverless-component@1.15.0-alpha.5" and "serverless-next.js@1.9.10" so most likely more versions are affected.

Expected behavior I should receive the file I requested instead of the SignatureDoesNotMatch error.

Screenshots

<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId>{REDACTED}</AWSAccessKeyId>
<StringToSign>AWS4-HMAC-SHA256 20200711T085322Z 20200711/eu-central-1/s3/aws4_request ae2db368616c3ee5907fb7d3b5851ebaff0bc2ea7f4f14f07126b5668b62c302</StringToSign>
<SignatureProvided>9416a27e3980602a06eb7f92c1928f7884ce4fbfdbcaad72bf998f7906e07bc1</SignatureProvided>
<StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 30 30 37 31 31 54 30 38 35 33 32 32 5a 0a 32 30 32 30 30 37 31 31 2f 75 73 2d 65 61 73 74 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 61 65 32 64 62 33 36 38 36 31 36 63 33 65 65 35 39 30 37 66 62 37 64 33 62 35 38 35 31 65 62 61 66 66 30 62 63 32 65 61 37 66 34 66 31 34 66 30 37 31 32 36 62 35 36 36 38 62 36 32 63 33 30 32</StringToSignBytes>
<CanonicalRequest>GET /public/robots.txt host:rishapparel.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20200711T085322Z host;x-amz-content-sha256;x-amz-date e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855</CanonicalRequest>
<CanonicalRequestBytes>47 45 54 0a 2f 70 75 62 6c 69 63 2f 72 6f 62 6f 74 73 2e 74 78 74 0a 0a 68 6f 73 74 3a 72 69 73 68 61 70 70 61 72 65 6c 2e 63 6f 6d 0a 78 2d 61 6d 7a 2d 63 6f 6e 74 65 6e 74 2d 73 68 61 32 35 36 3a 65 33 62 30 63 34 34 32 39 38 66 63 31 63 31 34 39 61 66 62 66 34 63 38 39 39 36 66 62 39 32 34 32 37 61 65 34 31 65 34 36 34 39 62 39 33 34 63 61 34 39 35 39 39 31 62 37 38 35 32 62 38 35 35 0a 78 2d 61 6d 7a 2d 64 61 74 65 3a 32 30 32 30 30 37 31 31 54 30 38 35 33 32 32 5a 0a 0a 68 6f 73 74 3b 78 2d 61 6d 7a 2d 63 6f 6e 74 65 6e 74 2d 73 68 61 32 35 36 3b 78 2d 61 6d 7a 2d 64 61 74 65 0a 65 33 62 30 63 34 34 32 39 38 66 63 31 63 31 34 39 61 66 62 66 34 63 38 39 39 36 66 62 39 32 34 32 37 61 65 34 31 65 34 36 34 39 62 39 33 34 63 61 34 39 35 39 39 31 62 37 38 35 32 62 38 35 35</CanonicalRequestBytes>
<RequestId>546CC35EF0006FC3</RequestId>
<HostId>qmARkR3O4ObBkURJD67jfNK4r6mmJQvepY0mt1JcAAqhGD+6gcTnGVxOaxZNp35trI7y6YY3qpQ=</HostId>
</Error>

Desktop (please complete the following information):

Additional context As far as I know for public assets the default lambda@edge is being invoked. So I checked what happens there, and I found this in the handler:

    if (isHTMLPage || isPublicFile) {
        s3Origin.path = isHTMLPage ? "/static-pages" : "/public";
        if (isHTMLPage) {
            addS3HostHeader(request, normalisedS3DomainName);
            request.uri = `${uri}.html`;
        }

        return request;
    }

It looks like for public assets the S3 domain name is not being normalized even though public assets are retrieved from the same S3 bucket as the static pages. So I deployed a modified version of the lambda which normalized it and it fixed the problem.

Can you confirm this is a proper solution?

P.S 2: I forked the repo and wanted to create a PR, but it looks like the lerna exec fails on master and a lot of tests are failing in the lambda-at-edge package, so I will let you fix it if this is the proper solution.

danielcondemarin commented 4 years ago

Thanks for reporting @botond-veress !

Could you post your serverless.yml as well? We got a PR in progresss here (https://github.com/serverless-nextjs/serverless-next.js/pull/495) that may also fix this if my last suggestion in this comment is implemented. I suspect there is something weird going on with S3 regional endpoints and the CloudFront distribution.

danielcondemarin commented 4 years ago

Also to get the project working locally for you this should help.

botond-veress commented 4 years ago

Thanks for the fast reply @danielcondemarin.

Here is the serverless.yml:

nextApp:
  component: '@sls-next/serverless-component@1.15.0-alpha.5'
  inputs:
    domain:
      - ${env.SUBDOMAIN}
      - ${env.HOSTED_ZONE}
    domainType: apex
    bucketName: ${env.BUCKET_NAME}
    bucketRegion: ${env.AWS_DEFAULT_REGION}
    memory: 1024

Btw, I followed the CONTRIBUTING guide but as I said the yarn fails, because during postinstall the lerna exec fails to install aws-sdk:

$ yarn
yarn install v1.21.1
[1/4] 🔍  Resolving packages...
success Already up-to-date.
$ yarn packages-install && opencollective-postinstall || true
yarn run v1.21.1
$ lerna exec -- yarn install --frozen-lockfile
lerna notice cli v3.22.1
lerna info versioning independent
lerna info Executing command in 10 packages: "yarn install --frozen-lockfile"
[1/4] 🔍  Resolving packages...
[1/4] 🔍  Resolving packages...
success Already up-to-date.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
error https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz: Extracting tar content of undefined failed, the file appears to be corrupt: "ENOENT: no such file or directory, stat '/Users/botondveress/Library/Caches/Yarn/v6/npm-aws-sdk-2.706.0-09f65e9a91ecac5a635daf934082abae30eca953-integrity/node_modules/aws-sdk/dist/aws-sdk-react-native.js'"
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
lerna ERR! yarn install --frozen-lockfile exited 1 in '@sls-next/cloudfront'
lerna ERR! yarn install --frozen-lockfile exited 1 in '@sls-next/cloudfront'
lerna WARN complete Waiting for 4 child processes to exit. CTRL-C to exit immediately.
error Command failed with exit code 1.
danielcondemarin commented 4 years ago

error https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz: Extracting tar content of undefined failed,

Mmh that same error has happened on CI before a few times, never for me locally though. Probably worth starting by bumping the aws-sdk in the packages that is being used and see if that fixes it?

botond-veress commented 4 years ago

@danielcondemarin I opened a tiny PR so this can fixed until https://github.com/serverless-nextjs/serverless-next.js/pull/495 gets merged.

danielcondemarin commented 4 years ago

I've just published @sls-next/serverless-component@1.15.1 with your PR