使用 CLI 上传的文件夹没有正确的 ACL(文件没问题,只有文件夹有问题)

Folders uploaded with CLI don't have proper ACL (files are ok, only folders have issues)

所以我正在尝试将资产从服务器移动到 S3。

资产用于 typo3 环境。不过,我的问题似乎出在 S3 上。由于某种原因,它不提供对文件夹的适当访问权限。

Created 文件夹似乎工作正常,而通过浏览器或 aws-cli 上传的文件夹没有获得适当的权限。文件夹里面的文件都ok,可读可写。但是 TYPO3 也需要文件夹。否则我到处都会遇到一些严重的错误。

这是我第一次使用 S3,所以问题是:我在 permissions/settings 中做错了什么,或者这是 S3 的一个已知问题?如果我搞砸了,有什么地方可以看吗?

这是我的项目存储桶策略。 user/project 出于安全原因更改。

{
    "Version": "2012-10-17",
    "Id": "someID",
    "Statement": [
        {
            "Sid": "Read and write access for typo3 system",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::user/project"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::project/*"
        },
        {
            "Sid": "Public read access",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl"
            ],
            "Resource": "arn:aws:s3:::project/*"
        }
    ]
}

而且我还添加了一个 CORS 配置,因为存储桶用作 typo3 系统的资产存储。出于安全原因更改域。

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://*.domain.com</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

正如我所说,在 typo3 后端或 S3 管理控制台中手动创建文件夹工作正常。 在 S3 管理控制台中上传,或与 aws-cli 同步不会。

(抱歉,无法 post 图片,因为我没有足够的 "reputation")

https://imgur.com/lDlg4bP.png

https://i.imgur.com/UexKWLo.png

And when selecting a folder that contains other such broken folders, there's an orange error showing in TYPO3's Filelist module:

Error executing "GetObjectAcl" on "https://project.s3.eu-central-1.amazonaws.com/test_folder/uploaded_with_cli/?acl"; AWS HTTP error: Client error: 
`GET https://project.s3.eu-central-1.amazonaws.com/test_folder/uploaded_with_cli/?acl` resulted in a `404 Not Found` response: <?xml version="1.0" 
encoding="UTF-8"?> <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message> (truncated...) NoSuchKey (client): The specified
 key does not exist. - <?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>
test_folder/uploaded_with_cli/</Key><RequestId>****randomkey****</RequestId><HostId>****randomsecretkey****</HostId></Error>

标记的randomkeyrandomsecretkey好像是类似id&secretkey的随机字符串,但是每次破解文件夹都会出现这样的错误使用完全不同的密钥集。我检查过,其中 none 个是用户的真实 ID 和密钥。

S3没有目录(文件夹)的概念。 S3 是一个对象存储,其中每个对象都由一个键标识。密钥可能是 "logs/2014/06/04/system.log"

这样的字符串

S3 之上的大多数图形用户界面(AWS CLI、AWS 控制台、Cloudberry、Transmit 等...)将“/”字符解释为目录分隔符并显示文件列表 "as is"在目录结构中。

但是,在内部,没有目录的概念,S3 有一个扁平的命名空间。有关详细信息,请参阅 http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html

鉴于此,您不能对文件夹定义权限是正常的,因为S3 上没有文件夹。一些 GUI 工具会创建空文件来表示文件夹,有些则不会。我不知道 Typo3 如何处理 S3 上的 "folders"。

对于那些在使用 S3 时寻找解决 typo3 文件列表问题的方法的人,您需要将 ACL 添加到所有文件夹。

创建 S3Client 对象:

$s3 = new Aws\S3\S3Client([
        'region' => $region,
        'version' => 'latest',
        'credentials' => [
            'key' => $key,
            'secret' => $secret,
        ]
    ]);

并为每个 "folder" 添加 ACL:

$s3->putObject([
            'Bucket' => $bucket,
            'Key' => $folderToCreate,
            'Body' => '',
            'ACL' => 'public-read'
        ]);

您可以使用包含文件夹列表的简单 .txt 文件

find -type d -printf "%P\n" > dirs.txt

或者,如果您喜欢过度设计,您可以使用

列出数组中的所有现有对象
try {
        $results = $s3->getPaginator('ListObjects', [
            'Bucket' => $bucket
        ]);

        foreach ($results as $result) {
            foreach ($result['Contents'] as $object) {
                array_push($allObjects, $object['Key']);
            }
        }
    } catch (S3Exception $e) {
        echo $e->getMessage() . PHP_EOL;
    }

,从那里你必须:

删除文件(您只需要一个目录列表)。您可以为此使用 pathinfo())

删除重复项

去掉“.” and/or“..”值

您可能还想为构成文件路径的子目录设置 ACL(对于构成路径的子目录中没有文件的情况)

foreach ($allPaths as $longpath) {
        $explodedpath = explode('/', $longpath);

        $goodPathValue = '';

        foreach ($explodedpath as $segment) {

            if ($goodPathValue == '') {
                $goodPathValue = $segment;
            } else {

                // if it's not the first folder, we append the segment to it with a slash in between
                $goodPathValue .= "/" . $segment;
            }

            // at this point we either have first folder, or a part of the full path, which we enter in the array if it's unique
            if (!in_array($goodPathValue, $allPaths)) {
                array_push($allPaths, $goodPathValue);
            }
        }
    }

为了获得最佳结果,.txt 或数组应该是这样的

downloads
downloads/en
downloads/en/user_upload
downloads/en/user_upload/Products
downloads/en/user_upload/Markets