如何配置Amazon S3仅允许单个HTTPS主机访问
当然可以实现!这种场景下,我们可以通过S3桶策略配合Nginx反向代理的配置,精准控制只有你的HTTPS代理主机能读取存储桶内容,同时完全不影响签名上传的需求。下面是一步步的具体方案:
一、S3存储桶策略配置
我们需要通过桶策略实现两个核心规则:
- 仅允许Nginx代理服务器的公网IP执行读取操作
- 仅允许带有效签名的HTTPS请求执行上传操作
将以下JSON替换为你的实际信息后,直接粘贴到S3桶的「权限」→「桶策略」中:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowReadFromNginxProxy", "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::your-bucket-name", "arn:aws:s3:::your-bucket-name/*" ], "Condition": { "IpAddress": { "aws:SourceIp": "1.2.3.4/32" // 替换成你的Nginx服务器公网IP } } }, { "Sid": "AllowSignedUploads", "Effect": "Allow", "Principal": "*", "Action": [ "s3:PutObject", "s3:PutObjectAcl" ], "Resource": "arn:aws:s3:::your-bucket-name/*", "Condition": { "Bool": { "aws:SecureTransport": "true" // 强制HTTPS上传 }, "StringNotEquals": { "aws:SignatureVersion": "None" // 拒绝无签名的上传请求 } } }, { "Sid": "DenyAllOtherRequests", "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::your-bucket-name", "arn:aws:s3:::your-bucket-name/*" ], "Condition": { "NotIpAddress": { "aws:SourceIp": "1.2.3.4/32" } } } ] }
策略说明:
- 第一条规则:仅放行来自Nginx IP的读取/列桶请求,确保只有代理能获取桶内内容
- 第二条规则:允许任何带有效签名的HTTPS上传请求(预签名URL、IAM凭证签名都适用),同时拦截无签名的公开上传
- 第三条规则:兜底拒绝所有不符合上述条件的请求,彻底锁死未授权访问
二、Nginx反向代理配置
接下来配置Nginx作为HTTPS代理,转发客户端请求到S3,同时隐藏S3的原始信息:
server { listen 443 ssl; server_name your-proxy-domain.com; // 替换成你的代理域名 # 配置HTTPS证书(用Let's Encrypt或自有证书均可) ssl_certificate /path/to/your/fullchain.crt; ssl_certificate_key /path/to/your/private.key; location / { # 转发请求到S3桶的Endpoint(非默认区域需替换为对应区域域名,比如s3-us-west-2.amazonaws.com) proxy_pass https://your-bucket-name.s3.amazonaws.com; # 必须设置Host头,否则S3无法识别请求目标 proxy_set_header Host your-bucket-name.s3.amazonaws.com; # 传递客户端真实IP(可选,但便于日志排查) proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 隐藏S3暴露的敏感响应头,避免泄露桶信息 proxy_hide_header x-amz-id-2; proxy_hide_header x-amz-request-id; proxy_hide_header Set-Cookie; # 可选:配置缓存提升读取性能 proxy_cache_valid 200 302 1h; proxy_cache_valid 404 1m; } } # 强制HTTP跳转HTTPS,确保所有请求都是加密的 server { listen 80; server_name your-proxy-domain.com; return 301 https://$server_name$request_uri; }
三、签名上传的注意事项
因为桶名会公开,为了保障上传安全:
- 生成预签名URL时,使用仅拥有
s3:PutObject权限的IAM用户/角色,遵循最小权限原则 - 设置合理的预签名URL过期时间(比如15分钟),避免URL被滥用
- 确保上传请求始终使用HTTPS(桶策略已经强制这一点)
四、验证配置
完成后可以通过以下方式测试:
- 用非Nginx IP的机器直接访问S3对象URL,应该返回
AccessDenied错误 - 通过你的代理域名访问对象,应该能正常加载
- 使用预签名URL上传文件,应该能成功写入桶内
内容的提问来源于stack exchange,提问作者porton




