如何使用预签名的 url 将对象放入 amazon s3?

Posted

技术标签:

【中文标题】如何使用预签名的 url 将对象放入 amazon s3?【英文标题】:How do I put object to amazon s3 using presigned url? 【发布时间】:2016-06-17 19:16:00 【问题描述】:

我正在尝试使用签名的 url 将图像上传到 s3 存储桶。以下是我的存储桶策略:


    "Version": "2012-10-17",
    "Statement": [
        
            "Sid": "",
            "Effect": "Allow",
            "Principal": 
                "AWS": [
                    "arn:aws:iam::12345678:user/myuser",
                    "arn:aws:iam::12345678:root"
                ]
            ,
        "Action": [
                "s3:List*",
                "s3:Put*",
                "s3:Get*"
            ],
            "Resource": [
                "arn:aws:s3:::myBucket",
                "arn:aws:s3:::myBucket/*"
            ]
        
    ]

我正在从服务器生成签名的 url,如下所示:

var aws = require('aws-sdk');
aws.config = 
    accessKeyId: myAccessKeyId,
    secretAccessKey: mySecretAccessKey
;

var s3 = new aws.s3();
s3.getSignedUrl('putObject', 
    Bucket: 'myBucket',
    Expires: 60*60,
    key: 'myKey'
, function (err, url) 
    console.log(url);
);

我得到了网址。但是当我尝试放置一个对象时,我收到以下错误:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>FXXXXXXXXX</RequestId>
    <HostId>fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</HostId>
</Error>

更新 1

这是我的用户的政策:


  "Version": "2012-10-17",
  "Statement": [
    
        "Sid": "",
        "Effect": "Allow",
        "Principal": 
            "AWS": [
                "arn:aws:iam::2xxxxxxxxxxx:user/myuser",
                "arn:aws:iam::2xxxxxxxxxxx:root"
            ]
        ,
        "Action": [
            "s3:*"
        ],
        "Resource": [
            "arn:aws:s3:::myBucket",
            "arn:aws:s3:::myBucket/*"
        ]
    
  ]

更新 2 我只能在设置以下选项时上传。如果仅手动选择权限工作,我不明白存储桶策略的用途。

更新 3

以下代码有效。现在唯一的问题是签名的网址

 #!/bin/bash

 file="$1"

 bucket="mybucket"
 resource="/$bucket/$file"
 contentType="image/png"
 dateValue=`date -R`
 stringToSign="PUT\n\n$contentType\n$dateValue\n$resource"
 s3Key="AKxxxxxxxxxxxxxxxxx"
 s3Secret="/Wuxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 signature=`echo -en $stringToSign | openssl sha1 -hmac $s3Secret     -binary | base64`
 curl -X PUT -T "$file" \
   -H "Host: $bucket.s3.amazonaws.com" \
   -H "Date: $dateValue" \
   -H "Content-Type: $contentType" \
   -H "Authorization: AWS $s3Key:$signature" \
   https://$bucket.s3.amazonaws.com/$file

【问题讨论】:

我假设 myAccessKeyId 和 mySecretAccessKey 都属于 myuser? 是的,他们属于用户 当你生成“myKey”的url时,你正在上传一个名为“myKey”的文件,对吧? @VolkanPaksoy 不一定。上传到 s3 后文件重命名为 myKey。问题不在于这里的文件名。问题是许可。当我将权限设置为所有人时文件上传,当我不设置时访问被拒绝;无论我的存储桶或用户政策如何 我明白了。我认为您不需要“委托人”是用户的策略,无论如何它都附加到该用户。我会尝试为该用户附加从列表中选择的完整 S3 访问策略,并尝试使用 CloudBerry 之类的工具上传带有他的密钥的文件,以避免对代码或手动策略的任何可能的疏忽。一旦您可以手动上传文件,我会尝试使用预签名的网址。 【参考方案1】:

这是在 S3 中为任何类型的文件生成预签名 URL 的完整代码。

如果您愿意,可以在参数中使用 Expire 参数包含过期时间。 以下代码将上传任何类型的文件,如 excel(xlsx, pdf, jpeg)

    const AWS = require('aws-sdk');
    const fs = require('fs');
    const axios = require('axios');
    const s3 = new AWS.S3();
    const filePath = 'C:/Users/siva.cheedella/Downloads/invoice.pdf';
    
    
    var params = 
        Bucket: 'testing-presigned-url-dev',
        Key: 'dummy.pdf',
        "ContentType": "application/octet-stream"
    ;
    
    
    s3.getSignedUrl('putObject', params, function (err, url) 
        console.log('The URL is', url);
    
        fs.writeFileSync("./url.txt", url);
    
    
        axios(
            method: "put",
            url,
            data: fs.readFileSync(filePath),
            headers: 
                "Content-Type": "application/octet-stream"
            
        )
            .then((result) => 
                console.log('result', result);
    
            ).catch((err) => 
                console.log('err', err);
    
            );
    
    );

