使用 CloudFront 从 S3 提供 SSE‑KMS 加密内容

发布: (2026年1月31日 GMT+8 08:18)
12 分钟阅读
原文: Dev.to

Source: Dev.to

(请提供您希望翻译的正文内容,我将为您翻译成简体中文,并保留原有的格式、代码块和链接。)

问题

您正在构建一个应用,用户会上传:

  • 个人头像
  • 发票
  • 收据
  • 文档
  • 私人附件

您需要一个同时满足以下两点的解决方案:

  1. 隐私 – 文件必须保持私密。
  2. 性能 – 文件必须在全球快速加载。
选项优点缺点
公共 S3 存储桶快速(适合 CDN)不安全
私有 S3 存储桶安全可能更慢,且不适合 CDN
私有 + 自己的密钥加密即使存储被泄露仍然安全需要额外设置

引入 SSE‑KMS。

理想的设置如下:

  • ✅ 私有 S3 存储桶
  • ✅ 使用 KMS(SSE‑KMS)进行静态加密
  • ✅ 通过 CloudFront 全球分发
  • ✅ 存储桶永不公开

架构概览

User ──► CloudFront (edge cache) ──► S3 (private, SSE‑KMS)

每项服务的作用

  • S3 – 大规模云“硬盘”。

    • Bucket = 容器(文件夹)
    • Object = 文件(图片、PDF、ZIP,…)
    • 可以设为公开,但我们将其设为私有,用于存放用户内容。
  • CloudFront – AWS CDN,拥有全球边缘节点。

    • 当请求到达(例如 https://d1234abcdef.cloudfront.net/images/photo.jpg)时:
      1. 检查边缘缓存。
      2. 若已缓存 → 立即返回。
      3. 若未缓存 → 从 S3 获取,缓存后再返回。
  • KMS(密钥管理服务) – 管理加密密钥。

    • 使用 SSE‑KMS 时,S3 会对对象进行加密存储。
    • 收到请求时,S3 在返回之前使用 KMS 密钥进行解密。
    • 好处:自动加密、通过 IAM 控制访问、完整审计日志(CloudTrail)。

服务端加密(SSE)类型

类型描述
SSE‑S3由 S3 管理密钥;每个对象拥有唯一密钥。
SSE‑KMS客户主密钥(CMK)存放在 AWS KMS 中——提供更高的控制和可见性。
SSE‑C客户自行提供密钥;您管理密钥,S3 仅负责加密对象。

传输中的数据加密(CloudFront)

  • 强制使用 HTTPS(将 HTTP 重定向到 HTTPS)。
  • 选择最低的 TLS 版本和密码套件。
  • 绑定自定义域名并关联 TLS 证书。

结论: 在生产环境中,SSE‑KMS + CloudFront 是最佳组合。

CloudFront 如何访问受私有、SSE‑KMS 保护的存储桶

两种方法:

  1. Origin Access Identity (OAI) – 一个拥有 S3 权限的特殊 CloudFront 用户。

    • 限制: OAI 仅支持 SSE‑S3,不支持 SSE‑KMS
  2. Origin Access Control (OAC) – 更新且推荐的方式。

    • 使用 SigV4 签名、IAM 风格的访问控制,以及更强的安全模型。

📌 如果您使用 SSE‑KMS + CloudFront,请使用 OAC。

您将构建的内容

在本指南结束时,您将拥有:

  • 一个 私有 S3 存储桶,其中的对象使用 SSE‑KMS 加密。
  • 一个 CloudFront 分配,可在全球安全地提供这些对象。

步骤指南

步骤 1 – 创建你的第一个 KMS 密钥

  1. 打开 AWS 控制台 → KMS
  2. 点击 Customer managed keysCreate key
  3. 密钥类型: 对称
    密钥用途: 加密和解密
  4. 别名: myapp-dev-s3-key
  5. 描述: “用于通过 CloudFront 提供的 S3 内容的 SSE‑KMS 密钥”
  6. 分配管理员(你的 IAM 用户/角色),并根据需要编辑密钥策略。
  7. 完成密钥创建。

该密钥将成为你存储的所有 S3 对象的“主密钥”。

步骤 2 – 创建私有 S3 存储桶

  1. 前往 S3Create bucket
  2. 存储桶名称: 例如 myapp-dev-private-assets-123456(必须全局唯一)。
  3. 选择与你的 KMS 密钥相同的区域
  4. 阻止所有公共访问: 开启,以防止意外泄露。
  5. (可选)启用版本控制 – 可防止意外删除。
  6. 默认加密:
    • 选择 SSE‑KMS
    • 粘贴你创建的 KMS 密钥的 ARNmyapp-dev-s3-key)。
    • 启用 Bucket Key 以降低 KMS 请求费用。

