使用Terraform创建IAM策略遇格式错误,排查无果求助
解决Terraform创建IAM策略时的MalformedPolicyDocument错误
常见原因及排查步骤
策略JSON结构错误
多数情况是多个data "aws_iam_policy_document"合并时,Statement变成了二维数组,或者出现重复的顶层JSON键。比如直接把两个文档的statement字段放进一个数组,会生成[[...], [...]]这种无效结构——AWS要求Statement必须是一维对象数组。版本号冲突
所有参与合并的策略文档必须统一使用version = "2012-10-17",这是AWS唯一支持的现代策略版本号,混用旧版本会触发语法校验失败。字符串转义问题
如果手动拼接JSON字符串或使用变量注入,要检查变量值是否包含未转义的双引号、换行符等——这些字符会直接破坏JSON结构。比如变量值里的"bucket"会截断JSON,需要转义成\"bucket\"。Plan输出与实际提交的差异
Terraform Plan的输出可能未完全展示变量替换后的最终JSON,用以下命令获取实际要提交给AWS的完整策略:terraform show -json | jq '.values.root_module.resources[] | select(.address == "aws_iam_policy.foo_user_prod") | .values.policy'把输出复制到AWS IAM策略验证工具中,对比Plan里的内容,排查是否有差异。
正确的合并方式示例
下面是扩展PowerUserAccess策略的标准Terraform代码,可避免结构错误:
# 引用AWS托管的PowerUserAccess策略 data "aws_iam_policy" "poweruser" { arn = "arn:aws:iam::aws:policy/PowerUserAccess" } # 解析托管策略的Statement数组 data "aws_iam_policy_document" "poweruser_base" { version = "2012-10-17" statement = jsondecode(data.aws_iam_policy.poweruser.policy).Statement } # 自定义扩展权限 data "aws_iam_policy_document" "extra_perms" { version = "2012-10-17" statement { actions = ["s3:GetAccountPublicAccessBlock"] resources = ["*"] effect = "Allow" } } # 合并两个策略的Statement数组(关键:用concat生成一维数组) data "aws_iam_policy_document" "combined" { version = "2012-10-17" statement = concat( data.aws_iam_policy_document.poweruser_base.statement, data.aws_iam_policy_document.extra_perms.statement ) } # 创建最终的IAM策略 resource "aws_iam_policy" "foo_user_prod" { name = "foo_user_prod" description = "Extended PowerUserAccess with custom permissions" policy = data.aws_iam_policy_document.combined.json }
关键注意点
- 不要直接把多个
statement字段放进同一个数组,必须用concat()合并成一维数组 - 始终使用
2012-10-17作为策略版本号 - 避免手动拼接JSON字符串,尽量用Terraform的
aws_iam_policy_document数据源和concat生成合法结构
内容的提问来源于stack exchange,提问作者Josh Beauregard
相关产品推荐
相关产品推荐

