You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform:能否创建附加策略的私有AWS S3存储桶?

问题根源

你遇到的报错核心原因是当前桶策略包含公共访问规则,而AWS S3的block_public_policy = true安全设置会直接拦截这类策略。你策略里的Principal = "*"意味着允许任何匿名用户访问桶内对象,属于典型的公共访问规则,触发了BlockPublicPolicy的拦截机制。

解决方案

你不需要手动添加策略,也无需关闭全部公共访问保护,只需根据实际需求调整策略或配置:

场景1:仅允许内部IAM实体访问(保持桶完全私有)

如果你的策略是给内部IAM用户/角色使用,把Principal替换为具体的IAM实体ARN(比如特定用户、角色或AWS账户ID),此时策略不属于公共访问范畴,BlockPublicPolicy不会拦截。

修正后的Terraform桶策略示例:

resource "aws_s3_bucket_policy" "web_object_bucket_policy" {
  bucket = aws_s3_bucket.web_object_bucket.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        # 替换为你的目标IAM实体ARN
        Principal = { AWS = "arn:aws:iam::122111111:user/YourSpecificUser" }
        Action = "s3:GetObject"
        Resource = "${aws_s3_bucket.web_object_bucket.arn}/*"
      }
    ]
  })

  depends_on = [aws_s3_bucket_public_access_block.web_object_bucket_public_access_block]
}

场景2:必须公开部分对象(安全实现方式)

如果确实需要让部分对象对外访问(比如静态网站),不要直接用Principal = "*",更安全的方案是使用CloudFront Origin Access Identity (OAI):

  1. 创建CloudFront OAI实体
  2. 给OAI授予访问S3桶的权限
  3. 桶保持完全私有(所有BlockPublic设置为true)
  4. 用户通过CloudFront访问对象,S3本身不直接对外开放

对应的Terraform代码片段示例:

# 创建CloudFront OAI
resource "aws_cloudfront_origin_access_identity" "s3_oai" {
  comment = "OAI for example bucket"
}

# 修正桶策略,仅允许OAI访问
resource "aws_s3_bucket_policy" "web_object_bucket_policy" {
  bucket = aws_s3_bucket.web_object_bucket.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = { AWS = aws_cloudfront_origin_access_identity.s3_oai.iam_arn }
        Action = "s3:GetObject"
        Resource = "${aws_s3_bucket.web_object_bucket.arn}/*"
      }
    ]
  })

  depends_on = [aws_s3_bucket_public_access_block.web_object_bucket_public_access_block]
}

# 创建CloudFront分发
resource "aws_cloudfront_distribution" "s3_distribution" {
  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  origin {
    domain_name = aws_s3_bucket.web_object_bucket.bucket_regional_domain_name
    origin_id   = "S3-${aws_s3_bucket.web_object_bucket.id}"

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.s3_oai.cloudfront_access_identity_path
    }
  }

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "S3-${aws_s3_bucket.web_object_bucket.id}"

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_100"

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

场景3:临时允许公共策略(不推荐)

如果一定要直接使用Principal = "*",可以临时将block_public_policy设为false,但必须同时保留另外三项公共访问保护:

  • block_public_acls = true
  • ignore_public_acls = true
  • restrict_public_buckets = true
    同时确保策略仅开放必要操作(比如仅允许GetObject到特定路径)。这种方式会降低安全性,仅建议在测试场景使用。
关键说明

block_public_policy = true阻止的是允许匿名/公共访问的桶策略,而非所有桶策略。只要你的策略仅针对特定IAM实体,就可以在保持全部公共访问保护的前提下成功添加。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:22:03