thephpleague / flysystem

Abstraction for local and remote filesystems
https://flysystem.thephpleague.com
MIT License
13.37k stars 829 forks source link

How to set 'bucket-owner-full-control' with async-aws s3 client? #1639

Open Jay-Way opened 1 year ago

Jay-Way commented 1 year ago

Hi all,

I am using flysystem with the async-aws s3 client. I want to upload a file to a bucket in an external account. I don't want to access the file afterwards, so the owner of the file should be the bucket owner. So what I did was set the ['ACL'=> 'bucket-owner-full-control'] as $config for the write method from the StorageInterface:

public function write(string $location, string $contents, array $config = []): void;

But when doing this then the receiving bucket owner cannot view the files, we always encounter an "access denied" on the external bucket side, when trying to open the file.

So, first question: What is the correct way to set 'bucket-owner-full-control' ACL for s3 uploads when using flysystem and async-aws as the adapter?

The second idea was to disable ACLs completely for the external bucket, but then we're getting 400 errors when uploading, with the error message "bucket does not support ACLs" - afaik the adapter always sets some kind of ACL internally, and then the external bucket denies the upload because no ACLs are expected.

Another thing I did not fully understand was the visibility option. I am using Symfony and in our flysystem.yaml the visibility property is not allowed under options.

Apart from that the visibility does not seem to be what I am looking for, because there is only public and private - but what I am looking for is the 'bucket-owner-full-control' option, I just want that the owner of the external bucket can access everything I upload into their bucket. So I tried setting the visbility to "public", but then I am getting a 403 error again.

Maybe someone can help with my confusion, TIA!

frankdejonge commented 1 year ago

@Nyholm would you be able to pick up this issue?

StagasaurusRex commented 1 year ago

I'm also trying to write to a bucket in a different account that is configured do disallow ACLs (as Amazon recommends) and am unable to do so due to Flysystem setting the 'ACL' property. Is it actually not possible to write to an S3 bucket in another account that is configured "correctly" from Amazons perspective?

LaurentQ56 commented 3 months ago

For my needs, I went through an override of League\Flysystem\AsyncAwsS3\PortableVisibilityConverter class, to override 'ACL' definition, and have bucket-owner-full-control.

namespace App\MyNamespace\Flysystem;

final class PortableVisibilityConverter implements VisibilityConverter
{
    private const PUBLIC_GRANTEE_URI = 'http://acs.amazonaws.com/groups/global/AllUsers';
    private const PUBLIC_GRANTS_PERMISSION = 'READ';
    private const FULL_CONTROL_ACL = 'bucket-owner-full-control';

    public function __construct(private readonly string $defaultForDirectories = Visibility::PUBLIC)
    {
    }

    public function visibilityToAcl(string $visibility): string
    {
        return self::FULL_CONTROL_ACL;
    }

    /**
     * {@inheritDoc}
     */
    public function aclToVisibility(array $grants): string
    {
        foreach ($grants as $grant) {
            if (null === $grantee = $grant->getGrantee()) {
                continue;
            }
            $granteeUri = $grantee->getUir();
            $permission = $grant->getPermission();

            if (self::PUBLIC_GRANTEE_URI === $granteeUri && self::PUBLIC_GRANTS_PERMISSION === $permission) {
                return Visibility::PUBLIC;
            }
        }

        return Visibility::PRIVATE;
    }

    public function defaultForDirectories(): string
    {
        return $this->defaultForDirectories;
    }
}
# config/services.yaml

services:

...

    flysystem.adapter.my_adapter:
        class: League\Flysystem\AsyncAwsS3\AsyncAwsS3Adapter
        arguments:
            $client: '@async_aws.client.s3'
            $bucket: '%env(MY_BUCKET_NAME)%'
            $prefix: ''
            $visibility: '@App\MyNamespace\Flysystem\PortableVisibilityConverter'

...
# config/packages/flysystem.yaml

flysystem:
    storages:
        s3.storage.my_storage:
            adapter: 'flysystem.adapter.my_adapter'
            options:
                client: 'async_aws.client.my_client.s3'
                bucket: '%env(MY_BUCKET_NAME)%'