You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何配置Amazon S3仅允许单个HTTPS主机访问

当然可以实现!这种场景下,我们可以通过S3桶策略配合Nginx反向代理的配置,精准控制只有你的HTTPS代理主机能读取存储桶内容,同时完全不影响签名上传的需求。下面是一步步的具体方案:

一、S3存储桶策略配置

我们需要通过桶策略实现两个核心规则:

  1. 仅允许Nginx代理服务器的公网IP执行读取操作
  2. 仅允许带有效签名的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(桶策略已经强制这一点)
四、验证配置

完成后可以通过以下方式测试:

  1. 用非Nginx IP的机器直接访问S3对象URL,应该返回AccessDenied错误
  2. 通过你的代理域名访问对象,应该能正常加载
  3. 使用预签名URL上传文件,应该能成功写入桶内

内容的提问来源于stack exchange,提问作者porton

火山引擎 最新活动