审计AWS S3存储桶权限 是做什么的?
何时使用
- 在进行AWS环境安全评估以识别公开暴露的数据时
- 在接入新的AWS账户并建立存储资源安全基线时
- 在响应来自AWS Trusted Advisor或Security Hub的潜在S3数据暴露警报时
- 当合规框架(SOC 2、PCI DSS、HIPAA)要求定期审查数据访问控制时
- 在发生数据泄露或凭据泄露时,需要立即审查所有可访问的S3资源
请勿用于审计非AWS对象存储(请使用特定于提供商的工具)、实时监控(请使用S3事件通知与Lambda配合)或审计S3访问模式(请使用S3 Access Analyzer或CloudTrail S3数据事件)。
前提条件
- 已安装AWS CLI v2,并配置了具有
s3:GetBucketPolicy、s3:GetBucketAcl、s3:GetBucketPublicAccessBlock、s3:GetEncryptionConfiguration和s3:ListAllMyBuckets权限的凭据 - 已安装Prowler(通过
pip install prowler),用于自动执行CIS基准检查 - 已安装S3audit或类似的枚举工具,用于快速检测公有存储桶
- 如果跨多个账户审计,需访问AWS Organizations
- Python 3.8+及boto3,用于自定义审计脚本
工作流
步骤 1:枚举所有S3存储桶和账户级屏蔽公有访问
首先检查账户级S3屏蔽公有访问设置,然后列出所有存储桶及其区域。
# 检查账户级S3屏蔽公有访问设置
aws s3control get-public-access-block \
--account-id $(aws sts get-caller-identity --query Account --output text) \
--output json
# 列出所有存储桶及其创建日期
aws s3api list-buckets \
--query 'Buckets[*].[Name,CreationDate]' \
--output table
# 获取每个存储桶的区域
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
region=$(aws s3api get-bucket-location --bucket "$bucket" --query 'LocationConstraint' --output text)
echo "$bucket -> ${region:-us-east-1}"
done
步骤 2:检查每个存储桶的公有访问屏蔽和ACL配置
遍历所有存储桶,评估其各自的公有访问屏蔽和ACL授权。
# 检查每个存储桶的屏蔽公有访问设置
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
echo "=== $bucket ==="
aws s3api get-public-access-block --bucket "$bucket" 2>/dev/null || echo " 未配置屏蔽公有访问"
# 检查ACL中的公有授权
aws s3api get-bucket-acl --bucket "$bucket" \
--query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers` || Grantee.URI==`http://acs.amazonaws.com/groups/global/AuthenticatedUsers`]' \
--output json
done
步骤 3:分析存储桶策略是否存在过度宽松的访问权限
审查存储桶策略中的通配符主体、缺失的条件以及允许广泛访问的语句。
# 提取并分析存储桶策略
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
policy=$(aws s3api get-bucket-policy --bucket "$bucket" --output text 2>/dev/null)
if [ -n "$policy" ]; then
echo "=== $bucket 策略 ==="
echo "$policy" | python3 -c "
import json, sys
policy = json.load(sys.stdin)
for stmt in policy.get('Statement', []):
principal = stmt.get('Principal', {})
effect = stmt.get('Effect', '')
if principal == '*' or principal == {'AWS': '*'}:
print(f' 警告: {effect} 包含通配符主体')
print(f' 操作: {stmt.get(\"Action\", \"\")}')
print(f' 条件: {stmt.get(\"Condition\", \"无\")}')
"
fi
done
步骤 4:验证加密和版本控制设置
检查所有存储桶是否启用了服务器端加密并配置了版本控制以保护数据。
# 检查所有存储桶的加密和版本控制状态
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
echo "=== $bucket ==="
# 加密配置
aws s3api get-bucket-encryption --bucket "$bucket" 2>/dev/null \
&& echo " 加密: 已启用" \
|| echo " 加密: 已禁用"
# 版本控制状态
aws s3api get-bucket-versioning --bucket "$bucket" \
--query 'Status' --output text
# 日志记录状态
aws s3api get-bucket-logging --bucket "$bucket" \
--query 'LoggingEnabled' --output text 2>/dev/null
done
步骤 5:运行Prowler S3专用检查
执行Prowler针对S3的检查,符合CIS AWS Foundations基准。
# 运行Prowler S3专用检查
prowler aws \
--checks s3_bucket_public_access \
s3_bucket_default_encryption \
s3_bucket_policy_public_write_access \
s3_bucket_server_access_logging_enabled \
s3_bucket_versioning_enabled \
s3_bucket_acl_prohibited \
-M json-ocsf \
-o ./prowler-s3-audit/
# 查看摘要
prowler aws --checks s3 -M csv -o ./prowler-s3-audit/
步骤 6:使用IAM Access Analyzer获取S3公有和跨账户发现
利用IAM Access Analyzer识别对外公开或跨账户共享的存储桶。
# 列出S3的Access Analyzer发现结果
aws accessanalyzer list-findings \
--analyzer-arn $(aws accessanalyzer list-analyzers --query 'analyzers[0].arn' --output text) \
--filter '{"resourceType": {"eq": ["AWS::S3::Bucket"]}}' \
--query 'findings[*].[resource,status,condition,principal]' \
--output table
# 如果分析器不存在,则创建一个
aws accessanalyzer create-analyzer \
--analyzer-name s3-access-audit \
--type ACCOUNT
步骤 7:生成审计报告并进行修复
将发现结果汇编成可操作的报告,并对关键问题应用修复措施。
# 快速修复:在存储桶上启用屏蔽公有访问
aws s3api put-public-access-block \
--bucket TARGET_BUCKET \
--public-access-block-configuration \
'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'
# 使用SSE-S3启用默认加密
aws s3api put-bucket-encryption \
--bucket TARGET_BUCKET \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"alias/aws/s3"},"BucketKeyEnabled":true}]}'
# 启用版本控制
aws s3api put-bucket-versioning \
--bucket TARGET_BUCKET \
--versioning-configuration Status=Enabled
关键概念
| 术语 | 定义 |
|---|---|
| S3屏蔽公有访问 | 账户级和存储桶级设置,可覆盖ACL和策略,无论单个资源配置如何,都能防止公有访问 |
| 存储桶策略 | 附加到存储桶的基于JSON的资源策略,定义谁可以访问该存储桶以及他们可以执行哪些操作 |
| ACL(访问控制列表) | 传统S3访问控制机制,向AWS账户或预定义组(如AllUsers或AuthenticatedUsers)授予权限 |
| IAM Access Analyzer | AWS服务,分析资源策略以识别与外部实体或公众共享的资源 |
| 服务器端加密 | S3在对象级别应用的加密,使用SSE-S3、SSE-KMS或SSE-C在将数据写入磁盘之前进行加密 |
| CIS AWS Foundations基准 | 来自互联网安全中心的安全最佳实践标准,包含针对S3存储桶配置的特定控制 |
工具与系统
- AWS CLI:查询S3存储桶配置、策略、ACL和加密设置的主要接口
- Prowler:开源安全工具,提供50+项S3专用检查,符合CIS、PCI DSS和HIPAA控制要求
- IAM Access Analyzer:AWS原生服务,用于持续监控授予外部访问权限的资源策略
- S3audit:轻量级工具,用于快速枚举账户中的公有S3存储桶
- ScoutSuite:多云审计工具,收集S3配置数据并生成带风险评分的HTML报告
常见场景
场景:识别包含客户数据的公有可读存储桶
背景:安全工程师收到Trusted Advisor关于公有可访问S3存储桶的警报。该存储桶由开发团队为演示创建,但从未锁定。
方法:
- 运行
aws s3api get-bucket-acl,发现对AllUsers授予了READ权限 - 检查
get-bucket-policy,发现存在Principal: "*"和s3:GetObject的策略 - 确认在存储桶或账户级别未启用屏蔽公有访问
- 枚举存储桶内容以评估数据敏感性
- 立即在存储桶上启用屏蔽公有访问
- 审查CloudTrail S3数据事件,以确定是否发生了未经授权的访问
- 报告发现结果,包括时间线、数据清单和修复确认
陷阱:启用屏蔽公有访问可能会破坏有意提供公共内容(如静态网站)的应用程序。在应用限制之前,务必验证存储桶的预期用途。检查是否有CloudFront分发或其他依赖该存储桶公有访问的服务。
输出格式
S3存储桶权限审计报告
=====================================
账户:123456789012(生产环境)
日期:2026-02-23
审计员:安全工程团队
存储桶总数:47
账户级设置:
屏蔽公有访问:已启用(所有四个设置)
关键发现:
[S3-001] 通过ACL实现公有读取访问
存储桶:marketing-assets-prod
问题:AllUsers组通过ACL被授予了READ权限
风险:任何互联网用户都可以列出并下载存储桶内容
数据敏感性:包含面向客户但非敏感的市场营销资产
修复措施:移除AllUsers ACL授权,启用屏蔽公有访问
[S3-002] 存储桶策略中的通配符主体
存储桶:data-exchange-partner
问题:策略允许s3:GetObject,主体为"*",且无VPC/IP条件
风险:旨在供合作伙伴访问,但任何知道存储桶名称的人都可以访问
修复措施:添加aws:SourceVpce或aws:SourceIp条件以限制访问
摘要:
具有公有访问权限的存储桶: 3 / 47
未加密的存储桶: 5 / 47
未启用版本控制的存储桶: 12 / 47
未启用访问日志记录的存储桶: 18 / 47
具有过度宽松策略的存储桶: 7 / 47