我有两个帐户(acc-1
和acc-2
)。
acc-1
托管一个API,用于处理文件上传到acc-1
桶中的情况(我们将其称为upload
)。上传会触发SNS转换图像或对视频进行转码。生成的文件被放入acc-1
(output
)中的另一个存储桶中,这再次触发SNS。然后,我将文件(作为用户api
从acc-1
复制到它们在acc-2
(content
)中的最终存储桶中。
content
中的 acc-2
存储桶策略
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACC_1_ID>:user/api"
},
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::content/*"
}
]
}
api
中的 acc-1
用户策略
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::upload/*",
"arn:aws:s3:::output/*",
"arn:aws:s3:::content/*"
]
}
]
}
我使用aws-sdk for nodejs复制文件,并将ACL设置为bucket-owner-full-control
,以便acc-2
中的用户可以访问content
中的复制文件,尽管{{1 }} api
的用户仍然是文件的所有者。
一切正常-文件存储在acc-1
存储桶中,并具有存储桶所有者和content
用户的访问权限。
api
存储桶中的文件对其他任何人都是私有的,应通过Cloudfront分发来提供。
我为Web创建了一个新的Cloudfront发行版,并使用了以下设置:
原始域名:content
原始路径:content
限制存储桶访问:/folder1
原始访问身份:yes
授予对存储桶的读取权限:create new identity
这创建了一个新的Origin Access Identity,并将存储桶策略更改为:
yes, update bucket policy
之后的存储桶策略
content
但是当我使用Cloudfront URL时,尝试从{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACC_1_ID>:user/api"
},
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::content/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <OAI_ID>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::content/*"
}
]
}
文件夹内的content
存储桶访问文件是行不通的:
folder1
这将返回403“访问被拒绝”。
如果我从❌ https://abcdef12345.cloudfront.net/test1.jpg
直接将文件(test2.jpg
)上传到acc-2
并尝试访问它,它就可以工作了...!?
content/folder1
✅ https://abcdef12345.cloudfront.net/test2.jpg
和test1.jpg
除了拥有不同的所有者外,看起来完全相同。
我在做什么错了?
答案 0 :(得分:1)
正如@Michael-sqlbot在他的答案中指出的那样,这是预期的行为。
一种可能的解决方案是使用acc-2
帐户中的凭据执行到最终存储桶的复制,因此对象的所有者将始终为acc-2
。至少有两个选择可以做到这一点:
1)使用临时凭证和AssumeRole AWS STS API :您在acc-2
中创建了一个IAM角色,并具有足够的权限以执行将副本复制到content
存储桶({{ 1}}和PutObject
),然后从PutObjectAcl
API调用AWS STS AssumeRole,以通过承担IAM角色获取临时凭证,并使用这些临时访问密钥执行复制。
这是最安全的方法。
2)使用访问密钥:您可以在acc-1
中创建一个IAM用户,为其生成常规访问密钥,并处理到acc-2
的那些密钥,因此acc-1
使用那些“永久”凭据来执行复制。
从安全角度来看,在AWS账户之间分配访问密钥不是一个好主意,AWS不鼓励您这样做,但肯定有可能。同样,从可维护性的角度来看,也可能是一个问题-因为acc-1
应该以非常安全的方式存储访问密钥,而acc-1
应该经常旋转访问密钥。
答案 1 :(得分:1)
解决方案包括两个步骤。
aws s3api put-object-acl --bucket bucket_name --key object_name --acl bucket-owner-full-control
aws s3 cp s3://object_path s3://object_path --metadata-directive COPY
答案 2 :(得分:0)
不幸的是,这是预期的行为。 OAI无法访问其他帐户拥有(创建)的对象,因为bucket-owner-full-control
使用了不完整的“完整”定义,该定义不包括对您自己的AWS账户之外的委托人的存储桶策略授权-而且从技术上讲,OAI的规范用户是,在您的AWS账户之外。
如果另一个AWS账户将文件上传到您的存储桶,则该账户是这些文件的所有者。存储桶策略仅适用于存储桶所有者拥有的文件。这意味着,如果另一个帐户将文件上载到存储桶,则不会为这些文件评估为OAI创建的存储桶策略。
答案 3 :(得分:0)
我的解决方案是使用s3 putobject事件和lambda。 在acc-1的putobject上,发出s3 putobject事件,并且该对象被acc-2的lambda覆盖。 这是我的程序(Python3)。
import boto3
from urllib.parse import unquote_plus
s3_client = boto3.client('s3')
def lambda_handler(event, context):
for record in event['Records']:
bucket = record['s3']['bucket']['name']
key = unquote_plus(record['s3']['object']['key'])
filename = '/tmp/tmpfile'
s3_client.download_file(bucket, key, filename)
s3_client.upload_file(filename, bucket, key)