如何使用AWS S3或AWS S3API递归对文件夹更改许可



我试图将权限授予S3中的现有帐户。

该存储桶归该帐户所有,但是数据是从另一个帐户的存储库复制的。

当我尝试使用命令授予权限时:

aws s3api put-object-acl --bucket <bucket_name> --key <folder_name> --profile <original_account_profile> --grant-full-control emailaddress=<destination_account_email>

我收到错误:

An error occurred (NoSuchKey) when calling the PutObjectAcl operation: The specified key does not exist.

,如果我在一个文件上执行此操作,则命令成功。

如何使其适用于完整文件夹?

这只能通过使用管道来实现。尝试 -

aws s3 ls s3://bucket/path/ --recursive | awk '{cmd="aws s3api put-object-acl --acl bucket-owner-full-control --bucket bucket --key "$4; system(cmd)}'

其他答案还可以,但是最快的方法是将aws s3 cp命令与选项--metadata-directive REPLACE一起使用,例如:

aws s3 cp --recursive --acl bucket-owner-full-control s3://bucket/folder s3://bucket/folder --metadata-directive REPLACE

这给出了50mib/s和80mib/s的速度。

John R的评论中的答案,该评论建议使用"虚拟"选项,例如--storage-class STANDARD。虽然这起作用,但只给了我5MIB/s和11MB/s。

之间的复制速度

尝试此操作的灵感来自AWS关于该主题的支持文章:https://aws.amazon.com/premiumsupport/knowledge-center/s3-object-change-change-annymos--anyrips/

注意:如果您对某些对象遇到"访问",这可能是因为您正在为存储桶拥有帐户使用AWS CREDS,而您需要对复制文件的帐户使用CREDS。/p>

您需要为每个对象单独运行命令。

您可能可以通过使用:

来缩短该过程
aws s3 cp --acl bucket-owner-full-control --metadata Key=Value --profile <original_account_profile> s3://bucket/path s3://bucket/path

也就是说,您将文件复制到自己,但添加的ACL将权限授予存储桶所有者。

如果您有子目录,请添加--recursive

使用python递归设置权限

#!/usr/bin/env python
import boto3
import sys
client = boto3.client('s3')
BUCKET='enter-bucket-name'
def process_s3_objects(prefix):
    """Get a list of all keys in an S3 bucket."""
    kwargs = {'Bucket': BUCKET, 'Prefix': prefix}
    failures = []
    while_true = True
    while while_true:
      resp = client.list_objects_v2(**kwargs)
      for obj in resp['Contents']:
        try:
            print(obj['Key'])
            set_acl(obj['Key'])
            kwargs['ContinuationToken'] = resp['NextContinuationToken']
        except KeyError:
            while_true = False
        except Exception:
            failures.append(obj["Key"])
            continue
    print "failures :", failures
def set_acl(key):
  client.put_object_acl(     
    GrantFullControl="id=%s" % get_account_canonical_id,
    Bucket=BUCKET,
    Key=key
)
def get_account_canonical_id():
  return client.list_buckets()["Owner"]["ID"]

process_s3_objects(sys.argv[1])

您可以做的一件事可以解决为每个对象设置ACL的需求,即为存储桶禁用ACL。然后,存储桶中的所有对象将由存储桶所有者所有,您可以使用策略进行访问控制而不是ACL。

您通过设置"对象所有权"来做到这一点。设置为"遗愿所有者"执行。根据AWS文档,这实际上是建议的设置:

在S3中的大多数现代用例中,我们建议您通过选择Bucket所有者执行设置并使用您的存储桶策略来禁用ACL,并根据需要与您的帐户外部的用户共享数据。这种方法简化了权限管理和审计。

您可以通过"权限"来将其设置在Web控制台中。标签的标签,然后单击"编辑"对象所有权"中的按钮部分。然后,您可以选择"禁用ACLS"。广播按钮。

您也可以使用AWS CLI。文档中的一个示例:

aws s3api put-bucket-ownership-controls --bucket DOC-EXAMPLE-BUCKET --ownership-controls Rules=[{ObjectOwnership=BucketOwnerEnforced}]

这是我的powershell解决方案。

aws s3 ls s3://BUCKET/ --recursive | %{ "aws s3api put-object-acl --bucket BUCKET --key "+$_.ToString().substring(30)+" --acl bucket-owner-full-control" }

我也有类似的问题,即在一个很大的存储桶中将日志对象拥有。物体总数-3,290,956总尺寸1.4 tb。

我能够找到的解决方案对于这一数量的对象来说太迟钝了。我最终编写了一些能够比

快几次的代码

AWS S3 CP

您需要安装要求:

pip install pathos boto3 click

#!/usr/bin/env python3
import logging
import os
import sys
import boto3
import botocore
import click
from time import time
from botocore.config import Config
from pathos.pools import ThreadPool as Pool
logger = logging.getLogger(__name__)
streamformater = logging.Formatter("[*] %(levelname)s: %(asctime)s: %(message)s")
logstreamhandler = logging.StreamHandler()
logstreamhandler.setFormatter(streamformater)

def _set_log_level(ctx, param, value):
    if value:
        ctx.ensure_object(dict)
        ctx.obj["log_level"] = value
        logger.setLevel(value)
        if value <= 20:
            logger.info(f"Logger set to {logging.getLevelName(logger.getEffectiveLevel())}")
    return value

