如何在 S3 中公开 10,000 个文件
Posted
技术标签:
【中文标题】如何在 S3 中公开 10,000 个文件【英文标题】:How to make 10,000 files in S3 public 【发布时间】:2011-03-09 17:09:47 【问题描述】:我在存储桶中有一个包含 10,000 个文件的文件夹。似乎没有办法将它们上传并立即公开。所以我把它们都上传了,它们是私人的,我需要把它们都公开。
我已经尝试过 aws 控制台,它只是给出了一个错误(适用于文件较少的文件夹)。
我尝试在 Firefox 中使用 S3 组织,同样的事情。
我可以运行一些软件或脚本来公开所有这些吗?
【问题讨论】:
我尝试的每个工具都崩溃了,所以我最终编写了一个 php 脚本,花了几个小时才遍历存储桶中的每个对象并将其公开。 【参考方案1】:您可以生成一个存储桶策略(参见下面的示例),该策略允许访问存储桶中的所有文件。桶策略可以通过 AWS 控制台添加到桶中。
"Id": "...",
"Statement": [
"Sid": "...",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bucket/*",
"Principal":
"AWS": [ "*" ]
]
另请参阅 Amazon 提供的以下策略生成器工具。
http://awspolicygen.s3.amazonaws.com/policygen.html
【讨论】:
这对我不起作用。即使存储桶策略到位,某些对象仍会返回“拒绝访问”响应。它是从上面复制粘贴的,仅更改了存储桶名称。我想是时候编写一个脚本来遍历所有 130 万个对象了……有点烦人 你需要把“bucket”改成你的bucket的名字 我讨厌这样做。那是一些丑陋的 JSON。 请注意:这似乎很明显,但您也可以选择限制对特定文件夹的访问:bucket/avatars/*
。 (别忘了最后的*
。我做到了,我绕着圈跑了一会儿。)
@Benjamin 对你来说什么是“基本”配置对其他人来说是不合适的,因为每个人的安全要求都不一样。 AWS 提供了一种统一的方式来自定义这些策略。因此,必须花时间正确学习安全策略,不要回避几行简单的 JSON。【参考方案2】:
如果你是第一次上传,你可以在命令行设置文件上传时公开:
aws s3 sync . s3://my-bucket/path --acl public-read
如 Using High-Level s3 Commands with the AWS Command Line Interface 中所述
不幸的是,它仅在文件上传时应用 ACL。它不会(在我的测试中)将 ACL 应用于已上传的文件。
如果您确实想更新现有对象,您曾经能够将存储桶同步到自身,但这似乎已经停止工作。
[不再工作] 这可以从命令行完成:
aws s3 sync s3://my-bucket/path s3://my-bucket/path --acl public-read
(所以这不再回答问题,而是留下答案以供参考。)
【讨论】:
这个命令对已经上传但尚未公开读取的文件有影响吗? 当我测试它时,它似乎只将ACL添加到新同步的文件中。 感谢重播,我也测试过了。有没有办法批量修改上传文件的权限? 哦,难怪。我对此感到困惑。非常感谢您的澄清。 答案已更新,包括如何更改现有文件。【参考方案3】:我不得不更改数十万个对象。我启动了一个 EC2 实例来运行它,这使得它运行得更快。您需要先安装 aws-sdk
gem。
代码如下:
require 'rubygems'
require 'aws-sdk'
# Change this stuff.
AWS.config(
:access_key_id => 'YOURS_HERE',
:secret_access_key => 'YOURS_HERE',
)
bucket_name = 'YOUR_BUCKET_NAME'
s3 = AWS::S3.new()
bucket = s3.buckets[bucket_name]
bucket.objects.each do |object|
puts object.key
object.acl = :public_read
end
【讨论】:
简单的方法是上传它们并首先设置 public_read 标志,但如果失败,这是一个不错的选择。 这段代码已经过时了,参考我的answer【参考方案4】:我遇到了同样的问题,@DanielVonFange 的解决方案已经过时,因为新版本的 SDK 已经发布。
使用 AWS Ruby SDK 添加现在适合我的代码 sn-p:
require 'aws-sdk'
Aws.config.update(
region: 'REGION_CODE_HERE',
credentials: Aws::Credentials.new(
'ACCESS_KEY_ID_HERE',
'SECRET_ACCESS_KEY_HERE'
)
)
bucket_name = 'BUCKET_NAME_HERE'
s3 = Aws::S3::Resource.new
s3.bucket(bucket_name).objects.each do |object|
puts object.key
object.acl.put( acl: 'public-read' )
end
【讨论】:
绝妙的答案 - 正是我急需的脚本 @ksarunas 在我的情况下,我需要将公共权限更改为私有权限,因此将 public-read 替换为 private 并且访问权限已更改,但我仍然可以访问 URL?【参考方案5】:只是想通过新的 S3 控制台添加它,您可以选择您的文件夹并选择 Make public
以公开文件夹中的所有文件。它作为后台任务工作,因此可以处理任意数量的文件。
【讨论】:
不幸的是,它需要很长时间,并且在命令运行时您无法关闭浏览器。您的浏览器为每个文件发送 2 个请求,在我的情况下,这两个请求花费了 500 毫秒。如果您有很多文件,则需要很长时间 =( 还有一个问题:这将完全公开。如果您只想要公共读取访问权限,那就有问题了。 要非常注意 - 我做了这个 Make Public 并且弹出的“进度条”非常微妙,我认为它已经完成了。我检查了一下,可能花了一个小时来解决这个问题,然后我才意识到你点击了 Make Public 并且小的微妙的“进度条出现了”...... grrr......因为我关闭了浏览器窗口大约 10 次,我认为每次都会杀死它.我现在正在运行它 - 它非常快 - 120k 图像可能需要 20 分钟【参考方案6】:使用 cli:
aws s3 ls s3://bucket-name --recursive > all_files.txt && grep .jpg all_files.txt > files.txt && cat files.txt | awk 'cmd="aws s3api put-object-acl --acl public-read --bucket bucket-name --key "$4;system(cmd)'
【讨论】:
您不能只使用管道进行 grep,而不是使用所有 files.txt 写入磁盘吗?这可以是aws s3 ls s3://bucket-name --recursive | grep .jpg | awk 'cmd="aws s3api put-object-acl --acl public-read --bucket bucket-name --key "$4;system(cmd)'
@sakurashinken 回答完美。如果你看到这个。这是要使用的。【参考方案7】:
我自己也需要这个,但是文件的数量使得串行执行速度很慢。所以我写了a script,它是在iron.io 的IronWorker 服务上完成的。他们每月 500 个免费计算小时足以处理大型存储桶(如果您确实超过了,定价是合理的)。由于它是并行完成的,因此对于我拥有的 32,000 个对象,它在不到一分钟的时间内完成。另外我相信他们的服务器在 EC2 上运行,因此作业和 S3 之间的通信很快。
欢迎任何人根据自己的需要使用我的脚本。
【讨论】:
【参考方案8】:看看BucketExplorer,它可以很好地管理批量操作,并且是一个可靠的 S3 客户端。
【讨论】:
现在还可以通过信息面板批量更改 Cyberduck(免费)中的权限。 BucketExplorer 仅在您有权列出所有存储桶时才有用。最好使用 CLI 或 SDK 进行此操作,并让您的用户拥有受限的权限。【参考方案9】:您会认为他们会公开阅读默认行为,不是吗? :) 我在构建自定义 API 以通过 C# 解决方案与 S3 交互时分享了您的挫败感。这是完成上传 S3 对象并默认将其设置为公共读取访问的 sn-p:
public void Put(string bucketName, string id, byte[] bytes, string contentType, S3ACLType acl)
string uri = String.Format("https://0/1", BASE_SERVICE_URL, bucketName.ToLower());
DreamMessage msg = DreamMessage.Ok(MimeType.BINARY, bytes);
msg.Headers[DreamHeaders.CONTENT_TYPE] = contentType;
msg.Headers[DreamHeaders.EXPECT] = "100-continue";
msg.Headers[AWS_ACL_HEADER] = ToACLString(acl);
try
Plug s3Client = Plug.New(uri).WithPreHandler(S3AuthenticationHeader);
s3Client.At(id).Put(msg);
catch (Exception ex)
throw new ApplicationException(String.Format("S3 upload error: 0", ex.Message));
ToACLString(acl) 函数返回 public-read,BASE_SERVICE_URL 是 s3.amazonaws.com,AWS_ACL_HEADER 常量是 x-amz-acl强>。当我们使用 Dream 框架来简化我们的 http 通信时,plug 和 DreamMessage 的东西可能看起来很奇怪。本质上,我们正在根据 aws 规范执行具有指定标头和特殊标头签名的 http PUT(有关如何构造授权标头的示例,请参阅aws docs 中的此页面)。
要更改现有的 1000 个对象 ACL,您可以编写一个脚本,但使用 GUI 工具解决当前问题可能更容易。到目前为止,我使用过的最好的是来自一家名为 cloudberry 的 S3 公司;看起来他们至少有一种产品可以免费试用 15 天。我刚刚验证了它允许您一次选择多个对象并通过上下文菜单将它们的 ACL 设置为公共。享受云!
【讨论】:
【参考方案10】:如果您的文件名有空格,我们可以采用上面 Alexander Vitanov 的答案并通过 jq 运行它:
#!/bin/bash
# make every file public in a bucket example
bucket=www.example.com
IFS=$'\n' && for tricky_file in $(aws s3api list-objects --bucket "$bucket" | jq -r '.Contents[].Key')
do
echo $tricky_file
aws s3api put-object-acl --acl public-read --bucket "$bucket" --key "$tricky_file"
done
【讨论】:
以上是关于如何在 S3 中公开 10,000 个文件的主要内容,如果未能解决你的问题,请参考以下文章