Amazon S3 策略阻止创建根级文件夹
Amazon S3 Policy Prevent Creation of Root-level Folders
我们希望阻止我们的 S3 用户在我们存储桶的根目录中创建新文件夹。换句话说,他们必须使用存储桶中的现有文件夹来上传或修改文件。如果愿意,他们可以选择在这些现有文件夹中创建子文件夹。
注意:使用 S3 策略。用户选择任何现有文件夹。他们没有分配文件夹。
我知道 S3 将文件和文件夹都视为对象,所以我不确定是否可以这样做,但我相信社区的潜力。
这是我想要的:
桶名: 测试桶
操作: 在测试桶的根目录中创建文件夹。
期望的结果:被拒绝
操作: 在测试桶的根目录中上传随机文件。
期望的结果:被拒绝
操作: 在测试桶的现有 "folder1" 文件夹 (test-bucket/folder1/file1) 中上传文件 "file1"。
期望的结果:成功
操作: 在测试桶的现有 "folder1" 文件夹 (test-bucket/folder1/sub-folder1/) 中创建文件夹 "sub-folder1"。
期望的结果:成功
您的概念模型存在缺陷。
I know S3 treats both files and folders as objects
这是不正确的。
这是正确的版本:
- S3 服务和 API 没有文件夹的概念。
- S3 对象没有任何真正意义上的分层。
- S3 控制台是唯一具有文件夹概念的实体。
- S3 服务和 API 支持 prefix、delimiter 和 common 前缀的概念.
当对 API 的 List Objects 请求带有指定前缀时,仅返回键以该前缀开头的对象,而不管前缀后其对象键中的任何 /
.
当一个 List Objects 请求伴随着一个前缀和一个分隔符(通常是 /
)时,API 只有 returns 个键与给定前缀匹配的对象 和 在键中没有后续的 /
(在请求中指定的前缀之后)。这些类似于 "files in the folder."
与给定前缀匹配但确实有后续(在指定前缀之后)/
的任何对象的键的前缀被合并成一个唯一的前缀列表,截断到它们的下一个 /
。这些是常见的前缀,类似于 "folders in the folder."
但是,事实上,没有什么是真正的 "in"。
控制台通过从列表对象请求中读取公共前缀到 API,并将它们显示为文件夹,从而创建文件夹的错觉。
控制台通过允许您 "create a folder" 进一步增强了这种错觉——但它实际上不是一个文件夹,甚至不需要它。它只是一个带有键的空对象,键的最后一个字符是 /
。 S3 的正常操作不需要此对象,但创建它是为了方便,以便您可以导航 "into" 和 "empty folder" 并上传文件 "into" 空文件夹。
然而,真正发生的事情是这样的:
Console: "create folder foo in the root of the bucket"
API: PUT /foo/
Content-Length: 0
Console: "click folder foo"
API: GET /?prefix=foo/&delimiter=/
Console: "upload file bar.txt inside folder foo"
API: PUT /foo/bar.txt
现在...如果你拿一个空桶,并使用 API(不是控制台),你可以简单地 PUT /foo/bar.txt
并得到完全相同的最终结果 在控制台中 -- 你看到一个名为 "foo" 的文件夹包含 "bar.txt." 该文件夹显示 因为 有一个前缀为 foo/
。删除对象,文件夹消失。
相反,如果您使用控制台从顶部执行此操作,一旦您删除了 "bar.txt",文件夹 "foo" 仍然存在,因为它实际上只是一个空对象,其唯一目的是导致当没有其他具有该公共前缀的对象时,文件夹出现在控制台导航中。
所以,不...S3 不会将文件和文件夹都视为对象。 S3 console 创建欺骗文件夹的对象,严格来说是为了辅助导航,这里的神奇之处在于对象的键以 /
结尾。另一方面,如果那些空对象不存在,控制台仍会像在文件夹中一样显示对象。
然后您会看到出现的问题。不能要求 S3 服务针对它不知道且实际上不需要存在的内容进行测试。
因此,完全按照您的要求进行操作在技术上是不可能的;但是,似乎有一个有限的解决方法。主要限制是您不能指定 "the folder must exist," 但您 可以 指定 "the object key prefix must match a predefined set of patterns."
存储桶或用户策略的相关部分可能如下所示...
"Action": "s3:PutObject",
"Resource": [
"arn:aws:s3:::examplebucket/taxdocuments/*",
"arn:aws:s3:::examplebucket/personnel/*",
"arn:aws:s3:::examplebucket/unicorns/*"
...
],
受此政策影响的用户将能够在 "examplebucket" 存储桶中创建以 taxdocuments/ 或 personnel/ 或 unicorns/ 开头的任何对象,并且如果没有其中一个,将无法创建对象前缀。除此之外,他们可以整天创建控制台文件夹 "in" 文件夹 "in" 文件夹,只要这些前缀之一位于每个假文件夹的对象键的开头。
当然,限制是让另一个文件夹有资格访问需要修改策略。
这也可能有效,但请谨慎操作:
"Resource": "arn:aws:s3:::examplebucket/?*/?*",
直觉上这似乎可行,但这里的缺陷 - 假设 ?*/?*
有效(it seems to be)并且 ?
不匹配 0 个字符 *
是——这允许用户在根目录中创建一个新的(伪)文件夹,只要他们同时在其中创建名称至少一个字符长的东西,使用 API -- 也就是说,如果 "pics" 文件夹不存在,则使用键 pics/cat.jpg
"creates" 创建一个对象,如上所述。从控制台来看,应该 阻止在根目录中创建新文件夹,但从 API 来看,它不会施加这样的限制。
感谢@Michael 的详细回复。您说 API 和 CLI 调用可以在 non-empty 时继续创建 root-level 文件夹是绝对正确的。控制台和 S3 浏览器访问按预期工作。这是一个妥协,但它是我们最接近我们想要的。这是我正在使用的存储桶策略:
{
"Version": "2012-10-17",
"Id": "Policy1486492608325",
"Statement": [
{
"Sid": "Stmt1486492495770",
"Effect": "Allow",
"Principal": {
"*"
},
"Action": [
"s3:DeleteObject",
"s3:Get*",
"s3:List*",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::test-storage",
"arn:aws:s3:::test-storage/*"
]
},
{
"Sid": "Stmt1486492534643",
"Effect": "Deny",
"Principal": {
"*"
},
"Action": [
"s3:DeleteObject",
"s3:PutObject"
],
"NotResource": "arn:aws:s3:::test-storage/?*/?*"
}
]
}
我们希望阻止我们的 S3 用户在我们存储桶的根目录中创建新文件夹。换句话说,他们必须使用存储桶中的现有文件夹来上传或修改文件。如果愿意,他们可以选择在这些现有文件夹中创建子文件夹。
注意:使用 S3 策略。用户选择任何现有文件夹。他们没有分配文件夹。
我知道 S3 将文件和文件夹都视为对象,所以我不确定是否可以这样做,但我相信社区的潜力。
这是我想要的:
桶名: 测试桶
操作: 在测试桶的根目录中创建文件夹。 期望的结果:被拒绝
操作: 在测试桶的根目录中上传随机文件。 期望的结果:被拒绝
操作: 在测试桶的现有 "folder1" 文件夹 (test-bucket/folder1/file1) 中上传文件 "file1"。 期望的结果:成功
操作: 在测试桶的现有 "folder1" 文件夹 (test-bucket/folder1/sub-folder1/) 中创建文件夹 "sub-folder1"。 期望的结果:成功
您的概念模型存在缺陷。
I know S3 treats both files and folders as objects
这是不正确的。
这是正确的版本:
- S3 服务和 API 没有文件夹的概念。
- S3 对象没有任何真正意义上的分层。
- S3 控制台是唯一具有文件夹概念的实体。
- S3 服务和 API 支持 prefix、delimiter 和 common 前缀的概念.
当对 API 的 List Objects 请求带有指定前缀时,仅返回键以该前缀开头的对象,而不管前缀后其对象键中的任何 /
.
当一个 List Objects 请求伴随着一个前缀和一个分隔符(通常是 /
)时,API 只有 returns 个键与给定前缀匹配的对象 和 在键中没有后续的 /
(在请求中指定的前缀之后)。这些类似于 "files in the folder."
与给定前缀匹配但确实有后续(在指定前缀之后)/
的任何对象的键的前缀被合并成一个唯一的前缀列表,截断到它们的下一个 /
。这些是常见的前缀,类似于 "folders in the folder."
但是,事实上,没有什么是真正的 "in"。
控制台通过从列表对象请求中读取公共前缀到 API,并将它们显示为文件夹,从而创建文件夹的错觉。
控制台通过允许您 "create a folder" 进一步增强了这种错觉——但它实际上不是一个文件夹,甚至不需要它。它只是一个带有键的空对象,键的最后一个字符是 /
。 S3 的正常操作不需要此对象,但创建它是为了方便,以便您可以导航 "into" 和 "empty folder" 并上传文件 "into" 空文件夹。
然而,真正发生的事情是这样的:
Console: "create folder foo in the root of the bucket"
API: PUT /foo/
Content-Length: 0
Console: "click folder foo"
API: GET /?prefix=foo/&delimiter=/
Console: "upload file bar.txt inside folder foo"
API: PUT /foo/bar.txt
现在...如果你拿一个空桶,并使用 API(不是控制台),你可以简单地 PUT /foo/bar.txt
并得到完全相同的最终结果 在控制台中 -- 你看到一个名为 "foo" 的文件夹包含 "bar.txt." 该文件夹显示 因为 有一个前缀为 foo/
。删除对象,文件夹消失。
相反,如果您使用控制台从顶部执行此操作,一旦您删除了 "bar.txt",文件夹 "foo" 仍然存在,因为它实际上只是一个空对象,其唯一目的是导致当没有其他具有该公共前缀的对象时,文件夹出现在控制台导航中。
所以,不...S3 不会将文件和文件夹都视为对象。 S3 console 创建欺骗文件夹的对象,严格来说是为了辅助导航,这里的神奇之处在于对象的键以 /
结尾。另一方面,如果那些空对象不存在,控制台仍会像在文件夹中一样显示对象。
然后您会看到出现的问题。不能要求 S3 服务针对它不知道且实际上不需要存在的内容进行测试。
因此,完全按照您的要求进行操作在技术上是不可能的;但是,似乎有一个有限的解决方法。主要限制是您不能指定 "the folder must exist," 但您 可以 指定 "the object key prefix must match a predefined set of patterns."
存储桶或用户策略的相关部分可能如下所示...
"Action": "s3:PutObject",
"Resource": [
"arn:aws:s3:::examplebucket/taxdocuments/*",
"arn:aws:s3:::examplebucket/personnel/*",
"arn:aws:s3:::examplebucket/unicorns/*"
...
],
受此政策影响的用户将能够在 "examplebucket" 存储桶中创建以 taxdocuments/ 或 personnel/ 或 unicorns/ 开头的任何对象,并且如果没有其中一个,将无法创建对象前缀。除此之外,他们可以整天创建控制台文件夹 "in" 文件夹 "in" 文件夹,只要这些前缀之一位于每个假文件夹的对象键的开头。
当然,限制是让另一个文件夹有资格访问需要修改策略。
这也可能有效,但请谨慎操作:
"Resource": "arn:aws:s3:::examplebucket/?*/?*",
直觉上这似乎可行,但这里的缺陷 - 假设 ?*/?*
有效(it seems to be)并且 ?
不匹配 0 个字符 *
是——这允许用户在根目录中创建一个新的(伪)文件夹,只要他们同时在其中创建名称至少一个字符长的东西,使用 API -- 也就是说,如果 "pics" 文件夹不存在,则使用键 pics/cat.jpg
"creates" 创建一个对象,如上所述。从控制台来看,应该 阻止在根目录中创建新文件夹,但从 API 来看,它不会施加这样的限制。
感谢@Michael 的详细回复。您说 API 和 CLI 调用可以在 non-empty 时继续创建 root-level 文件夹是绝对正确的。控制台和 S3 浏览器访问按预期工作。这是一个妥协,但它是我们最接近我们想要的。这是我正在使用的存储桶策略:
{
"Version": "2012-10-17",
"Id": "Policy1486492608325",
"Statement": [
{
"Sid": "Stmt1486492495770",
"Effect": "Allow",
"Principal": {
"*"
},
"Action": [
"s3:DeleteObject",
"s3:Get*",
"s3:List*",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::test-storage",
"arn:aws:s3:::test-storage/*"
]
},
{
"Sid": "Stmt1486492534643",
"Effect": "Deny",
"Principal": {
"*"
},
"Action": [
"s3:DeleteObject",
"s3:PutObject"
],
"NotResource": "arn:aws:s3:::test-storage/?*/?*"
}
]
}