在 AWS 上使用 Terraform 构建安全的 Serverless 上传模式 🚀

发布: (2026年3月9日 GMT+8 01:09)
5 分钟阅读
原文: Dev.to

Source: Dev.to

(请提供您希望翻译的文章内容,我将为您翻译成简体中文。)

一个真实的案例(我一直在看到的)

几周前,我审查了一个系统,用户在该系统中上传文件(有些超过 300 MB)。
原始流程看起来“合理”:

  1. 前端将文件上传到后端
  2. 后端处理请求
  3. 后端将文件上传到 S3
  4. 后端响应

实际上,系统彻底失败

  • ❌ 超时

根本原因始终相同:在无服务器架构中,后端绝不应该处理文件上传

修复一切的模式

S3 预签名 URL

与其通过后端路由文件,不如让客户端直接使用 受控、临时且安全 的预签名 URL 上传到 S3。这正是许多生产级无服务器应用采用的模式。

什么是预签名 URL(通俗解释)?

预签名 URL 是一种有时间限制的签名请求,拥有该 URL 的任何人都可以执行特定的 S3 操作(例如 PutObject)。URL 过期后就失效,无法再使用。

Lambda:生成预签名 URL(Node.js)

// src/index.mjs
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({ region: "us-east-1" });

export const handler = async (event) => {
  const { fileName, contentType } = JSON.parse(event.body);

  const key = `uploads/${Date.now()}-${fileName}`;

  const command = new PutObjectCommand({
    Bucket: process.env.BUCKET_NAME,
    Key: key,
    ContentType: contentType,
  });

  const uploadUrl = await getSignedUrl(s3, command, {
    expiresIn: 300, // 5 minutes
  });

  return {
    statusCode: 200,
    body: JSON.stringify({ uploadUrl, key }),
  };
};

Security Layers (What Makes This Production‑Ready)

  1. Short‑lived URLs – 限制为几分钟。
  2. IAM Least‑Privilege – Lambda 角色只能 s3:PutObjectarn:aws:s3:::my-bucket/uploads/*
  3. Private S3 Bucket – 没有公共访问。
  4. Sanitized Object Names – 在服务器端生成,以避免路径遍历。
  5. Proper CORS Configuration – 仅允许预期的来源进行上传。

⚠️ Important: CORS 通常是导致上传失败的首要因素;确保在存储桶上正确配置它。

基础设施即代码(Infrastructure as Code)使用 Terraform

所有资源均在 Terraform 中定义。仓库结构如下:

aws-s3-presigned-url-lambda-terraform/
├── 01-s3.tf
├── 02-lambda.tf
├── 04-api.tf
├── client/
│   ├── index.html
│   ├── index.html.tpl
│   ├── logo-client.png
│   └── logo-s3.png
├── dev.tfvars
├── drawio/
│   ├── aws-s3-presignend.gif
│   ├── aws-s3-url.drawio
│   ├── image-2.png
│   └── image.png
├── lambda-function.zip
├── main.tf
├── Makefile
├── provider.tf
├── README.md
├── security/
│   ├── checkov.yaml
│   └── trivy.yaml
├── src/
│   ├── index.mjs
│   ├── node_modules/
│   ├── package-lock.json
│   └── package.json
├── terraform.tfstate
├── terraform.tfstate.backup
├── tfplan
├── tfplan.json
├── variables.tf
└── versions.tf

核心组件包括:

  • S3 存储桶,设置了受限访问和 CORS 配置。
  • Lambda 函数,用于生成预签名 URL。
  • API Gateway(或 HTTP API),向客户端公开 /presign 端点。

运行 PoC 的要求

  • macOS(或任何已安装 AWS CLI、Node.js 和 Terraform 的类 Unix 环境)。
  • 除了克隆仓库并运行 terraform apply 外,无需其他设置。

完整可运行的 PoC

完整实现可在以下地址获取:

https://github.com/francotel/aws-s3-presigned-url-lambda-terraform

克隆仓库,使用 Terraform 部署,即可拥有完整的无服务器上传流程。

最终思考

如果你的后端仍然处理文件上传,你会付出更高的成本且扩展效率更低。使用预签名 URL 将繁重的工作转移到 S3,降低后端负载,并遵循最佳实践的安全模式。

参考文献

  • AWS Blog: Securing Amazon S3 presigned URLs for serverless applications

文章讨论了最佳实践,例如校验和验证、过期策略以及最小权限的 IAM 策略。

0 浏览
Back to Blog

相关文章

阅读更多 »