基于S3存储桶的AWS Cloudfront分发,带有跨帐户对象的访问被拒绝

时间:2019-06-27 20:51:52

标签: amazon-web-services amazon-s3 amazon-cloudfront

我有两个帐户(acc-1acc-2)。
acc-1托管一个API,用于处理文件上传到acc-1桶中的情况(我们将其称为upload)。上传会触发SNS转换图像或对视频进行转码。生成的文件被放入acc-1output)中的另一个存储桶中,这再次触发SNS。然后,我将文件(作为用户apiacc-1复制到它们在acc-2content)中的最终存储桶中。

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除了拥有不同的所有者外,看起来完全相同。

我在做什么错了?

4 个答案:

答案 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)

解决方案包括两个步骤。

  1. 使用源帐户凭据运行以下命令
aws s3api put-object-acl --bucket bucket_name --key object_name --acl bucket-owner-full-control
  1. 使用目标帐户凭据运行以下命令
aws s3 cp s3://object_path  s3://object_path  --metadata-directive COPY

答案 2 :(得分:0)

不幸的是,这是预期的行为。 OAI无法访问其他帐户拥有(创建)的对象,因为bucket-owner-full-control使用了不完整的“完整”定义,该定义不包括对您自己的AWS账户之外的委托人的存储桶策略授权-而且从技术上讲,OAI的规范用户是,在您的AWS账户之外。

  

如果另一个AWS账户将文件上传到您的存储桶,则该账户是这些文件的所有者。存储桶策略仅适用于存储桶所有者拥有的文件。这意味着,如果另一个帐户将文件上载到存储桶,则不会为这些文件评估为OAI创建的存储桶策略。

     

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-granting-permissions-to-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)