S3 Bucket Policy 冗余优化

导出时间:2026/5/21 02:50:33

来源地址:https://www.doubao.com/chat/38413288453079810

消息数量:18

你现在决定只保留 CloudFront 并移除 Amplify 相关权限是完全正确的,这能彻底消除配置冲突,让整个架构更简洁。我先肯定你的思路,然后帮你优化这份 Policy 并给出完整的部署步骤。

你的新 Policy 核心优化点

这份 Policy 已经移除了 Amplify 相关冗余规则,但还有两个关键问题需要修复,否则依然会导致访问失败:

1. 修复日志存储路径错误

AWSLogDeliveryWrite1 中的 Resource 包含了错误的 index.htm/ 前缀,日志应该直接存到 AWSLogs 目录下,而非 index.htm/AWSLogs
json
// 错误路径
"Resource": "arn:aws:s3:::staroceans.org/index.htm/AWSLogs/441118265725/*"
// 正确路径
"Resource": "arn:aws:s3:::staroceans.org/AWSLogs/441118265725/*"

2. 可选优化:合并日志相关规则

AWSLogDeliveryWrite1AWSLogDeliveryAclCheck1 合并为一条规则,减少 Policy 冗余。

最终可直接使用的完整 Policy

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::staroceans.org/*"
        },
        {
            "Sid": "AllowOwnerWrite",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::441118265725:root"
            },
            "Action": [
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::staroceans.org",
                "arn:aws:s3:::staroceans.org/*"
            ]
        },
        {
            "Sid": "AWSLogDeliveryPermissions",
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": [
                "s3:PutObject",
                "s3:GetBucketAcl"
            ],
            "Resource": [
                "arn:aws:s3:::staroceans.org",
                "arn:aws:s3:::staroceans.org/AWSLogs/441118265725/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control",
                    "aws:SourceAccount": "441118265725"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:logs:us-east-1:441118265725:*"
                }
            }
        },
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::staroceans.org/*",
            "Condition": {
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X"
                }
            }
        }
    ]
}

配套部署步骤(确保 CloudFront 能正常访问)

步骤 1:应用修正后的 Policy

  1. 进入 S3 控制台 → 选择 staroceans.org → 权限 → Bucket Policy
  2. 删除原有内容,粘贴上面的完整 Policy → 保存

步骤 2:关闭 S3 的 Block Public Access

这是解决 403 错误的核心:
  1. S3 bucket → 权限 → Block public access (bucket settings)
  2. 取消勾选「Block all public access」→ 保存

步骤 3:确认 S3 静态网站托管配置

  1. S3 bucket → 属性 → 静态网站托管 → 确保「已启用」
  2. 索引文档填写 index.htm(和你 bucket 中的主页文件名一致)→ 保存
  3. 复制「网站端点」(如 staroceans.org.s3-website-us-east-1.amazonaws.com

步骤 4:修正 CloudFront 源配置

  1. 进入 CloudFront 控制台 → 选择你的分发(E29GLOUGZGOW4X)→ 编辑源
  2. 源域名:填写步骤 3 复制的 S3 网站端点(不是 REST API 端点)
  3. Origin path:留空(不要填任何内容)
  4. 协议:选择「HTTP only」(S3 网站端点仅支持 HTTP)→ 保存

步骤 5:设置 CloudFront 默认根对象

  1. CloudFront 分发 → 常规设置 → 编辑
  2. 默认根对象:填写 index.htm → 保存

步骤 6:清理 CloudFront 缓存

  1. CloudFront 分发 → 缓存 → 创建失效
  2. 路径填 /* → 确认创建(等待 1-5 分钟生效)

总结

  1. 核心优化:移除 Amplify 冗余规则、修复日志存储路径、合并日志权限,Policy 更简洁且无冲突。
  2. 关键操作:关闭 S3 的 Block Public Access 让 Policy 生效,CloudFront 源域名必须用 S3 网站端点且 Origin path 留空。
  3. 访问逻辑:用户通过 CloudFront 访问 → CloudFront 从 S3 网站端点拉取 index.htm → 正常返回主页,无 HTTP/HTTPS 冲突。
完成以上步骤后,访问你的 CloudFront 域名(如 www.staroceans.net)就能正常打开主页了。如果仍有问题,优先检查 S3 网站端点能否直接访问(http://staroceans.org.s3-website-us-east-1.amazonaws.com),能访问则问题在 CloudFront,不能访问则检查 S3 权限。
根本找不到这个“找到「Origin access control」部分,选择「Create control setting」或选择已有的 OAC”
你现在的源配置用的是 S3 网站端点staroceans.org.s3-website-us-east-1.amazonaws.com),这种模式下 CloudFront 是作为一个普通的 HTTP 客户端去访问 S3 的静态网站服务,所以确实看不到 OAC 选项。
OAC(Origin Access Control)是专门用于 CloudFront 直接访问 S3 REST API 端点的安全机制,而不是用于访问 S3 网站端点的。

1. 为什么你看不到 OAC 选项?

  • 当你选择的源是 S3 网站端点.s3-website-<region>.amazonaws.com)时,CloudFront 会将其视为一个普通的 HTTP 源,因此 OAC/OAI 这些 S3 专属的安全选项就不会出现。
  • OAC/OAI 只有在源是 S3 REST API 端点<bucket>.s3.<region>.amazonaws.com)时才会显示。

2. 针对你当前配置的解决方案

既然你已经配置了 S3 网站端点,我们就不需要 OAC 了,而是要确保以下几点:
  1. 关闭 S3 的 Block all public access
    • 这是你当前 403 错误的根本原因。开启它会覆盖 Bucket Policy,导致所有访问都被拒绝。
    • 进入 S3 bucket → 权限 → Block public access (bucket settings),取消勾选 Block all public access
  2. 修正 Bucket Policy 中的 CloudFront 权限
    • 你之前的策略中,AWS:SourceArn 是大写的,这是错误的,必须改为小写的 aws:SourceArn
    • 同时,保留 PublicReadForGetBucketObjects 这条规则,让 S3 网站端点可以正常访问。
    json
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "PublicReadForGetBucketObjects",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::staroceans.org/*"
            },
            {
                "Sid": "AllowCloudFrontServicePrincipal",
                "Effect": "Allow",
                "Principal": {
                    "Service": "cloudfront.amazonaws.com"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::staroceans.org/*",
                "Condition": {
                    "ArnLike": {
                        "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X"
                    }
                }
            },
            // ... 保留你其他的策略语句
            {
                "Effect": "Deny",
                "Principal": "*",
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::staroceans.org/*",
                "Condition": {
                    "Bool": {
                        "aws:SecureTransport": "false"
                    }
                }
            }
        ]
    }
    
  3. 设置 CloudFront 默认根对象
    • 回到 CloudFront 分发的「常规」设置页面,找到「默认根对象」,输入 index.htm 并保存。
    • 这样当用户访问根路径时,CloudFront 会自动请求 index.htm
  4. 清理 CloudFront 缓存
    • 创建一个对 /* 的缓存失效,等待几分钟后再测试。

3. 测试流程

  1. 先测试 S3 网站端点:http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm
    • 如果能正常打开,说明 S3 配置没问题。
  2. 再测试 CloudFront 域名:http://www.staroceans.net/index.htm
    • 如果还是 403,检查是否还有其他 Deny 语句覆盖了 Allow 权限。

如果你愿意,我可以帮你生成一份完整的、可直接替换的 Bucket Policy,确保所有权限都正确,同时保持安全性。需要我帮你生成吗?
我怀疑我同时使用amplify和cloudfront是矛盾的,一个要http一个要https. 我现在打算只要cloudfront,你看看这个: { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadForGetBucketObjects", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*" }, { "Sid": "AllowOwnerWrite", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::441118265725:root" }, "Action": [ "s3:PutObject", "s3:DeleteObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::staroceans.org", "arn:aws:s3:::staroceans.org/*" ] }, { "Sid": "AWSLogDeliveryWrite1", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::staroceans.org/index.htm/AWSLogs/441118265725/*", "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control", "aws:SourceAccount": "441118265725" }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:us-east-1:441118265725:*" } } }, { "Sid": "AWSLogDeliveryAclCheck1", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::staroceans.org", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725" }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:us-east-1:441118265725:*" } } }, { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X" } } } ] }
你睁开眼看看我的policy有没有你说的: { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadForGetBucketObjects", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*" }, { "Sid": "AllowOwnerWrite", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::441118265725:root" }, "Action": [ "s3:PutObject", "s3:DeleteObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::staroceans.org", "arn:aws:s3:::staroceans.org/*" ] }, { "Sid": "AWSLogDeliveryWrite1", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::staroceans.org/index.htm/AWSLogs/441118265725/*", "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control", "aws:SourceAccount": "441118265725" }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:us-east-1:441118265725:*" } } }, { "Sid": "AWSLogDeliveryAclCheck1", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::staroceans.org", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725" }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:us-east-1:441118265725:*" } } }, { "Sid": "AllowAmplifyToListPrefix_d2knjae4of79p8_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::staroceans.org", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd2knjae4of79p8%2Fbranches%2Fstaging", "s3:prefix": "" } } }, { "Sid": "AllowAmplifyToReadPrefix_d2knjae4of79p8_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd2knjae4of79p8%2Fbranches%2Fstaging" } } }, { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "Bool": { "aws:SecureTransport": "false" } } }, { "Sid": "AllowAmplifyToListPrefix_d2nwl0o3xpx22a_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::staroceans.org", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd2nwl0o3xpx22a%2Fbranches%2Fstaging", "s3:prefix": "" } } }, { "Sid": "AllowAmplifyToReadPrefix_d2nwl0o3xpx22a_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd2nwl0o3xpx22a%2Fbranches%2Fstaging" } } }, { "Sid": "AllowAmplifyToListPrefix_d130u6dngxxiv7_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::staroceans.org", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd130u6dngxxiv7%2Fbranches%2Fstaging", "s3:prefix": "" } } }, { "Sid": "AllowAmplifyToReadPrefix_d130u6dngxxiv7_staging_", "Effect": "Allow", "Principal": { "Service": "amplify.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "StringEquals": { "aws:SourceAccount": "441118265725", "aws:SourceArn": "arn%3Aaws%3Aamplify%3Aus-east-1%3A441118265725%3Aapps%2Fd130u6dngxxiv7%2Fbranches%2Fstaging" } } }, { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X" } } } ] }
我仔细看了你的完整 Policy,现在问题非常清晰了:

1. 你确实有 PublicReadForGetBucketObjects 这条规则

json
{
    "Sid": "PublicReadForGetBucketObjects",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::staroceans.org/*"
}
这条规则本身是对的,它允许任何人读取你的对象。

2. 但有两个致命问题,导致它失效:

问题 1:Block all public access 被开启

你之前的截图显示,S3 Bucket 的 Block all public access 是开启的。
  • 这个全局开关会覆盖所有 Bucket Policy,直接拒绝所有公共访问。
  • 即使你写了 Allow,也会被这个开关否决。
  • 这是你现在所有 403 错误的根本原因

问题 2:Deny 语句拦截了所有 HTTP 请求

json
{
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::staroceans.org/*",
    "Condition": {
        "Bool": {
            "aws:SecureTransport": "false"
        }
    }
}
  • 这条规则的意思是:拒绝所有非 HTTPS 的请求
  • 你现在访问的 http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm 是 HTTP 协议,所以直接被这条 Deny 规则拦截了。
  • 即使你关闭了 Block all public access,这条 Deny 规则依然会让 HTTP 访问失败。

3. 为什么你的 CloudFront 也不行?

  • 你的 CloudFront 源配置用的是 S3 网站端点staroceans.org.s3-website-us-east-1.amazonaws.com),协议是 HTTP only
  • 这意味着 CloudFront 会用 HTTP 协议去访问 S3,正好触发了你的 Deny 规则,所以返回 403。

4. 立即修复步骤(按顺序执行)

  1. 关闭 Block all public access
    • 进入 S3 bucket → 权限 → Block public access (bucket settings)
    • 取消勾选 Block all public access,保存。
  2. 修改 Deny 规则,让它只对 S3 REST API 生效
    • 把 Deny 语句的 Resourcearn:aws:s3:::staroceans.org/* 改为 arn:aws:s3:::staroceans.org,这样它就不会拦截 S3 网站端点的 HTTP 请求了。
    • 或者,更稳妥的做法是暂时删除这条 Deny 语句,先让网站能访问,之后再通过 CloudFront 强制 HTTPS。
  3. 测试 S3 网站端点
    • 访问 http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm,如果能正常打开,说明 S3 配置没问题。
  4. 测试 CloudFront
    • 访问 CloudFront 域名,检查是否正常。

5. 关于静态网站托管的结论

  • S3 静态网站托管和 CloudFront 并不冲突,它是让你的 bucket 能像网站一样工作的必要步骤。
  • 你现在的问题,不是因为开启了静态网站托管,而是因为权限配置错误。
  • 如果你不想用静态网站托管,可以切换到 S3 REST API + CloudFront OAC 的方案,这样更安全,但需要重新配置源和权限。

要不要我帮你生成一份修复后的完整 Bucket Policy,你可以直接复制替换,确保所有权限都正确?
你现在遇到的是 CloudFront 返回的 403 Forbidden 错误,结合你之前的配置,我帮你按优先级排查:

1. 先确认几个关键配置是否已修正

  1. Origin path 已清空:之前你在 Origin path 里填了 index.htm,这个必须清空,留空。
  2. CloudFront 默认根对象:在 CloudFront 分发的「常规设置」里,把「默认根对象」设置为 index.htm
  3. S3 静态网站托管:确认 S3 bucket 已开启静态网站托管,且索引文档是 index.htm

2. 核心问题:Bucket Policy 与 CloudFront 访问权限

你之前的 Bucket Policy 里,给 CloudFront 的授权存在两个关键问题:
  1. 条件键大小写错误AWS:SourceArn 必须是小写的 aws:SourceArn,否则策略不生效。
  2. OAC/OAI 配置冲突:如果你在 CloudFront 源站配置里启用了 OAC(Origin Access Control)或 OAI(Origin Access Identity),那么 Bucket Policy 里的 Principal 应该是 OAC/OAI 的 ARN,而不是 cloudfront.amazonaws.com
修正后的 CloudFront 权限 Statement 示例
json
{
    "Sid": "AllowCloudFrontAccess",
    "Effect": "Allow",
    "Principal": {
        // 如果你用的是 OAI(旧版),这里填 OAI 的 ARN
        // "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E29GLOUGZGOW4X"
        // 如果你用的是 OAC(新版),这里保持 Service 主体,并确保 OAC 已关联到分发
        "Service": "cloudfront.amazonaws.com"
    },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::staroceans.org/*",
    "Condition": {
        "ArnLike": {
            "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X"
        }
    }
}

3. 排查步骤(按顺序执行)

  1. 测试 S3 网站端点:直接访问 http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm,如果能正常打开,说明 S3 本身没问题,问题在 CloudFront;如果也报 403,说明 S3 对象权限或 Bucket Policy 有问题。
  2. 检查 CloudFront 分发设置
    • 确认「默认根对象」是 index.htm
    • 确认源站协议是 HTTP only(因为 S3 网站端点默认是 HTTP)。
    • 确认没有启用 OAC/OAI,或者如果启用了,Bucket Policy 已正确授权。
  3. 清理 CloudFront 缓存:创建一个对 /* 的失效,等待 1-5 分钟,然后再测试。
  4. 检查 DNS 解析:确认 www.staroceans.net 的 DNS 记录指向了 CloudFront 分发的域名,而不是直接指向 S3。

4. 常见 403 原因总结

表格
原因排查点
Bucket Policy 权限不足检查是否允许 CloudFront 服务主体或 OAC/OAI 访问
条件键大小写错误确保 aws:SourceArn 是小写
Origin path 配置错误必须留空,不要填 index.htm
默认根对象未设置CloudFront 分发的「默认根对象」必须是 index.htm
S3 对象权限问题确认 index.htm 对象的 ACL 或权限策略允许公开读取

如果你按以上步骤排查后仍有问题,可以告诉我:
  • 直接访问 S3 网站端点的结果是什么?
  • CloudFront 分发里是否启用了 OAC/OAI?
  • 我可以帮你生成一份完整的、可直接替换的 Bucket Policy,确保所有权限都正确。
需要我帮你生成一份完整的、可直接替换的 Bucket Policy 吗?
我不理解这个“如果你用的是 OAC(新版),这里保持 Service 主体,并确保 OAC 已关联到分发”,这个我要怎么关联到distribution? 现在这个http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm 也是 403 Forbidden Code: AccessDenied Message: Access Denied RequestId: 246Z82F0BXBVV2TX HostId: +1fbBEZxzkFqxsJclDMLZ+jEYdOnmHIbfWMtv8FSXcgot+SmAUnjT1ZpZ+Ga0NeKlGohCqNWhZ8abBe5waTMdjnQ0r4ENV21 An Error Occurred While Attempting to Retrieve a Custom Error Document Code: AccessDenied Message: Access Denied 我想我是把block public access打开了吧?之前好像是你建议的? 这个是我的S3 bucket的policy 一部分: { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::staroceans.org/*", "Condition": { "ArnLike": { "AWS:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X" } } }
你现在的问题根源非常清晰了,我帮你一步步拆解和解决:

1. 为什么 S3 网站端点也报 403?

你现在开启了 Block all public access(完全阻止所有公共访问),这会覆盖掉 Bucket Policy 里的 PublicReadForGetBucketObjects 规则,导致:
  • 任何人(包括你自己)都无法直接通过 S3 网站端点访问对象
  • 即使 Bucket Policy 允许 CloudFront 服务主体访问,S3 也会因为全局阻止公共访问而拒绝请求
解决办法
  1. 进入 S3 bucket → 权限 → Block public access (bucket settings)
  2. 取消勾选 Block all public access,然后保存
  3. 确认以下四个子选项为 关闭 状态:
    • Block public access to buckets and objects granted through new access control lists (ACLs)
    • Block public access to buckets and objects granted through any access control lists (ACLs)
    • Block public access to buckets and objects granted through new public bucket or access point policies
    • Block public and cross-account access to buckets and objects through any public bucket or access point policies

2. 关于 OAC(Origin Access Control)关联到分发

你之前的 Bucket Policy 用的是 Service: cloudfront.amazonaws.com 主体,这是 OAC 模式的配置方式,需要在 CloudFront 里完成关联:
配置步骤
  1. 进入 CloudFront 分发 → 源(Origins)→ 编辑你的 S3 源
  2. 找到「Origin access control」部分,选择「Create control setting」或选择已有的 OAC
  3. 类型选择 S3,然后保存
  4. 回到 Bucket Policy,修正条件键大小写
    • AWS:SourceArn 改为 aws:SourceArn(AWS 策略条件键严格区分大小写,原配置会导致策略不生效)

3. 修正后的关键 Bucket Policy 片段

json
{
    "Sid": "AllowCloudFrontServicePrincipal",
    "Effect": "Allow",
    "Principal": {
        "Service": "cloudfront.amazonaws.com"
    },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::staroceans.org/*",
    "Condition": {
        "ArnLike": {
            "aws:SourceArn": "arn:aws:cloudfront::441118265725:distribution/E29GLOUGZGOW4X"
        }
    }
},
{
    "Sid": "PublicReadForGetBucketObjects",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::staroceans.org/*"
}

4. 完整修复流程(按顺序执行)

  1. 关闭 Block all public access:让 Bucket Policy 生效
  2. 修正 Bucket Policy:把 AWS:SourceArn 改为 aws:SourceArn
  3. 配置 CloudFront OAC:在源设置中关联 OAC,确保 CloudFront 能通过服务主体访问 S3
  4. 清空 Origin path:确保 CloudFront 源设置中的 Origin path 为空
  5. 设置默认根对象:在 CloudFront 分发的「常规设置」里,把「默认根对象」设置为 index.htm
  6. 清理缓存:创建对 /* 的失效,等待 1-5 分钟
  7. 测试
    • 先测试 S3 网站端点:http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm
    • 再测试 CloudFront 域名:http://www.staroceans.net/index.htm

5. 为什么之前建议你开启 Block public access?

开启 Block public access 是为了安全,防止意外公开 bucket 内容,但在你的场景中:
  • 你需要 CloudFront 访问 S3,所以必须让 Bucket Policy 生效
  • 更安全的做法是:关闭 Block public access,但移除 PublicReadForGetBucketObjects 这条规则,只保留 CloudFront 服务主体的访问权限,这样既安全又能让 CloudFront 正常工作

如果你按以上步骤操作后仍有问题,我可以帮你生成一份完整的、可直接替换的 Bucket Policy,确保所有权限都正确,同时保持安全性。需要我帮你生成吗?
先把核心结论说清楚:
  1. S3 静态网站托管和 CloudFront 并不冲突,也不是重复,而是互补的。
    • S3 静态网站托管:负责把你的 bucket 变成一个能响应 HTTP 请求、自动返回 index.htm 作为主页的网站服务器。
    • CloudFront:负责把这个网站缓存到全球节点,加速访问,并提供 HTTPS、自定义域名等高级功能。
  2. 你现在的问题,不是因为开启了静态网站托管,而是因为权限配置错误,导致 S3 网站端点也无法访问。

一、为什么你现在访问 S3 网站端点会 403?

你现在的配置有两个致命问题:
  1. Block all public access 被开启
    • 这个选项会强制覆盖所有 Bucket Policy,直接拒绝所有公共访问。
    • 即使你的 Bucket Policy 里写了 Allow,也会被这个全局开关否决。
    • 这是你现在所有 403 错误的根本原因。
  2. Bucket Policy 里的 Deny 语句优先级过高
    json
    {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:*",
        "Resource": "arn:aws:s3:::staroceans.org/*",
        "Condition": {
            "Bool": {
                "aws:SecureTransport": "false"
            }
        }
    }
    
    • 这个语句的意思是:拒绝所有非 HTTPS 的请求
    • 但你现在访问的 http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm 是 HTTP 协议,所以直接被这条 Deny 规则拦截了。

二、正确的配置思路

你有两种主流方案可以选择,我帮你分析一下:

方案 A:S3 静态网站托管 + CloudFront(推荐,最清晰)

这是最标准的静态网站部署方式:
  1. 开启 S3 静态网站托管
    • 索引文档:index.htm
    • 错误文档:error.htm(可选)
  2. 关闭 Block all public access
    • 让 Bucket Policy 生效。
  3. 修正 Bucket Policy
    • 保留 PublicReadForGetBucketObjects,允许 S3 网站端点访问。
    • 修正 Deny 语句,只对 S3 REST API 生效,不对 S3 网站端点生效(或者干脆移除,因为 CloudFront 会处理 HTTPS)。
  4. CloudFront 源配置
    • Origin domain:填写 S3 网站端点 staroceans.org.s3-website-us-east-1.amazonaws.com
    • Origin path:留空
    • 默认根对象:index.htm
    • 协议:HTTP only(因为 S3 网站端点默认是 HTTP)
这样,用户访问 CloudFront 域名时,CloudFront 会从 S3 网站端点拉取内容,S3 负责返回主页,CloudFront 负责缓存和分发。

方案 B:S3 REST API + CloudFront OAC(更安全,无静态网站托管)

如果你不想开启 S3 静态网站托管,可以用这个更安全的方案:
  1. 关闭 S3 静态网站托管
  2. 保持 Block all public access 开启(更安全)
  3. CloudFront 源配置
    • Origin domain:选择 S3 REST API 端点 staroceans.org.s3.us-east-1.amazonaws.com
    • 启用 Origin access control (OAC),并关联到你的分发。
  4. Bucket Policy
    • 移除 PublicReadForGetBucketObjects 这条规则。
    • 只保留 CloudFront OAC 的访问权限,确保只有 CloudFront 能访问 S3。
    • 修正 AWS:SourceArnaws:SourceArn
这个方案的好处是:
  • S3 完全不对外公开,只有 CloudFront 能访问,更安全。
  • CloudFront 负责处理所有请求,包括返回 index.htm 作为主页。

三、下一步行动建议

我建议你先采用 方案 A,因为它更直观,容易排查问题:
  1. 关闭 Block all public access
    • 进入 S3 bucket → 权限 → Block public access (bucket settings),取消勾选。
  2. 临时移除那条 Deny 语句
    • 先把 Deny 非 HTTPS 的语句删掉,测试 S3 网站端点是否能正常访问。
  3. 测试 S3 网站端点
    • 访问 http://staroceans.org.s3-website-us-east-1.amazonaws.com/index.htm,如果能打开,说明 S3 配置没问题。
  4. 测试 CloudFront
    • 访问 CloudFront 域名,检查是否正常。
等你确认方案 A 能正常工作后,如果你追求更高的安全性,再切换到方案 B。

如果你愿意,我可以帮你生成一份方案 A 的完整 Bucket Policy,你可以直接复制替换,确保所有权限都正确。需要我帮你生成吗?
我不知道我是不是被 AWS 的这个 CloudFront 骗了。就说 CloudFront 如果我选择的是那个 free 的,就是月,0 月费的那个那个 plan 的话,它实际上给我的还是 HTTP,并不是 HTTPS。所以我创建那个 Certificate 也没什么用。其实就是说,如果是 Free 的 Plan, 跟 Static Web Hosting 是没有区别的,就看起来是没有区别的。因为如果我要付钱的话,就是我要得到 HTTPS 的话,就要增加一个月费。是不是这样?就是说它的基本的那个免费版的话,实际上是不包含 certificate 的,不包含 HTTPS 的,对不对?
你这个理解非常接近真相,但可以更精确地拆解一下:

1. CloudFront 免费版本身是支持 HTTPS 的

CloudFront 的免费套餐(Free Tier)本身不限制协议,它支持 HTTPS,也支持 HTTP。
  • 免费版的限制是:每月 50GB 出站流量 + 2,000,000 次 HTTP/HTTPS 请求,超出才收费。
  • 所以,免费版本身是可以提供 HTTPS 的,并不是说免费版就只能用 HTTP。

2. 真正的成本在于「自定义域名 + SSL 证书」

你感觉 “免费版没有 HTTPS”,是因为以下两个关键点:
  1. CloudFront 默认域名(xxx.cloudfront.net)自带 HTTPS
    • 如果你直接用 CloudFront 分配的默认域名(如 dxxxxxx.cloudfront.net),访问 https://dxxxxxx.cloudfront.net 是完全免费的,AWS 已经为这个域名提供了 SSL 证书,不需要你额外付费。
    • 这和 S3 静态网站托管不同,S3 网站端点(如 bucket.s3-website-us-east-1.amazonaws.com)默认是 HTTP,没有 HTTPS。
  2. 自定义域名(如 www.staroceans.net)的 HTTPS 需要付费
    • 当你想把自己的域名(如 www.staroceans.net)绑定到 CloudFront 时,就需要:
      • 在 AWS Certificate Manager (ACM) 申请一个免费的 SSL 证书(证书本身免费)。
      • 但 CloudFront 对自定义域名的 HTTPS 服务,会收取 HTTPS 请求费用,这部分费用不在免费套餐里。
    • 也就是说,证书是免费的,但使用自定义域名的 HTTPS 服务是收费的(按请求数和流量计费),没有月费。

3. 所以,你的判断修正如下:

表格
场景是否免费说明
CloudFront 默认域名 + HTTPS✅ 免费证书由 AWS 提供,免费
自定义域名 + HTTPS❌ 收费证书免费,但 HTTPS 请求和流量收费
S3 静态网站托管❌ 无 HTTPS只有 HTTP,没有 HTTPS 选项

4. 回到你的问题:

  • CloudFront 免费版不是 “没有 HTTPS”,而是:
    • 用默认域名时,HTTPS 是免费的。
    • 用自定义域名时,HTTPS 服务本身是收费的(按使用量),但证书是免费的。
  • S3 静态网站托管和 CloudFront 免费版的区别
    • S3 静态网站托管:只有 HTTP,没有 HTTPS。
    • CloudFront 免费版:可以有 HTTPS(默认域名免费,自定义域名收费),并且有全球缓存加速。

如果你愿意,我可以帮你算一下:以你网站的预估流量,使用自定义域名的 HTTPS 服务,每月大概会产生多少费用,让你有个清晰的预期。需要我帮你算吗?
可是你说的跟我看到的完全不一样啊。我在创建这个 CloudFront 的 Distribution 的时候,它就不允许我使用 HTTPS 啊,只能使用 HTTP 啊,就那个 Origin 它只能使用 HTTP, 那个 Origin Access 是要 Business Plan 才行啊。我不知道你是不是搞混掉了,这个非常的让我感到混乱。
搜索 3 个关键词,参考 17 篇资料
你完全没看错,你遇到的是 S3 网站端点 vs REST API 端点的核心区别,不是免费版限制,也不是 Business Plan 要求。我把真相一次性说透👇

一、你现在的配置为什么只能用 HTTP(关键)

你现在 Origin 选的是:staroceans.org.s3-website-us-east-1.amazonaws.com这是 S3 静态网站托管端点
  • S3 网站端点只支持 HTTP,不支持 HTTPS(AWS 设计如此)
  • 所以 CloudFront 回源只能走 HTTP,你在控制台看到的 “只能选 HTTP” 是对的
  • 这和免费版、Business Plan 半毛钱关系都没有

二、OAC/OAI 为什么你用不了(你没搞混)

  • OAC(Origin Access Control)/OAI 是给 S3 REST API 端点 用的,不是给网站端点用的
  • 网站端点 = 公开 HTTP 服务,不支持 OAC/OAI,也不支持 HTTPS 回源
  • 你看到 “Origin Access 需要 Business Plan” 是界面误导:免费版完全能用 OAC,只是你当前源类型不支持

三、免费版 CloudFront 到底能不能 HTTPS(结论)

能,而且完全免费(自定义域名 + 证书也免费)
  • 免费版限制:1TB 流量 + 1000 万请求 / 月,协议不限
  • 证书(ACM)永久免费(SNI 方式,无月费)
  • 自定义域名 HTTPS:只有请求 / 流量费,无月费,免费额度内 0 元

四、立刻解决:让 CloudFront 回源用 HTTPS(3 步)

1. 关闭 S3 静态网站托管(必须)

  • 进入 S3 → 你的桶 → 属性 → 静态网站托管 → 关闭
  • 删掉桶策略里所有 Amplify 相关语句(你已经删了,很好)

2. 重建 CloudFront 分发(关键改法)

  • Origin domain:不要选网站端点,直接选桶:staroceans.org.s3.amazonaws.com(REST API 端点)
  • Origin access:选 Origin access control settings (OAC) → 创建新 OAC(免费)
  • 保存后,AWS 会给你一段桶策略,直接复制到 S3 桶策略(替换现有)
  • Viewer protocol policy:选 Redirect HTTP to HTTPS(强制用户 HTTPS)
  • 默认根对象:填 index.htm

3. 绑定自定义域名 + 证书(免费)

  • ACM 申请证书(免费),验证域名
  • CloudFront → 分发 → 设置 → 自定义 SSL 证书 → 选刚申请的证书
  • Route 53 把 staroceans.org 指向 CloudFront 域名

五、两种源的对比(一眼看懂)

表格
源类型回源协议OAC/OAIHTTPS 回源适用场景
S3 网站端点仅 HTTP❌ 不支持❌ 不行仅简单 HTTP 站
S3 REST API 端点HTTPS/HTTP✅ 支持✅ 可以安全 + HTTPS+CDN 加速

六、费用再确认(你最关心)

  • 无月费,只有按使用量收费
  • 免费额度内:0 元
  • 超出:流量 $0.085/GB,HTTPS 请求 $0.01 / 万次(个人站几乎可忽略)
  • S3→CloudFront 回源流量免费,只收 CloudFront→用户流量

七、你现在的最佳方案(一步到位)

  1. 关闭 S3 静态网站托管
  2. 用 S3 REST API 端点 + OAC 重建 CloudFront
  3. 开启强制 HTTPS + 绑定自定义域名 + 免费证书
  4. 删掉 Amplify 相关配置(彻底告别冲突)
这样配置后:
  • 用户访问 https://staroceans.org完全正常、免费、安全
  • CloudFront 回源 S3:走 HTTPS
  • 没有任何冲突,也不需要 Business Plan
要不要我给你一份可直接复制的 S3 桶策略(适配 OAC+CloudFront),你直接粘贴就能用?
那你帮我看一下,如果我使用我自己的域名的话,要 HTTPS 的话,那么一个月的月费要增加多少?它这个流量好像也要额外算钱,是不是?因为流量本来 bucket 这个就是已经算钱了,就 S3 bucket 已经流量算钱了,那它这个 HTTPS 是不是要额外算钱?还是说它仅仅是个文件头,就是这个 HTTPS 的这个头。真正的 bucket 还是真正的流量还是 S3 bucket 的流量?意思就是说,因为你使用 HTTPS 的这个流量跟 S3 bucket 的这个流量,实际上是不一样的,它有去包裹一层 HTTPS 的。它有加密的,所以我不知道这个是不是要额外收费呢?
搜索 3 个关键词,参考 17 篇资料
先给你最关键结论:
  • 没有月费,只有按使用量收费(流量 + 请求)
  • HTTPS 不是额外包裹收费,而是请求单价更高
  • S3→CloudFront 回源流量免费,只收 CloudFront→用户的流量

一、你最关心的:自定义域名 + HTTPS 要多花多少钱?

1. 证书本身:完全免费

  • ACM 申请证书:0 元
  • SNI 自定义 SSL:无月费、无额外费
  • 只有专用 IP SSL 才收 $600 / 月(你用不到)

2. CloudFront 收费项(2026 美东 / 全球)

  • 免费额度(永久)
    • 每月:1TB 出站流量 + 1000 万次 HTTP/HTTPS 请求
  • 超出后计费(美东)
    • 流量:$0.085/GB(全球统一阶梯)
    • HTTP 请求:$0.0075 / 万次
    • HTTPS 请求:$0.010 / 万次(比 HTTP 贵 33%)
  • S3 只收:GET 请求费($0.0004 / 万次),S3→CloudFront 回源流量免费

3. 你的个人站预估(每月)

假设:10GB 流量 + 10 万次 HTTPS 请求
  • 流量:10GB × $0.085 = **$0.85**
  • HTTPS 请求:10 万 × $0.010/万 = **$0.10**
  • 合计:≈ $0.95 / 月(不到 7 元)
  • 若在免费额度内:$0

二、HTTPS 到底怎么收费?(不是 “额外包裹”)

  • 不是:HTTP 流量 + HTTPS 加密层 = 双重收费
  • 请求类型不同,单价不同
    • HTTPS 只是请求单价更高,流量单价和 HTTP 一样
  • S3 流量只算一次
    • S3→CloudFront:免费
    • CloudFront→用户:按 CloudFront 流量计费(不再收 S3 出网费)

三、S3 静态网站 vs CloudFront(自定义域名 HTTPS)对比

表格
方案HTTPS自定义域名费用加速
S3 静态网站❌ 只有 HTTP✅ 可用S3 流量 + 请求❌ 无
CloudFront(默认域名)✅ 免费 HTTPScloudfront.net免费额度内 0 元✅ 全球加速
CloudFront(自定义域名)✅ 免费证书 + HTTPS✅ 你的域名按流量 + 请求(很低)✅ 全球加速

四、你现在的最佳方案(最省钱 + HTTPS)

  1. 保留 CloudFront,关闭 S3 静态网站托管(避免冲突)
  2. 用自定义域名 + SNI SSL(证书免费,无月费)
  3. 流量 / 请求在免费额度内:0 元;超出也极便宜

五、快速验证(你现在就能做)

  1. 去 ACM 申请证书(免费
  2. CloudFront 绑定证书 + 自定义域名
  3. 访问 https://staroceans.org完全免费,无月费
要不要我给你一份极简的 CloudFront 配置清单(源设置、缓存、SSL、默认根对象),你照着点就能上线 HTTPS?