"开启了S3版本控制,所以备份不会丢"是一个常见误区。Versioning确实能保留被覆盖或误删对象的历史版本,但如果攻击者已经获得删除对象版本的权限,历史版本仍可能被永久删除。要构建更可靠的备份链路,需要把版本恢复、WORM不可变保留、权限隔离和恢复演练放在一起设计。
本文以AWS CLI演示一套可验证流程:先启用Versioning,再为现有Bucket启用Object Lock,设置30天GOVERNANCE默认保留期,模拟删除并恢复对象,最后验证受保护版本无法被普通删除。命令依据AWS官方当前文档整理;示例保留期、区域和Bucket名称必须按企业数据分类、法规和成本要求调整。

一、四层保护解决的是不同问题

第一层是Versioning。普通删除会添加Delete Marker,覆盖写入会产生新版本,因此可以找回旧版本。但Versioning不是不可删除机制。
第二层是Object Lock。它只保护指定对象版本,通过保留期或Legal Hold阻止版本被覆盖或删除。它不会阻止创建新版本,也不会阻止在对象上方添加Delete Marker。
第三层是权限隔离。应用账号通常只应写入新备份,不应拥有删除历史版本、缩短保留期或绕过GOVERNANCE的权限。
第四层是恢复演练。没有定期验证版本清单、校验和、解密权限和恢复时间的"备份",只能算存储副本。
二、GOVERNANCE与COMPLIANCE不能混用概念
Object Lock有两种主要保留模式:
GOVERNANCE:默认阻止删除或缩短保留期,但拥有s3:BypassGovernanceRetention权限的受控主体可以显式绕过,适合先试运行和具备紧急变更流程的场景;COMPLIANCE:在保留期到期前,即使Root用户也不能删除受保护版本或缩短保留期,适合明确的法规或审计要求。
不要因为"更安全"就直接把生产Bucket改成多年COMPLIANCE。错误保留期会带来无法提前删除和持续存储费用。先完成数据分类、法务确认、容量测算和测试Bucket演练。
AWS官方目前支持在现有Bucket上启用Object Lock,但要求先启用Versioning;启用后,Bucket将永久具备锁定对象的能力,不能撤销这一能力。
三、准备测试环境
先确认CLI身份和区域。不要在脚本中写长期Access Key;本地优先使用AWS IAM Identity Center或受控临时凭证。
bash
aws sts get-caller-identity
export AWS_REGION="ap-southeast-1"
export BUCKET="company-backup-lab-$(aws sts get-caller-identity --query Account --output text)"
export KEY="database/orders-$(date +%F).sql.gz"
创建专用测试Bucket:
bash
aws s3api create-bucket \
--bucket "$BUCKET" \
--region "$AWS_REGION" \
--create-bucket-configuration LocationConstraint="$AWS_REGION"
us-east-1创建Bucket时不使用LocationConstraint,如果选择该区域,应移除最后一行参数。
四、启用Versioning并验证
bash
aws s3api put-bucket-versioning \
--bucket "$BUCKET" \
--versioning-configuration Status=Enabled
aws s3api get-bucket-versioning --bucket "$BUCKET"
期望看到:
json
{
"Status": "Enabled"
}
Versioning启用后,暂停Versioning不会删除已有版本,但会改变后续对象的版本行为。生产环境应通过组织级策略、权限边界和配置监控防止未经授权的状态变更。
五、为现有Bucket启用Object Lock
以下示例启用Object Lock,并为之后写入的新对象设置30天GOVERNANCE默认保留期:
bash
cat > object-lock.json <<'JSON'
{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 30
}
}
}
JSON
aws s3api put-object-lock-configuration \
--bucket "$BUCKET" \
--object-lock-configuration file://object-lock.json
aws s3api get-object-lock-configuration --bucket "$BUCKET"
这里的默认保留规则只自动应用于规则生效后写入的新对象版本。不要假设Bucket内所有历史对象都会自动获得相同保留期;历史对象需要清单、Batch Operations或逐版本处理,并应先在测试范围验证。
六、上传对象并核对锁定元数据
创建一份测试文件并上传:
bash
printf 'backup-test %s\n' "$(date -Iseconds)" > backup.txt
aws s3api put-object \
--bucket "$BUCKET" \
--key "$KEY" \
--body backup.txt
取得Version ID:
bash
VERSION_ID=$(aws s3api list-object-versions \
--bucket "$BUCKET" \
--prefix "$KEY" \
--query 'Versions[?IsLatest==`true`].VersionId | [0]' \
--output text)
echo "$VERSION_ID"
验证保留模式和到期时间:
bash
aws s3api head-object \
--bucket "$BUCKET" \
--key "$KEY" \
--version-id "$VERSION_ID" \
--query '{VersionId:VersionId,Mode:ObjectLockMode,RetainUntil:ObjectLockRetainUntilDate,Length:ContentLength}'
如果返回Mode: GOVERNANCE和未来的RetainUntil时间,说明默认规则已应用到该版本。
七、模拟误删并恢复