【讨论】:

【参考方案2】:

您已正确设置存储桶的权限,以允许用户访问。

但您还需要编辑用户的策略,以允许用户访问 S3 服务。

编辑您使用其凭证生成自签名 URL 的用户的 IAM 策略。此策略允许用户对账户中的所有 S3 存储桶进行完全管理访问:


  "Statement": [
    
      "Sid": "AllowAllS3Access",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": "*"
    
  ]

【讨论】:

我还是不懂人。到底是怎么回事?它仍然给出拒绝访问错误。 这将授予用户对所有 S3 存储桶的所有权限。相当开放且不安全。 这授予用户在 S3 服务中执行任何操作的权限。它不会自动授予他们访问存储桶的权限,除非存储桶策略允许。【参考方案3】:

它也可以帮助你:) 添加 ContentType 属性:

s3.getSignedUrl('putObject', 
    Bucket: 'myBucket',
    Expires: 60*60,
    Key: 'myKey',
    ContentType: 'image/jpeg',
, function (err, url) 
   console.log(url);
);

【讨论】:

我不知道为什么,但是在我添加这个之前我收到了签名错误! 上传时,您的浏览器会将内容类型添加到请求标头中。这将在执行的请求和您使用 getSignerUrl 获得的签名之间产生差异。当然,您必须根据要上传的文件设置正确的内容类型。【参考方案4】:

我设法使用您的代码成功上传了一个文件。

这是我遵循的步骤:

    创建了一个新的存储桶和一个新的 IAM 用户

    如下设置 IAM 用户的策略:

    
        "Version": "2012-10-17",
        "Statement": [
            
                "Sid": "Stmt1418647210000",
                "Effect": "Allow",
                "Action": [
                    "s3:Put*"
                ],
                "Resource": [
                    "arn:aws:s3:::myBucket/*"
                ]
            
        ]
    
    

    未创建存储桶策略

    使用您的代码生成预签名 URL:

    var aws = require('aws-sdk');
    aws.config = 
        accessKeyId: myAccessKeyId,
        secretAccessKey: mySecretAccessKey
    ;
    
    var s3 = new aws.s3();
    s3.getSignedUrl('putObject', 
        Bucket: 'myBucket',
        Expires: 60*60,
        Key: 'myKey'
    , function (err, url) 
        console.log(url);
    );
    

    复制屏幕上的URL并使用curl测试上传如下:

    curl.exe -k -X PUT -T "someFile" "https://myBucket.s3.amazonaws.com/myKey?AWSAccessKeyId=ACCESS_KEY_ID&Expires=1457632663&Signature=Dhgp40j84yfjBS5v5qSNE4Q6l6U%3D"
    

在我的情况下,政策更改通常需要 5-10 秒才能生效,因此如果第一次失败,请确保继续发送一段时间。

希望这会有所帮助。

【讨论】:

您好,请问getSignedUrl函数中的myKey是什么。 @Siddhant 这基本上是 S3 上对象的名称。在此处查看参数说明:docs.aws.amazon.com/AWSjavascriptSDK/latest/AWS/… 我可以建议:- var s3 = new aws.S3( signatureVersion: 'v4', region: 'eu-central-1' ) - Key: 'images/upload/noek.jpg ' 我在这上面花了将近 3.5 个小时。拥有 apt-permission 集的 IAM 用户是完成此任务的正确方法。【参考方案5】:
    在您的 IAM 控制台中,click Users 在右侧列表中,选择您使用的 IAM 用户(应为“myuser”) 在子选项卡上选择权限 单击附加策略并选择 AmazonS3FullAccess

最后一页会像this。

您也可以检查安全凭证子选项卡,您的 accessKeyId 应该在列表中。 secretAccessKey 只是无法再次获取。

【讨论】:

它现在拥有完全的管理员权限。我可以从 s3 控制台上传。问题是我无法使用签名网址上传。

以上是关于如何使用预签名的 url 将对象放入 amazon s3?的主要内容,如果未能解决你的问题,请参考以下文章