注意: 存储桶级别的加密仅对之后上传的对象生效。

步骤 3 – 为 CloudFront 提供访问存储桶的密钥(OAC)

  1. 打开 CloudFrontOrigin accessCreate origin access control
  2. 名称: myapp-dev-oac(或任意描述性名称)。
  3. 签名行为: SigV4
  4. 源类型: S3
  5. 访问权限: 只读(或根据需要)。
  6. 保存 OAC。

步骤 4 – 创建 CloudFront 分配

  1. 在 CloudFront 中点击 Create DistributionWeb
  2. 源设置:
    • 源域名: 选择你刚创建的私有 S3 存储桶。
    • Origin Access Control: 选择刚才创建的 OAC。
    • Origin request policy: 使用默认或创建一个转发必要头部的策略。
  3. 缓存行为设置:
    • Viewer Protocol Policy: Redirect HTTP to HTTPS
    • Allowed HTTP Methods: GET, HEAD, OPTIONS(如有需要可添加其他方法)。
    • Cache based on selected request headers: Whitelist 仅你应用需要的头部。
  4. 分配设置:
    • Price class: 根据目标地区选择。
    • Alternate domain names (CNAMEs): 如有自定义域名请添加。
    • SSL certificate: 为你的域名选择 Custom SSL(ACM 提供)。
  5. 点击 Create Distribution 并等待部署完成(通常几分钟)。

步骤 5 – 为 OAC 更新存储桶策略

