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/*",
问题根源
操作与资源不匹配
s3:ListBucket是桶级别操作,对应的资源必须是桶的完整ARN(如arn:aws:s3:::bucket-name),而非带/*的对象路径ARN。当前把ListBucket和GetObject(对象级别操作)放在同一个statement中,资源使用桶ARN/*,直接导致ListBucket的资源无效。
Deny语句逻辑错误
- Deny语句使用
s3:*覆盖所有操作,但资源仅设置为桶ARN/*,桶级别操作(如ListBucket)无法作用于对象路径资源,导致资源无效。 - Condition的
values为空数组[""],会让Deny规则永远不生效(aws:PrincipalArn不可能为空字符串),逻辑完全失效。
- Deny语句使用
单个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
相关产品推荐
相关产品推荐