普通删除当前对象:
bash
aws s3api delete-object --bucket "$BUCKET" --key "$KEY"
Versioning开启时,这一步通常创建Delete Marker,而不是删除受保护的数据版本。查询版本和删除标记:
bash
aws s3api list-object-versions \
--bucket "$BUCKET" \
--prefix "$KEY" \
--query '{Versions:Versions[].{Id:VersionId,Latest:IsLatest,Size:Size},DeleteMarkers:DeleteMarkers[].{Id:VersionId,Latest:IsLatest}}'
取得最新Delete Marker并删除它,当前对象即可重新可见:
bash
DELETE_MARKER_ID=$(aws s3api list-object-versions \
--bucket "$BUCKET" \
--prefix "$KEY" \
--query 'DeleteMarkers[?IsLatest==`true`].VersionId | [0]' \
--output text)
aws s3api delete-object \
--bucket "$BUCKET" \
--key "$KEY" \
--version-id "$DELETE_MARKER_ID"
aws s3api head-object --bucket "$BUCKET" --key "$KEY"
如果Delete Marker不是最新版本,恢复策略应明确指定要恢复的对象版本,避免误删其他合法版本。
八、验证锁定版本无法被普通删除
尝试永久删除受保护版本:
bash
aws s3api delete-object \
--bucket "$BUCKET" \
--key "$KEY" \
--version-id "$VERSION_ID"
在保留期内,普通请求应返回AccessDenied。GOVERNANCE模式下,只有同时具备s3:BypassGovernanceRetention权限并显式发送绕过参数的受控操作才可能删除;日常应用角色不应拥有该权限。
不要在生产演练中为了"验证能否绕过"而直接删除真实备份。应使用专用测试对象、审批后的Break-glass角色和完整CloudTrail审计。
九、恢复验收矩阵

至少检查以下结果:
bash
# 1. 版本控制状态
aws s3api get-bucket-versioning --bucket "$BUCKET"
# 2. Object Lock默认规则
aws s3api get-object-lock-configuration --bucket "$BUCKET"
# 3. 指定对象的所有版本与Delete Marker
aws s3api list-object-versions --bucket "$BUCKET" --prefix "$KEY"
# 4. 下载指定版本并计算校验和
aws s3api get-object \
--bucket "$BUCKET" --key "$KEY" --version-id "$VERSION_ID" restored.txt
sha256sum restored.txt
恢复演练记录应包括:操作时间、操作者、源Version ID、目标位置、校验和、恢复耗时、权限异常和整改项。对于KMS加密对象,还要验证灾难场景下KMS Key、Key Policy和跨账号角色是否可用。
十、生产环境还需要的三项加固
1. 分离备份账号
把备份Bucket放在独立AWS账号,生产账号仅获得写入或复制所需的最小权限。这样即使生产账号的高权限凭证泄露,攻击者也不应直接控制备份保留策略。
2. 跨区域或跨账号复制
Object Lock可以与S3 Replication结合,复制锁定对象及其保留元数据。目标Bucket也必须启用Object Lock。复制是异步过程,应监控复制状态和失败事件,不能把"已配置规则"视为"所有对象已复制"。
3. 生命周期与成本测算
不可变版本会持续占用存储。为保留期结束后的历史版本设置Lifecycle前,先确认与Object Lock、MFA Delete和合规要求的交互。AWS官方明确指出MFA Delete不能与Lifecycle配置同时使用,因此不要把所有功能简单叠加。
十一、上线前检查清单
- 明确恢复点目标RPO、恢复时间目标RTO和保留期;
- 生产数据、备份数据和日志使用不同权限边界;
- 应用角色没有删除版本、修改保留期或绕过GOVERNANCE的权限;
- CloudTrail记录Object Lock、Versioning、Bucket Policy和删除操作;
- 定期抽样恢复,并验证Version ID、内容校验和和KMS解密;
- 先在测试Bucket验证COMPLIANCE保留期,再决定是否用于生产;
- 监控跨区域复制、存储增长和到期后清理结果。
结语
可靠备份不是"文件上传成功",而是攻击者拿到生产权限后仍难以删除历史版本,并且团队能在规定时间内恢复出可用数据。Versioning负责保留历史,Object Lock负责不可变窗口,权限隔离降低单账号失陷风险,恢复演练证明方案真正可用。
如需国际云服务器合规开户流程咨询、AWS存储与备份架构选型、部署和运维支持,可通过平台私信说明目标地区、数据规模、保留期、RPO和RTO。客户本人完成实名、验证码、支付和合同确认;本文不含返佣链接,不承诺固定费用或绝对安全。
官方资料
- S3 Object Lock工作原理:https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html
- 为新建或现有Bucket配置Object Lock:https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-configure.html
- Object Lock与复制等注意事项:https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-managing.html
- S3 Versioning:https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html
- MFA Delete限制:https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiFactorAuthenticationDelete.html