S3公共读取访问受IP范围的限制,用于第三方上传的对象

时间:2018-06-21 13:54:30

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

我正在尝试完成以下方案:

1)帐户A将文件上传到帐户B拥有的S3存储桶。在上传时,我指定了帐户所有者B的完全控制权

s3_client.upload_file(
    local_file, 
    bucket, 
    remote_file_name, 
    ExtraArgs={'GrantFullControl': 'id=<AccountB_CanonicalID>'}
)

2)帐户B定义了一个存储桶策略,该策略限制了IP对对象的访问(见下文)

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "AllowIPs",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucketB/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        <CIDR1>,
                        <CIDR2>
                    ]
                }
            }
        }
    ]
}

如果我尝试以匿名用户的身份下载文件,即使是从特定的IP范围,也将拒绝访问。如果在上传时我为所有人添加了公共读取权限,则可以从任何IP下载文件。

s3_client.upload_file(
    local_file, bucket, 
    remote_file_name, 
    ExtraArgs={
        'GrantFullControl': 'id=AccountB_CanonicalID', GrantRead':'uri="http://acs.amazonaws.com/groups/global/AllUsers"'
    }
) 

问题:是否可以将文件从帐户A上传到帐户B,但仍通过IP范围限制公共访问。

1 个答案:

答案 0 :(得分:0)

这是不可能的。根据{{​​3}}:

  

存储桶策略–对于您的存储桶,您可以添加存储桶策略以授予   存储桶和存储区的其他AWS账户或IAM用户权限   对象。任何对象权限仅适用于   桶拥有者创建。桶策略的补充,在许多方面   在这种情况下,请替换基于ACL的访问策略。

但是,此方案有解决方法。问题在于上传文件的所有者是帐户A。我们需要以文件所有者为帐户B的方式上传文件。要实现这一点,我们需要:

  1. 在账户B中为可信实体创建一个角色(选择“另一个AWS账户”并指定账户A)。添加存储桶的上传权限。
  2. 在帐户A中创建一个策略,该策略允许执行AssumeRole操作,并作为资源指定在步骤1中创建的角色的ARN。

要从boto3上传文件,可以使用以下代码。请注意,使用cachetools处理临时证书的有限TTL。

import logging
import sys
import time

import boto3

from cachetools import cached, TTLCache

CREDENTIALS_TTL = 1800
credentials_cache = TTLCache(1, CREDENTIALS_TTL - 60)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger()


def main():
    local_file = sys.argv[1]
    bucket = '<bucket_from_account_B>'
    client = _get_s3_client_for_another_account()
    client.upload_file(local_file, bucket, local_file)
    logger.info('Uploaded to %s to %s' % (local_file, bucket))


@cached(credentials_cache)
def _get_s3_client_for_another_account():
    sts = boto3.client('sts')
    response = sts.assume_role(
        RoleArn='<arn_of_role_created_in_step_1>',
        DurationSeconds=CREDENTIALS_TTL
    )
    credentials = response['Credentials']
    credentials = {
        'aws_access_key_id': credentials['AccessKeyId'],
        'aws_secret_access_key': credentials['SecretAccessKey'],
        'aws_session_token': credentials['SessionToken'],
    }
    return boto3.client('s3', 'eu-central-1', **credentials)

if __name__ == '__main__':
    main()