AWS S3 预签名 URL 无效 AWS 访问密钥 ID

问题描述 投票:0回答:2

我正在我的应用程序中进行图像上传。我使用预签名的 POST URL 将文件上传到我的 S3 存储桶。负责创建 URL 的函数如下所示

  public createUrl(filename: string): Promise<string> {
    return new Promise((resolve, reject) => {
      this.s3.createPresignedPost(
        {
          Bucket: "{{bucket-name}}",
          Fields: {
            key: filename,
          },
          Conditions: [
            ["content-length-range", 0, 1048576],
            ["starts-with", "$Content-Type", "image/"],
          ],
          Expires: 120,
        },
        (error, data) => {
          if (error) reject(error);
          else resolve(data);
        },
      );
    });
  }

其中s3对象的创建如下

import { S3 } from "aws-sdk";

export const s3 = new S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});

当我使用

sls offline
命令测试所有内容时,一切似乎都工作正常,我得到以下响应

{
    "url": "https://s3.{{region}}.amazonaws.com/{{bucket-name}}",
    "fields": {
        "key": "{{filename}}.png",
        "bucket": "{{bucket-name}}",
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "AKIA{{key}}/20220619/eu-central-1/s3/aws4_request",
        "X-Amz-Date": "20220619T131035Z",
        "Policy": "{{policy-token}}",
        "X-Amz-Signature": "{{signature}}"
    }
}

然后,我可以使用所有这些值发出请求,将图像上传到我的存储桶,并且图像确实已上传。但是每当我使用

sls deploy
部署所有内容时,该函数生成的数据看起来完全正常,然后当我调用 s3 预签名 url 时,我会得到以下响应

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>InvalidAccessKeyId</Code>
    <Message>The AWS Access Key Id you provided does not exist in our records.</Message>
    <AWSAccessKeyId>ASIA{{key}}</AWSAccessKeyId>
    <RequestId>{{id}}</RequestId>
    <HostId>{{host-id}}</HostId>
</Error>

值得一提的是,当我使用

sls offline
时,我得到的密钥以
AKIA...
开头,但是当我调用已部署的版本时,我得到
ASIA...
。此外,
AWS_ACCESS_KEY_ID
环境变量设置正确,因为我也使用 DynamoDB 客户端,并且它工作正常,我使用了完全相同的变量。

typescript amazon-web-services amazon-s3 serverless
2个回答
0
投票

好吧,原来问题完全在我这边。我不知道为什么,但是当我改变线路时

export const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});

我没有使用环境变量,而是直接将这些值作为字符串,一切都神奇地开始工作。我不知道为什么会这样,因为我在设置 DynamoDB 客户端时确实使用了这些环境变量,它运行得很好。现在,我不再获得

ASIA...
键,而是获得
AKIA...
键,它们的作用就像魅力一样。


0
投票

ASIA...
vs
AKIA...
表明您正在使用 STS(使用假定角色生成的临时凭证)。这在 Lambda 中很常见,因为您不使用访问密钥,而是通过其 IAM 执行角色来承担角色。这意味着,对于每次调用,它都会生成有效期较短的临时凭证,并使用它们来执行所需的任何操作(在本例中为预签名 URL)。

实际从客户端下载/上传时,您需要在正文中发送“X-Amz-Security-Token”以及预签名时获得的值。不幸的是,AWS 没有明确记录这一点。

在 NodeJS 中,这将是:

const s3 = new AWS.S3();
const credentials = s3.config.credentials;
const sessionToken = credentials.sessionToken;

在 PHP 中是

$credentials = $s3client->getCredentials()->wait();
$sessionToken = $credentials->getSecurityToken();

上传/下载文件时,您可以将其作为正文发送:

"acl": presignUploadData.acl, // for upload
"key": presignUploadData.key, // the key you presigned for download/upload
"X-Amz-Credential": presignUploadData.XAmzCredential,
"X-Amz-Algorithm": presignUploadData.XAmzAlgorithm,
"X-Amz-Date": presignUploadData.XAmzDate,
"Policy": presignUploadData.Policy,
"X-Amz-Signature": presignUploadData.XAmzSignature,
"X-Amz-Security-Token": presignUploadData.XAmzSecurityToken,
© www.soinside.com 2019 - 2024. All rights reserved.