拒绝从某些 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 存储桶的主要内容,如果未能解决你的问题,请参考以下文章
无需凭据即可从特定 IP 授予对 AWS S3 存储桶的访问权限