拒绝从某些 IP 地址访问公共 S3 存储桶

Posted

技术标签:

【中文标题】拒绝从某些 IP 地址访问公共 S3 存储桶【英文标题】:Access Denied to Public S3 Bucket from certain IP addresses 【发布时间】:2022-01-14 14:42:46 【问题描述】:

我尝试制作一个完全公开的 S3 存储桶并使用 php SDK 进行访问。当我从本地机器运行下面的访问代码时,这有效:

require 'vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;

$s3 = new S3Client([
    'version' => 'latest',
    'region'  => 'eu-west-2',
    'credentials' => [
        'key'    => "my correct key",
        'secret' => "my correct secret"
        ]
]);

// //publictest2
$bucket = 'mybucketname';
$keyname = 'test_file.txt';

// Upload an object
try 
    // Upload data.
    $result = $s3->putObject([
        'Bucket' => $bucket,
        'Key'    => $keyname,
        'Body'   => 'Hello',
        'ACL'    => 'public-read'
    ]);

    // Print the URL to the object.
    echo $result['ObjectURL'] . PHP_EOL;
 catch (S3Exception $e) 
    echo $e->getMessage() . PHP_EOL;

但是,一旦我从测试服务器(AWS EC2)运行它,我就会收到以下错误:

Error executing "PutObject" on "mybucketname"; AWS HTTP error: Client error: `PUT https://mybucketname/test_file.txt` resulted in a `403 Forbidden` response: AccessDeniedAccess DeniedVTJX7V (truncated...) AccessDenied (client): Access Denied - AccessDeniedAccess DeniedVTJX7V4CCKZYG7CRTz+dPA7fsZQnFxTERKxxbP+IpTtMIIsS1uu23fvTruHH3w8KxwGIduCntRBM5u6tIfHdusbCoPw=

我已经实现了以下内容来公开存储桶:

关闭所有阻止公共访问设置,包括帐户和存储桶级别:block public access settings at bucket level 编辑对象所有权: edit object ownership section 我这样编辑了 ACL 列表:acl settings 我什至创建了一个存储桶策略,允许任何人对存储桶执行任何操作:
    
    "Version": "2012-10-17",
    "Id": "S3BukcetPolicyIPAccess",
    "Statement": [
        
            "Sid": "DenyIfNotFromAllowedVPC",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "mybucketarn",
                "mybucketarn/*"
            ]
        
    ]

为什么从我的 EC2 服务器运行时这仍然不起作用?

【问题讨论】:

在本地和 Ec2 实例中运行时是否使用相同的 Access Key 和 Secret Access Key? 您不需要 ACL 来处理这些。一般来说,您不应该使用 ACL。此外,向任何人授予 s3:* 权限的存储桶策略几乎可以肯定是一个非常糟糕的主意(除非您临时这样做是为了测试某些东西,在这种情况下它仍然是一个坏主意)。 在您的 EC2 实例上运行此命令:aws sts get-caller-identity。这将使您深入了解 AWS 委托人,AWS CLI 代表 AWS API 对 AWS API 进行身份验证。 【参考方案1】:

这与 S3 存储桶无关 - 这里的提示是它在您的本地机器上工作,这意味着 S3 存储桶不应该受到指责,而是实例。

这与您的 EC2 实例承担(或不承担)的角色有关 - 创建并分配有权在 mybucketname 上执行 PutObject 的 IAM 角色。

对此进行测试的一种快速方法是使用附加了 AWS 托管策略 AmazonS3FullAccess 的角色,该策略提供对所有 S3 存储桶的完全访问权限。

然后您的 EC2 实例将有权访问 S3 存储桶。

【讨论】:

【参考方案2】:

对于 HTTP 403 Forbidden 错误,请按照以下步骤进行调试。

    缺少对 s3:PutObject 或 s3:PutObjectAcl 的权限 缺少使用 AWS Key Management Service (AWS KMS) 的权限 键 存储桶策略中的显式拒绝语句 存储桶访问控制列表 (ACL) 不允许 AWS 账户根 用户编写对象

您能否从您的 ec2 实例中检查此命令

“aws s3 ls s3://doc-example-bucket/abc/”

如果此命令成功,则您的应用程序代码中指定的凭据或角色会导致“访问被拒绝”错误。 确保实例配置文件角色具有 S3 存储桶所需的读取和写入权限。例如,以下 IAM 策略中的 S3 操作提供了对 S3 存储桶所需的读写访问权限。

【讨论】:

【参考方案3】:

您的问题是在您的 EC2 实例上运行的 PHP Web 服务器使用 AWS PHP SDK,并且它确实没有配置了 IAM 主体,因为没有 instance profile(AWS 角色)附加到您的 EC2,也不是使用aws configure 配置的默认配置文件(AWS 用户)。

