Skip to content

S3 存储桶 ACL 错误解决方案

问题描述

在使用 AWS S3 上传文件时遇到 "The bucket does not allow ACLs" 错误,即使已经在对象所有权设置中启用了 ACLs。这个问题通常发生在尝试通过代码上传文件并设置 ACL 权限时。

错误示例代码:

csharp
[HttpPost]
public bool UploadFile(string file)
{
    var s3Client = new AmazonS3Client(accesskey, secretkey, RegionEndpoint.APSoutheast1);
    var fileTransferUtility = new TransferUtility(s3Client);
    
    if (file.Length > 0)
    {
        var fileTransferUtilityRequest = new TransferUtilityUploadRequest
        {
            BucketName = bucketName,
            FilePath = filePath,
            StorageClass = S3StorageClass.StandardInfrequentAccess,
            PartSize = 6291456,
            Key = keyName,
            CannedACL = S3CannedACL.PublicRead // 这里导致问题
        };
        fileTransferUtilityRequest.Metadata.Add("param1", "Value1");
        fileTransferUtilityRequest.Metadata.Add("param2", "Value2");
        fileTransferUtility.Upload(fileTransferUtilityRequest);
        fileTransferUtility.Dispose();
    }
    return true;
}

解决方案

方法一:启用存储桶 ACL(推荐临时的解决方案)

注意

AWS 推荐使用存储桶策略而非 ACL 来管理权限。仅在必要时启用 ACL。

  1. 进入 S3 控制台,选择目标存储桶
  2. 点击「权限」选项卡
  3. 找到「对象所有权」部分,点击「编辑」
  4. 选择「ACLs 已启用」选项
  5. 保存更改

对象所有权设置

  1. 现在可以编辑 ACL 权限:
    • 选择「存储桶」选项卡
    • 点击「权限」→「编辑」ACL 设置
    • 设置所需权限并保存

方法二:使用 CLI 配置(适合自动化部署)

bash
# 禁用公共访问阻止设置
aws s3api put-public-access-block --bucket MY_BUCKET \
  --public-access-block-configuration 'BlockPublicAcls=false,
    IgnorePublicAcls=false,
    BlockPublicPolicy=false,
    RestrictPublicBuckets=false'

# 设置存储桶所有权控制
aws s3api put-bucket-ownership-controls --bucket MY_BUCKET \
  --ownership-controls 'Rules=[{ObjectOwnership="BucketOwnerPreferred"}]'

方法三:使用存储桶策略替代 ACL(最佳实践)

推荐

这是 AWS 推荐的最佳实践,避免使用 ACL 并完全依赖存储桶策略管理权限。

修改代码,移除 ACL 设置:

csharp
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
    BucketName = bucketName,
    FilePath = filePath,
    StorageClass = S3StorageClass.StandardInfrequentAccess,
    PartSize = 6291456,
    Key = keyName
    // 移除 CannedACL = S3CannedACL.PublicRead
};

使用以下存储桶策略:

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowOwnerFullAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<your-account-id>:user/<dedicated-s3-user>"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:PutObjectAcl",
                "s3:GetObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::<bucket>/*",
                "arn:aws:s3:::<bucket>"
            ]
        },
        {
            "Sid": "AllowPublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<bucket>/*"
        }
    ]
}

方法四:PHP/Laravel 特定解决方案

对于 Laravel 用户,可以在配置中设置空 ACL:

php
's3' => [
    'driver' => 's3',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_DEFAULT_REGION'),
    'bucket' => env('AWS_BUCKET'),
    'url' => env('AWS_URL'),
    'endpoint' => env('AWS_ENDPOINT'),
    'options' => [
        'ACL' => '', // 设置空 ACL
    ],
]

或在代码中使用私有权限:

php
// 将 'public' 改为 'private'
$isStore = Storage::disk(env('CLOUD_STORAGE_DISK'))->put(
    $filePath, 
    file_get_contents($file), 
    'private' // 而非 'public'
);

总结

"S3 存储桶不允许 ACL" 错误通常由以下原因引起:

  1. 存储桶的 ACL 被禁用或受公共访问块限制
  2. 代码中显式设置了 ACL 但存储桶配置不允许

推荐解决方案

  • 优先使用存储桶策略而非 ACL 管理权限
  • 如果必须使用 ACL,确保正确配置存储桶设置
  • 遵循最小权限原则,仅授予必要的访问权限

通过正确配置存储桶策略和访问控制设置,可以完全避免 ACL 相关的错误,同时提高安全性。