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

Terraform配置S3 Bucket Policy遇MalformedPolicy资源无效错误

S3 Bucket Policy配置报错:MalformedPolicy: Policy has invalid resource

报错内容:

Error putting S3 policy: MalformedPolicy: Policy has invalid resource

涉及桶:s3_published_bucket、s3_raw_bucket、s3_processed_bucket


现有配置

IAM策略文档配置

data "aws_iam_policy_document" "s3_admin_access" {
  statement {
    sid    = "AllowGroupAAccess"
    effect = "Allow"
    actions = [
      "s3:GetObject",
      "s3:ListBucket"
    ]

    resources = local.s3_arn_etl_bucket_array

    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }

  statement {
    sid    = "DenyAllOtherUsers"
    effect = "Deny"
    actions = [
      "s3:*"
    ]

    resources = local.s3_arn_etl_bucket_array

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    condition {
      test     = "StringNotEquals"
      variable = "aws:PrincipalArn"
      values   = [""]
    }
  }
}

S3 Bucket Policy资源

resource "aws_s3_bucket_policy" "s3_admin_access" {
  for_each = data.terraform_remote_state.s3_buckets.outputs.map_s3_bucket_id
  bucket   = each.value
  policy   = data.aws_iam_policy_document.s3_admin_access.json
}

Locals配置

s3_buckets_arn       = data.terraform_remote_state.s3_buckets.outputs.map_s3_bucket_arn

s3_arn_etl_bucket_array = [for key, value in local.s3_buckets_arn : "${value}/*"]

Outputs配置

output "map_s3_bucket_arn" {
  value = {
    for k, v in module.s3_etl_module : k => v.bucket_arn
  }
}

output "map_s3_bucket_id" {
  value = {
    for k, v in module.s3_etl_module : k => v.bucket_id
  }
}

生成的资源值

data-s3-raw-bucket-source/*",
data-s3-published-bucket-source/*",
data-s3-processed-bucket-source/*",

问题根源

  1. 操作与资源不匹配

    • s3:ListBucket是桶级别操作,对应的资源必须是桶的完整ARN(如arn:aws:s3:::bucket-name),而非带/*的对象路径ARN。当前把ListBucket和GetObject(对象级别操作)放在同一个statement中,资源使用桶ARN/*,直接导致ListBucket的资源无效。
  2. Deny语句逻辑错误

    • Deny语句使用s3:*覆盖所有操作,但资源仅设置为桶ARN/*,桶级别操作(如ListBucket)无法作用于对象路径资源,导致资源无效。
    • Condition的values为空数组[""],会让Deny规则永远不生效(aws:PrincipalArn不可能为空字符串),逻辑完全失效。
  3. 单个Policy复用给多个桶

    • 用for_each为每个桶绑定同一个policy,但该policy包含所有桶的资源ARN。S3桶的Policy只能引用当前桶的资源,不能包含其他桶的ARN,这是触发MalformedPolicy的核心原因。

修复方案

1. 拆分操作与对应资源

将桶级别和对象级别操作拆分为独立statement,匹配正确的资源类型:

data "aws_iam_policy_document" "s3_admin_access" {
  # 允许桶级别List操作
  statement {
    sid    = "AllowListBucket"
    effect = "Allow"
    actions = ["s3:ListBucket"]
    resources = [for key, value in local.s3_buckets_arn : value]
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }

  # 允许对象级别Get操作
  statement {
    sid    = "AllowGetObject"
    effect = "Allow"
    actions = ["s3:GetObject"]
    resources = local.s3_arn_etl_bucket_array
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }

  # 修正Deny语句逻辑
  statement {
    sid    = "DenyAllOtherUsers"
    effect = "Deny"
    actions = ["s3:ListBucket", "s3:GetObject"]
    resources = concat(
      [for key, value in local.s3_buckets_arn : value],
      local.s3_arn_etl_bucket_array
    )
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    condition {
      test     = "StringNotEquals"
      variable = "aws:PrincipalArn"
      values   = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }
}

2. 为每个桶生成专属Policy

不能复用同一个Policy给多个桶,需为每个桶单独生成Policy文档:

# 为每个桶生成专属Policy文档
data "aws_iam_policy_document" "s3_admin_access" {
  for_each = local.s3_buckets_arn
  statement {
    sid    = "AllowListBucket"
    effect = "Allow"
    actions = ["s3:ListBucket"]
    resources = [each.value]
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }

  statement {
    sid    = "AllowGetObject"
    effect = "Allow"
    actions = ["s3:GetObject"]
    resources = ["${each.value}/*"]
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }

  statement {
    sid    = "DenyAllOtherUsers"
    effect = "Deny"
    actions = ["s3:ListBucket", "s3:GetObject"]
    resources = [each.value, "${each.value}/*"]
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    condition {
      test     = "StringNotEquals"
      variable = "aws:PrincipalArn"
      values   = ["arn:aws:iam::598889206234:user/tester123@tt.com"]
    }
  }
}

# 为每个桶绑定专属Policy
resource "aws_s3_bucket_policy" "s3_admin_access" {
  for_each = data.terraform_remote_state.s3_buckets.outputs.map_s3_bucket_id
  bucket   = each.value
  policy   = data.aws_iam_policy_document.s3_admin_access[each.key].json
}

3. 验证ARN格式

确保local.s3_buckets_arn中的值是完整的S3桶ARN(格式为arn:aws:s3:::bucket-name),而非仅桶名。当前生成的资源值显示为桶名而非ARN,需确认map_s3_bucket_arn输出的是正确格式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:25:34