换句话说,您的 AWS API 调用未经过身份验证,更不用说授权对 S3 执行任何操作了。 即使如果您在 Bucket 策略中允许所有 Principals 使用 s3:*。请记住:存储桶策略需要 AWS 委托人,但您的请求未经过身份验证(AWS API 无法确定谁在调用)。因此AccessDenied

您的问题有多种解决方案。但所有这些都可以归结为:

使用 IAM 政策(推荐)

使用 S3 存储桶策略

您可以查看 this AWS blog post 以了解要遵循的方法,但对于您的特定问题,我会使用 IAM 政策。


使用 S3 存储桶策略

让我先从第二种解决方案开始。

    创建一个存储桶。禁用对它的所有公共访问。 附加以下 S3 存储桶策略:

    "Version": "2012-10-17",
    "Statement": [
        
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": 
                "AWS": "arn:aws:iam::xxxxxxxxxxx:role/ec2-instance-role"
            ,
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::yyyyyyyyyyy",
                "arn:aws:s3:::yyyyyyyyyyy/*"
            ]
        
    ]

    创建一个名为 ec2-instance-role 的新 IAM 角色。您确实需要附加任何 IAM 策略。留空。

    转到您的 EC2 实例,单击 Actions -> Security -> Modify IAM role 并选择在步骤 3 中创建的角色。

    无需重启实例。为了验证一切按预期工作,我使用的是 AWS CLI,但它也应该适用于任何 SDK(例如 PHP)。从您的 EC2 实例执行:

# Make sure the correct role is assumed
$ aws sts get-caller-identity

    "Account": "xxxxxxxxxxx",
    "UserId": "AROAYGJILC6K4AJRGLZTS:i-0aa422c12359ac00e",
    "Arn": "arn:aws:sts::xxxxxxxxxxx:assumed-role/ec2-instance-role/i-0aa422c12359ac00e"


# Upload a test file and check the bucket
$ touch test.txt
$ aws s3 cp test.txt s3://yyyyyyyyyyy/test.txt
upload: ./test.txt to s3://yyyyyyyyyyy/test.txt
$ aws s3 ls s3://yyyyyyyyyyy
2021-12-12 11:01:51        0 test.txt

使用 IAM 政策

在这里,除了您不需要任何存储桶策略之外,一切都保持不变,但您将策略直接附加到 IAM 实例配置文件(角色)。

    创建一个存储桶。禁用对它的所有公共访问。禁用 ACL。

    使用以下策略创建一个名为 ec2-instance-role 的新 IAM 角色:


    "Version": "2012-10-17",
    "Statement": [
        
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::yyyyyyyyyyy",
                "arn:aws:s3:::yyyyyyyyyyy/*"
            ]
        
    ]

    转到您的 EC2 实例,单击 Actions -> Security -> Modify IAM role 并选择在上一步中创建的角色。

    为了验证一切是否按预期工作,我使用的是 AWS CLI,但它也应该适用于任何 SDK(例如 PHP)。从您的 EC2 实例执行:

# Make sure the correct role is assumed
$ aws sts get-caller-identity

    "Account": "xxxxxxxxxxx",
    "UserId": "AROAYGJILC6K4AJRGLZTS:i-0aa422c12359ac00e",
    "Arn": "arn:aws:sts::xxxxxxxxxxx:assumed-role/ec2-instance-role/i-0aa422c12359ac00e"


# Upload a test file and check the bucket
$ touch test.txt
$ aws s3 cp test.txt s3://yyyyyyyyyyy/test.txt
upload: ./test.txt to s3://yyyyyyyyyyy/test.txt
$ aws s3 ls s3://yyyyyyyyyyy
2021-12-12 11:01:51        0 test.txt

最后但并非最不重要的两种方法:不要使用 ACL(使用 ACLs disabled 配置您的存储桶),因为存在 ACL 是为了向后兼容以支持存储桶策略,请参阅同一 blog post 中的详细信息:

作为一般规则,AWS 建议使用 S3 存储桶策略或 IAM 访问控制策略。 S3 ACL 是传统的访问控制 早于 IAM 的机制。


在上面的sn-ps中:

xxxxxxxxxxx 是您的 AWS 帐号,例如561262107623 yyyyyyyyyyy 是您的存储桶名称,例如mybucket

【讨论】:

以上是关于拒绝从某些 IP 地址访问公共 S3 存储桶的主要内容,如果未能解决你的问题,请参考以下文章

AWS S3 存储桶策略编辑器访问被拒绝

无需凭据即可从特定 IP 授予对 AWS S3 存储桶的访问权限

将文件从 HDFS 放入 S3 存储桶时访问被拒绝

S3 端点访问被拒绝错误

AWS S3 存储桶策略:如何授予对 EC2 实例的访问权限?

为啥我的 lambda 函数在尝试访问 S3 存储桶时会被拒绝访问?