将占位符替换为 OAC 的 IAM 主体 ARN(在 OAC 控制台可见),并相应修改存储桶名称。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontRead",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <OAC-ARN>"
      },
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::myapp-dev-private-assets-123456/*"
    }
  ]
}

保存策略。

步骤 6 – 测试端到端流程

  1. 向 S3 存储桶上传测试文件(例如 test.txt)。

  2. 验证对象的 Encryption 列显示 SSE‑KMS 且使用了正确的 KMS 密钥。

  3. 通过 CloudFront 域名访问该文件:

    curl -I https://d1234abcdef.cloudfront.net/test.txt
    • 请求应成功(HTTPS)。
    • CloudFront 会在边缘缓存对象,然后即时向后续用户提供。
  4. 检查 CloudTrail 中的解密事件——你应该能看到每次请求的 KMS 使用日志。

好处回顾

  • 存储桶始终保持私有 – 没有公共 ACL 或 “拥有链接的任何人” 访问。
  • 对象使用您的 KMS 密钥加密 – 完全控制和可审计性。
  • 通过 CloudTrail 完整的解密审计日志 → 更好的合规性。
  • CloudFront 边缘缓存 → 全球更快的下载和降低 S3 请求费用。

TL;DR

  • Private S3 bucket + SSE‑KMS = 您可控制的数据静止加密。
  • CloudFront OAC (SigV4) = 对该存储桶的安全、CDN 友好访问。
  • 结果:安全、快速、全球分发的内容交付,且永不公开您的存储桶。

步骤指南:使用 OAC 通过 CloudFront 提供 SSE‑KMS 加密的 S3 对象

步骤 1 – 创建源访问控制 (OAC)

  1. 导航: CloudFront → Origin Access Controls → Create OAC
  2. 填写:
字段
Namemyapp-dev-oac
Origin typeS3
Signing behaviorAlways sign requests
  1. 点击 Create
    此时 CloudFront 在从私有存储桶获取对象时即可进行身份验证。

步骤 2 – 创建 CloudFront 分配

  1. 导航: CloudFront → Distributions → Create distribution

  2. 配置源:

    • Origin domain: 选择您的 S3 存储桶

    • ⚠️ 关键: 使用 存储桶端点,例如

      myapp-dev-private-assets-123456.s3.eu-west-2.amazonaws.com

      不要使用网站端点(例如 s3-website.eu-west-2.amazonaws.com)。

    • Origin access: 选择您刚创建的 OAC(myapp‑dev-oac)。

  3. 配置缓存行为:

设置
Viewer protocol policyRedirect HTTP → HTTPS
Allowed methodsGET, HEAD, OPTIONS
Cache policyCachingOptimized
  1. 点击 Create

步骤 3 – 更新 S3 存储桶策略

  1. 在分配页面会看到蓝色横幅:“The S3 bucket policy needs to be updated.”
  2. 点击 Copy policy
  3. 前往 S3 → <your bucket> → Permissions → Bucket policy → Edit
  4. 粘贴复制的策略并 Save

示例存储桶策略(用您的实际值替换占位符):

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipalReadOnly",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::myapp-dev-private-assets-123456/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::123456785012:distribution/E2ABCDEFG12345"
        }
      }
    }
  ]
}

注意: AWS:SourceArn 在您保存后会自动填入分配的实际 ARN。

步骤 4 – 为 CloudFront 更新 KMS 密钥策略

由于对象是 SSE‑KMS 加密的,CloudFront 需要解密权限。

  1. 前往 KMS → Customer managed keys → <your key> → Key policy → Edit
  2. 添加以下语句(用您的实际值替换占位符):
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnableIAMUserPermissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<account-id>:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AllowCloudFrontDecryptThroughS3Only",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:DescribeKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::<account-id>:distribution/<distribution-id>",
          "kms:ViaService": "s3.eu-west-2.amazonaws.com"
        }
      }
    }
  ]
}
  • 替换
    • AWS:SourceArn → 您的分配 ARN。
    • kms:ViaService → 您的 S3 存储桶所在区域(例如 s3.eu-west-2.amazonaws.com)。

步骤 5 – 等待部署完成

  • CloudFront 传播时间:5–15 分钟
  • 分配状态变化:Deploying → Enabled
  • 策略更新后,需 2–3 分钟 进行传播。

可选: 创建缓存失效(/*)以立即进行测试。

步骤 6 – 测试全部功能

  1. 上传测试文件(例如 test.jpg)到 S3 存储桶。确认在 Properties → Server‑side encryption 中显示 SSE‑KMS 加密。

  2. 通过 CloudFront 进行测试(应成功):

curl -I https://d1234abcdef.cloudfront.net/test.jpg

预期: HTTP/2 200 OK

  1. 测试直接 S3 URL(应失败):
curl -I https://myapp-dev-private-assets-123456.s3.eu-west-2.amazonaws.com/test.jpg

预期: HTTP/1.1 403 Forbidden

结果: CloudFront 是唯一的公共访问点。

常见陷阱与解决方案

症状可能原因解决办法
403 AccessDenied from CloudFrontKMS 密钥策略中的 AWS:SourceArn 错误,存储桶策略不匹配,缺少 CloudFront 权限,传播延迟核实 ARN 值,确保引用了 OAC,等待策略传播
Files not encrypted在启用 SSE‑KMS 之前已上传的文件重新上传或在复制对象时启用 SSE‑KMS
Wrong S3 origin endpoint使用了网站端点而非存储桶端点使用存储桶端点(*.s3.<region>.amazonaws.com
CloudFront keeps serving old errors缓存的错误响应使缓存失效(/*

您现在拥有一个安全的、通过 CloudFront 前端的 S3 存储桶,对象已使用 SSE‑KMS 加密,仅可通过 CloudFront 分配访问。

Back to Blog

相关文章

阅读更多 »