AWS S3 生成签名 URL ''AccessDenied''
Posted
技术标签:
【中文标题】AWS S3 生成签名 URL \'\'AccessDenied\'\'【英文标题】:AWS S3 Generating Signed Urls ''AccessDenied''AWS S3 生成签名 URL ''AccessDenied'' 【发布时间】:2019-03-11 01:38:41 【问题描述】:我正在使用 NodeJs 将文件上传到 AWS S3。我希望客户端能够安全地下载文件。所以我试图生成签名的 URL,在使用一次后过期。我的代码如下所示:
上传中
const s3bucket = new AWS.S3(
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
)
const uploadParams =
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/$file.name`,
s3bucket.upload(uploadParams, function (err, data)
// ...
)
正在下载
const url = s3bucket.getSignedUrl('getObject',
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
)
问题
打开网址时,我得到以下信息:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>AccessDenied</Code>
<Message>
There were headers present in the request which were not signed
</Message>
<HeadersNotSigned>host</HeadersNotSigned>
<RequestId>D63C8ED4CD8F4E5F</RequestId>
<HostId>
9M0r2M3XkRU0JLn7cv5QN3S34G8mYZEy/v16c6JFRZSzDBa2UXaMLkHoyuN7YIt/LCPNnpQLmF4=
</HostId>
</Error>
我无法找到错误。我真的很感激任何帮助:)
【问题讨论】:
任何拥有有效安全凭证的人都可以创建预签名 URL。但是,为了让您成功上传对象,预签名 URL 必须由有权执行预签名 URL 基于docs.aws.amazon.com/AmazonS3/latest/dev/… 的操作的人创建。您的 IAM 策略是否有权访问 S3 存储桶?如果文件在您的存储桶中成功生成,并且在您创建签名网址后您无法立即访问它,请检查您传递给getSignedUrl
的文件名和存储桶是否有效
有没有办法检查 IAM 策略是否有权访问存储桶?
确实,检查这一点的快速方法就是查看您的存储桶并确认对象已创建。因为您收到了AccessDenied
response,请尝试检查您的存储桶权限并允许用户读取和查看(启用读取和查看权限)。
prntscr.com/l2lkwb账号有权限
您可以授予角色 AmazonS3FullAccess 权限。如果它有效,那么您就知道问题出在授予角色的访问权限上。删除 AmazonS3FullAccess 并将 GetObject 授予您的存储桶并尝试一下。如果它仍然不起作用,那么您将不得不进行一些研究以找出您需要哪些权限,并检查您是否使用了正确的资源(即存储桶)
【参考方案1】:
我也在使用无服务器框架的应用程序中解决了这个问题。
我的解决方法是向 serverless.yml 文件中的 IAM 角色添加 S3 权限。
我不确定 s3 如何制作预签名 URL,但事实证明他们考虑了您的 IAM 角色。
添加所有 s3 动作就可以了。这就是 S3 的 IAM 角色的样子?
iamRoleStatements:
- Effect: Allow
Action:
- 's3:*'
Resource:
- 'arn:aws:s3:::$self:custom.imageBucket/*'
【讨论】:
很好的提示,但它应该在provider
内,像这样:provider: name: aws iamRoleStatements: - Effect: Allow Action: - 's3:*' Resource: - 'arn:aws:s3:::$env:S3_BUCKET_NAME/*'
这对我有用。 Lambda 拥有的唯一权限是s3:PutObject
。一旦我将其更改为s3:*
。最好准确地缩小所需的权限范围,因为我觉得s3:*
过于宽松。如果我发现我会在这里发表另一条评论。谢谢
更新:我错过了s3:GetObject
。这是 Lambda 访问存储桶的完整策略,new iam.PolicyStatement( effect: iam.Effect.ALLOW, actions: ['s3:PutObject', 's3:GetObject'], resources: [
$imageBucket.bucketArn/*] )
我做错的另一件事是参数中对象(密钥)的路径错误,s3Client.getSignedUrlPromise('getObject', Bucket: bucket, Key: path, Expires: expires )
。一旦我修复它,它就起作用了。所以总而言之,我有两个问题,(1)缺少对 Lambda 角色的 getObject S3 权限,以及(2)错误的 S3 对象路径被赋予S3.getSignedUrlPromise()
。干杯,祝你有美好的一天!【参考方案2】:
我最近在从不久前创建的存储桶移动到最近创建的存储桶时看到了这个问题。
看来 v2 预签名链接(目前)继续适用于旧存储桶,而新存储桶被强制使用 v4。
修订后的计划 - 2020 年 6 月 24 日之后创建的任何新存储桶都不会 支持 SigV2 签名请求,尽管现有的存储桶将继续存在 支持 SigV2,同时我们与客户合作以摆脱旧版本 请求签名方法。
即使您可以继续在现有存储桶上使用 SigV2,并且在 支持 SigV2 的 AWS 区域的子集,我鼓励您 迁移到 SigV4,获得一些重要的安全性和效率 过程中的好处。
https://docs.amazonaws.cn/AmazonS3/latest/API/sigv4-query-string-auth.html#query-string-auth-v4-signing-example
我们的解决方案涉及更新 AWS 开发工具包以默认使用它;我怀疑较新的版本可能已经默认了这个设置。
https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-other.html#config-setting-aws-s3-usesignatureversion4
【讨论】:
【参考方案3】:我在本地测试我的 lambda 函数时遇到了同样的问题,但在部署后它不起作用。一旦我添加了 s3 对 lambda 函数的完全访问权限它起作用了。
【讨论】:
【参考方案4】:如果您的 s3 文件已加密,请确保您的策略还可以访问加密密钥和相关操作。
【讨论】:
Amazon S3 在应用存储桶加密设置之前评估并应用存储桶策略。即使您启用了存储桶加密设置,如果您有存储桶策略来拒绝此类 PUT 请求,您的没有加密信息的 PUT 请求也将被拒绝。检查您的存储桶策略并根据需要进行修改。【参考方案5】:我一直遇到类似的问题,但我的问题是由于地区设置造成的。 在我们的后端,我们有一些应用程序的配置设置。
其中一个是"region": "us-west-2"
,所以预签名的url是用这个区域创建的,但是当它在前端被调用时,该区域被设置为"us-west-1"
。
将其更改为相同可以解决问题。
【讨论】:
【参考方案6】:您的代码是正确的,请仔细检查以下内容:
您的存储桶访问策略。
通过 API 密钥获得的存储桶权限。
您的 API 密钥和秘密。
您的存储桶名称和密钥。
对于存储桶策略,您可以使用以下内容:
"Version": "2012-10-17",
"Statement": [
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*"
]
将 bucket 更改为您的存储桶名称。
对于用户和访问密钥权限(#2),您应该按照以下步骤操作:
1-转到 AWS 身份和访问管理 (IAM) 并单击策略链接并单击“创建策略”按钮。
2-选择 JSON 选项卡。
3-输入以下语句,确保更改存储桶名称并点击“review policy”按钮。
"Version": "2012-10-17",
"Statement": [
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::YOURBUCKETNAME"
]
4-为您的策略输入一个名称,然后单击“创建策略”按钮。
5-点击用户链接,找到您当前的用户名(您已经拥有访问密钥和密码)
6-点击“添加权限”按钮。
7-添加我们在上一步中创建的策略并保存。
最后,确保您的存储桶无法从 Public 访问,将正确的内容类型添加到您的文件并设置 signatureVersion: 'v4'
最后的代码应该是这样的,感谢@Vaisakh PS:
const s3bucket = new AWS.S3(
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
)
const uploadParams =
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/$file.name`,
s3bucket.upload(uploadParams, function (err, data)
// ...
)
const url = s3bucket.getSignedUrl('getObject',
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
)
【讨论】:
我没有在 Bucket Policy 中添加任何内容...但我也不确定该添加什么 ? 我更新了政策 (prntscr.com/l3jj8q),但仍然遇到同样的错误。我很确定第 3 点和第 4 点是正确的。但我从未使用过 API 密钥 所以,请确保您的 #2 文档没有说明 API 密钥 (aws.amazon.com/sdk-for-node-js/?nc1=h_ls) 或该密钥应该在哪里? 答案更新为#2点,如果不行,重新测试所有步骤,可能你错过了一个步骤。【参考方案7】:您的代码看起来不错,但我认为您在创建 s3bucket
对象时缺少 signatureVersion: 'v4'
参数。请尝试以下更新的代码。
const s3bucket = new AWS.S3(
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
)
const uploadParams =
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/$file.name`,
s3bucket.upload(uploadParams, function (err, data)
// ...
)
const url = s3bucket.getSignedUrl('getObject',
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
)
有关signatureVersion: 'v4'
的更多信息,请参阅以下链接
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
您还可以尝试以下创建presigned url
的nodejs
库
https://www.npmjs.com/package/aws-signature-v4
【讨论】:
我仍然收到错误消息。但我感谢您的帮助! 我解决了我的问题,然后又遇到了另一个错误...通过将signatureVersion
设置为v4
修复了新错误,谢谢!以上是关于AWS S3 生成签名 URL ''AccessDenied''的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?
AWS S3 - 我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法