@click.group(chain=False)
@click.version_option(version='0.1.0')
@click.pass_context
def cli(ctx):
    """
        Take object ownership of S3 bucket objects.
    """
    ctx.ensure_object(dict)
    ctx.obj["aws_config"] = Config(
        retries={
            'max_attempts': 10,
            'mode': 'standard'
        }
    )

@cli.command("own")
@click.argument("bucket", type=click.STRING)
@click.argument("prefix", type=click.STRING, default="/")
@click.option("--profile", type=click.STRING, default="default", envvar="AWS_DEFAULT_PROFILE", help="Configuration profile from ~/.aws/{credentials,config}")
@click.option("--region", type=click.STRING, default="us-east-1", envvar="AWS_DEFAULT_REGION", help="AWS region")
@click.option("--threads", "-t", type=click.INT, default=40, help="Threads to use")
@click.option("--loglevel", "log_level", hidden=True, flag_value=logging.INFO, callback=_set_log_level, expose_value=False, is_eager=True, default=True)
@click.option("--verbose", "-v", "log_level", flag_value=logging.DEBUG, callback=_set_log_level, expose_value=False, is_eager=True, help="Increase log_level")
@click.pass_context
def command_own(ctx, *args, **kwargs):
    ctx.obj.update(kwargs)
    profile_name = ctx.obj.get("profile")
    region = ctx.obj.get("region")
    bucket = ctx.obj.get("bucket")
    prefix = ctx.obj.get("prefix").lstrip("/")
    threads = ctx.obj.get("threads")
    pool = Pool(nodes=threads)
    logger.addHandler(logstreamhandler)
    logger.info(f"Getting ownership of all objects in s3://{bucket}/{prefix}")
    start = time()
    try:
        SESSION: boto3.Session = boto3.session.Session(profile_name=profile_name)
    except botocore.exceptions.ProfileNotFound as e:
        logger.warning(f"Profile {profile_name} was not found.")
        logger.warning(f"Falling back to environment variables for AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN")
        AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
        AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
        AWS_SESSION_TOKEN = os.environ.get("AWS_SESSION_TOKEN", "")
        if AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY:
            if AWS_SESSION_TOKEN:
                SESSION: boto3.Session = boto3.session.Session(aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                                                               aws_session_token=AWS_SESSION_TOKEN)
            else:
                SESSION: boto3.Session = boto3.session.Session(aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
        else:
            logger.error("Unable to find AWS credentials.")
            sys.exit(1)
    s3c = SESSION.client('s3', config=ctx.obj["aws_config"])
    def bucket_keys(Bucket, Prefix='', StartAfter='', Delimiter='/'):
        Prefix = Prefix[1:] if Prefix.startswith(Delimiter) else Prefix
        if not StartAfter:
            del StartAfter
            if Prefix.endswith(Delimiter):
                StartAfter = Prefix
        del Delimiter
        for page in s3c.get_paginator('list_objects_v2').paginate(Bucket=Bucket, Prefix=Prefix):
            for content in page.get('Contents', ()):
                yield content['Key']
    def worker(key):
        logger.info(f"Processing: {key}")
        s3c.copy_object(Bucket=bucket, Key=key,
                        CopySource={'Bucket': bucket, 'Key': key},
                        ACL='bucket-owner-full-control',
                        StorageClass="STANDARD"
                        )
    object_keys = bucket_keys(bucket, prefix)
    pool.map(worker, object_keys)
    end = time()
    logger.info(f"Completed for {end - start:.2f} seconds.")

if __name__ == '__main__':
    cli()

用法:

get_object_ownership.py own -v my-big-aws-logs-bucket /prefix

上面提到的水桶使用40个线程处理了〜7小时。

[*]信息:2021-08-05 19:53:55,542:完成25320.45秒。

使用AWS CLI与此工具在同一数据子集上进行了更多速度比较:

aws S3 CP-回报 - acl buccet-lower-full-control-metadata指导53.59S用户7.24S系统20%CPU 5:02.42 Total

vs

[*]信息:2021-08-06 09:07:43,506:完成49.09秒。

我使用此Linux Bash Shell Oneliner递归更改ACL:

aws s3 ls s3://bucket --recursive | cut -c 32- | xargs -n 1 -d 'n' -- aws s3api put-object-acl --acl public-read --bucket bukcet --key

即使文件名包含()字符也有效。

python代码以这种方式更有效,否则需要更长的时间。

import boto3
import sys
client = boto3.client('s3')
BUCKET='mybucket'
def process_s3_objects(prefix):
    """Get a list of all keys in an S3 bucket."""
    kwargs = {'Bucket': BUCKET, 'Prefix': prefix}
    failures = []
    while_true = True
    while while_true:
      resp = client.list_objects_v2(**kwargs)
      for obj in resp['Contents']:
        try:
            set_acl(obj['Key'])
        except KeyError:
            while_true = False
        except Exception:
            failures.append(obj["Key"])
            continue
      kwargs['ContinuationToken'] = resp['NextContinuationToken']
    print ("failures :"+ failures)
def set_acl(key):
  print(key)
  client.put_object_acl(
    ACL='bucket-owner-full-control',
    Bucket=BUCKET,
    Key=key
)
def get_account_canonical_id():
  return client.list_buckets()["Owner"]["ID"]

process_s3_objects(sys.argv[1])

最新更新