Claude Code × AWS S3 入门: 用最小权限实现 sync、图片上传、备份和预签名 URL
面向初学者的 Claude Code 与 AWS S3 实战: IAM 最小权限、aws s3 sync、静态站点、图片上传、备份与预签名 URL。
S3 看起来只是对象存储,但真正放进业务系统时,它会同时涉及权限、公开范围、同步、缓存、删除和费用。Claude Code 很适合帮你生成脚本和 TypeScript helper,不过如果提示词太宽,它也很容易给出过大的 IAM policy。
这篇文章面向第一次把 S3 用到生产环境附近的读者。目标不是炫技,而是让静态站点、图片上传、备份和预签名 URL 都能安全落地。最重要的原则是 least privilege,也就是每个脚本只拿到自己需要的 action 和 prefix。
本文的命令和设计优先参考官方文档: AWS CLI S3 reference, aws s3 sync reference, Boto3 presigned URL guide, Claude Code common workflows.
如果需要补背景,可以先看站内相关文章: IAM, security, context.
先把 S3 的用途拆开
use case 1 是静态站点。dist 同步到 site/,由 CloudFront 对外提供缓存。use case 2 是图片管理。管理后台上传到 uploads/ 或 assets/images/,页面只读取公开图片。use case 3 是备份。数据库 dump、导出文件、账单 PDF 按日期 prefix 保存,并且不应该使用 —delete。use case 4 是私有下载。bucket 保持 private,应用只返回短时有效的预签名 URL。
把这些用途混在一起时,人就会想给 s3:*。正确做法是先设计 prefix,例如 site/、assets/images/、uploads/、backups/、assets/private-reports/。然后再让 Claude Code 生成代码和 policy。这样 AI 的输出会更具体,也更容易 review。
身份确认与 IAM 最小权限
先把 bucket 与 region 放进变量,人工和 Claude Code 都更容易确认目标。
export AWS_REGION=ap-northeast-1
export S3_BUCKET=claudecode-lab-assets-prod
aws sts get-caller-identity
aws s3 ls "s3://${S3_BUCKET}/" --region "${AWS_REGION}"
这份策略只读取 assets、只写入 uploads,并避免授予宽泛删除权限。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadPublicAssetsOnly",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::claudecode-lab-assets-prod/assets/*"
},
{
"Sid": "WriteUploadsOnly",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:AbortMultipartUpload"],
"Resource": "arn:aws:s3:::claudecode-lab-assets-prod/uploads/*"
},
{
"Sid": "ListLimitedPrefixes",
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::claudecode-lab-assets-prod",
"Condition": {
"StringLike": {
"s3:prefix": ["assets/*", "uploads/*", "backups/*"]
}
}
}
]
}
这是同步静态站点或图片目录的基本形态。第一次一定先用 dryrun。
# 1. Preview changes first. This should become a habit.
aws s3 sync ./dist "s3://${S3_BUCKET}/site/" \
--region "${AWS_REGION}" \
--delete \
--cache-control "public,max-age=300" \
--dryrun
# 2. Deploy only after the preview looks right.
aws s3 sync ./dist "s3://${S3_BUCKET}/site/" \
--region "${AWS_REGION}" \
--delete \
--cache-control "public,max-age=300"
# 3. Upload long-lived images with a different cache policy.
aws s3 sync ./public/images "s3://${S3_BUCKET}/assets/images/" \
--region "${AWS_REGION}" \
--exclude "*.psd" \
--cache-control "public,max-age=31536000,immutable"
预签名 URL 可以让 bucket 保持私有,同时短时间允许下载。
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const s3 = new S3Client({ region: process.env.AWS_REGION ?? "ap-northeast-1" });
export async function createDownloadUrl(key: string, filename: string) {
if (!key.startsWith("assets/private-reports/")) {
throw new Error(`Unexpected S3 key prefix: ${key}`);
}
const command = new GetObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
ResponseContentDisposition: `attachment; filename="${filename}"`,
});
return getSignedUrl(s3, command, { expiresIn: 900 });
}
给 Claude Code 的请求要同时写清用途、禁止事项和确认命令。
このリポジトリに AWS S3 連携を追加してください。
目的: public/images を S3 の assets/images/ に同期し、private-reports/ のPDFだけ署名付きURLで配布する。
制約: バケット全体公開は禁止。s3:DeleteObject は付けない。aws s3 sync は必ず --dryrun を先に出す。
成果物: scripts/s3-sync-assets.mjs、lib/s3-presigned-url.ts、READMEの手順、確認コマンド。
確認: npm test、aws s3 ls、aws s3 sync --dryrun の出力で説明してください。
参照: AWS CLI s3/sync docs と Anthropic Claude Code common workflows。
这份 policy 故意很窄。GetObject 只给 assets,PutObject 只给 uploads,ListBucket 还限制了 prefix。初学者最容易出错的是把 ListBucket 写到对象 ARN 上,或者为了省事给整个 bucket s3:*。这两个都应该在 review 时挡下来。
另一个 pitfall 是删除权限。很多场景并不需要 DeleteObject。即使需要,也建议独立角色或独立脚本,并要求 dryrun、确认数量和人工确认。Claude Code 可以写 JSON,但最终是否过宽,必须由人检查。
安全使用 aws s3 sync
aws s3 sync 非常方便,也非常危险。它会比较本地目录和 S3 prefix;加上 —delete 后,会删除远端多余文件。静态站点部署可以用这个行为,但备份和共享图片目录绝对不能随便用。
# Backup use case: append-only, no --delete.
BACKUP_DATE=$(date +%Y-%m-%d)
aws s3 sync ./backups "s3://${S3_BUCKET}/backups/${BACKUP_DATE}/" \
--region "${AWS_REGION}" \
--storage-class STANDARD_IA \
--exclude "*.tmp"
aws s3 ls "s3://${S3_BUCKET}/backups/${BACKUP_DATE}/" --recursive --summarize
我的固定做法是先 dryrun,再真正执行。让 Claude Code 生成脚本时,要要求它打印 bucket、region、prefix 和 dryrun diff。删除数量超过阈值就停止。这不是复杂架构,但能防止路径写错后清空生产文件。
预签名 URL 是临时许可,不是公开 bucket
presigned URL 的价值在于,bucket 仍然 private,但通过短时 URL 允许下载或上传。比如报价 PDF、课程资料、用户报告,都可以先鉴权,再生成 15 分钟有效的 URL。
实现时要注意三点: expiresIn 的单位是秒,key prefix 必须检查,浏览器传来的文件名不要直接当作 S3 key。建议在服务器生成 uploads/yyyy/mm/dd/uuid.ext 这样的 key。长时间有效的 URL 是常见 failure,测试方便但生产风险高。
费用、缓存与公开范围的陷阱
S3 的成本不仅是存储。请求次数、数据传输、CloudFront、版本控制、生命周期规则都会影响账单。公开资源建议通过 CloudFront,并给图片设置合理 cache-control。私有文件不要为了省事打开 bucket public access。
DRYRUN_OUTPUT=$(aws s3 sync ./dist "s3://${S3_BUCKET}/site/" --delete --dryrun)
echo "$DRYRUN_OUTPUT"
DELETE_COUNT=$(echo "$DRYRUN_OUTPUT" | grep -c "delete:" || true)
if [ "$DELETE_COUNT" -gt 20 ]; then
echo "Too many deletes: ${DELETE_COUNT}. Stop and review."
exit 1
fi
另一个 pitfall 是照着老教程直接启用 S3 static website hosting 并公开 bucket。现在很多场景更适合 private S3 + CloudFront。尤其是未来要过安全审查或接企业客户时,private by default 的说明更容易让人放心。
Claude Code 做什么,人类 review 什么
Claude Code 适合生成 sync 脚本、presigned URL helper、README、测试和错误消息。人类必须 review AWS account、bucket 名、prefix、DeleteObject、public access、CloudFront 访问方式。执行前用 aws sts get-caller-identity 和 aws s3 ls 确认目标账号。
Masa 的验证 memo: prefix 分离是最有价值的改动。site、assets、uploads、backups、private-reports 分开后,IAM review 和 Claude Code 的提示词都变简单了。让 Claude Code 同时写 verification steps,也比只写代码更可靠。
总结
Claude Code × AWS S3 的重点不是“能上传”,而是“不会误公开、不会误删、不会给过大权限”。先拆 use case,再设计 prefix,sync 永远先 dryrun,presigned URL 默认短期限,公开资源走 CloudFront。
如果想把这套方式应用到真实项目,可以从 training / consultation.
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code 免费 PDF 漏斗清单:把文章流量变成注册和商品点击
用 Claude Code 检查文章如何引导读者到免费 PDF、Gumroad 教材和咨询入口。
从Obsidian到CLAUDE.md的Claude Code流程:不再反复解释上下文
把 Obsidian 工作笔记整理成 CLAUDE.md 运行说明,让 Claude Code 每次都带着正确上下文开始。
Claude Code 收入 CTA 路由:从文章分流到 PDF、Gumroad 与咨询
用 Claude Code 按读者意图把文章流量分到免费 PDF、Gumroad 教材或咨询入口。