AWS S3 - 从 getSignedUrl() PUT 到 URL 返回 403 SignatureDoesNotMatch 错误

pko*_*pen 2 amazon-s3 node.js aws-lambda serverless

这个问题已经让我发疯了两天了。

目标:通过 AWS Javascript SDK 中的 getSignedUrl 函数提供的预签名 URL,将图像直接从浏览器上传到 S3。

我在使用 getSignedUrl 生成 URL 时没有遇到任何问题。下面的代码...

const params = {
  Key:         key,
  Bucket:      process.env.S3_BUCKET,
  ContentType: "image/jpeg"
};

S3.getSignedUrl("putObject", params, callback);
Run Code Online (Sandbox Code Playgroud)

...产生类似:

https://s3.amazonaws.com/foobar-bucket/someImage.jpeg?AWSAccessKeyId=ACCESSKEY123&Content-Type=image%2Fjpeg&Expires=1543357053&Signature=3fgjyj7gpJiQvbIGhqWXSY40JUU%3D&x-amz-acl=private&x-amz-security-token=FQoGZXIvYXdzEDYaDPzeqKMbfgetCcZBaCL0AWftL%2BIT%2BP3tqTDVtNU1G8eC9sjl9unhwknrYvnEcrztfR9%2FO9AGD6VDiDDKfTQ9SmQpfXmiyTKDwAcevTwxeRnj6hGwnHgvzFVBzoslrB8MxrxjUpiI7NQW3oRMunbLskZ4LgvQYs8Rh%2FDjat4H%2F%2BvfPxDSQUSa41%2BFKcoySUHGh2xqfBFGCkHlIqVgk1KELDHmTaNckkvc9B4cgEXmAd3u1f1KC9mbobYcLLRPIzMj9bLJH%2BIlINylzubao1pCQ7m%2BWdX5xAZDhTSNwQfo4ywSWV7kUpbq2dgEriOiKAReEjmFQtuGqYBi3t2dhrasptOlXFXUozdz23wU%3D

但是通过 PUT 请求将图像上传到提供的 URL 总是会403 SignatureDoesNotMatch从 S3返回错误。

有什么作用:

  • 从 AWS Lambda 的本地实例(通过无服务器离线)调用 getSignedUrl()。

什么不起作用:

  • 将查询字符串变量设置为标题(Content-Type、x-amz-* 等)
  • 删除所有标题
  • 获取 URL 时更改 ACL(私有、公共读写、无 ACL 等)
  • 更改aws-sdk节点中的区域
  • 尝试 POST 而不是 PUT(值得一试)

对此问题的任何帮助将不胜感激。如果这仍然是一个问题,我将把我的电脑扔出窗外,然后沮丧地跳出去,因为它根本不想工作!

pko*_*pen 8

I figured it out. The Lambda function invoking getSignedUrl() did not have the correct IAM role permissions to access the S3 bucket in question. In serverless.yml...

iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:*
      Resource: "arn:aws:s3:::foobar-bucket/*"
Run Code Online (Sandbox Code Playgroud)

I wouldn't actually use a wildcard here, but you get the picture. The fact that getSignedUrl() still succeeds and returns a URL even when the URL is doomed to fail because of missing permissions is extremely misleading.

I hope this answer helps some confused soul in the future.