【问题标题】:Access Denied to Public S3 Bucket from certain IP addresses拒绝从某些 IP 地址访问公共 S3 存储桶
【发布时间】: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=

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

    {
    "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 进行身份验证。

标签: php amazon-web-services amazon-s3 amazon-ec2


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    1. 缺少对 s3:PutObject 或 s3:PutObjectAcl 的权限
    2. 缺少使用 AWS Key Management Service (AWS KMS) 的权限 键
    3. 存储桶策略中的显式拒绝语句
    4. 存储桶访问控制列表 (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 存储桶策略

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

      1. 创建一个存储桶。禁用对它的所有公共访问。
      2. 附加以下 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/*"
                  ]
              }
          ]
      }
      
      1. 创建一个名为 ec2-instance-role 的新 IAM 角色。您确实需要附加任何 IAM 策略。留空。

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

      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 实例配置文件(角色)。

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

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

      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Sid": "Statement1",
                  "Effect": "Allow",
                  "Action": "s3:*",
                  "Resource": [
                      "arn:aws:s3:::yyyyyyyyyyy",
                      "arn:aws:s3:::yyyyyyyyyyy/*"
                  ]
              }
          ]
      }
      
      1. 转到您的 EC2 实例,单击 Actions -> Security -> Modify IAM role 并选择在上一步中创建的角色。

      2. 为了验证一切是否按预期工作,我使用的是 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

      【讨论】:

        猜你喜欢
        • 2019-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-16
        • 1970-01-01
        • 1970-01-01
        • 2017-07-04
        相关资源
        最近更新 更多