Terraform创建AWS IAM角色策略出现MalformedPolicyDocument错误求助
问题根因分析
- 你遇到的
MalformedPolicyDocument: The policy failed legacy parsing报错并不是原生JSON格式有问题,而是AWS IAM的legacy解析器对策略动态插值后的内容校验不通过,核心触发点有两个:
- 你当前手写heredoc内嵌插值变量的方式,插值后如果变量返回值包含特殊字符、或者索引越界返回空值,会直接导致策略结构异常,普通JSON校验工具只能校验静态文本,无法检测插值后的实际输出
- IAM legacy解析器对单元素数组的兼容性较差,你代码中第一句Statement的
"Resource": ["*"]是单元素数组,legacy解析器大概率无法识别,要求改为字符串格式"Resource": "*"
修复方案
临时修复(直接改现有代码)
修改两处内容即可:
- 把第一句Statement的单元素Resource数组改为字符串
- 确认
aws_subnet.private.*.id的返回值最少有2个,避免element取索引1时报空值
修改后的代码如下:
policy = <<POLICY { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": "*", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] }, { "Effect": "Allow", "Action": [ "ec2:CreateNetworkInterface", "ec2:DescribeDhcpOptions", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcs" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:CreateNetworkInterfacePermission" ], "Resource": [ "arn:aws:ec2:${var.REGION}:network-interface/*" ], "Condition": { "StringEquals": { "ec2:Subnet": [ "${element(aws_subnet.private.*.id, 0)}", "${element(aws_subnet.private.*.id, 1)}" ], "ec2:AuthorizedService": "codebuild.amazonaws.com" } } }, { "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "${aws_s3_bucket.codebuild.arn}", "${aws_s3_bucket.codebuild.arn}/*" ] } ] } POLICY
最优修复(推荐)
使用Terraform官方提供的aws_iam_policy_document数据源生成策略,自动处理JSON转义和语法兼容性,完全规避legacy解析错误,示例代码如下:
data "aws_iam_policy_document" "codebuild_policy" { statement { effect = "Allow" actions = [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] resources = ["*"] } statement { effect = "Allow" actions = [ "ec2:CreateNetworkInterface", "ec2:DescribeDhcpOptions", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcs" ] resources = ["*"] } statement { effect = "Allow" actions = ["ec2:CreateNetworkInterfacePermission"] resources = ["arn:aws:ec2:${var.REGION}:network-interface/*"] condition { test = "StringEquals" variable = "ec2:Subnet" values = aws_subnet.private.*.id } condition { test = "StringEquals" variable = "ec2:AuthorizedService" values = ["codebuild.amazonaws.com"] } } statement { effect = "Allow" actions = ["s3:*"] resources = [ aws_s3_bucket.codebuild.arn, "${aws_s3_bucket.codebuild.arn}/*" ] } } # 引用生成的策略 policy = data.aws_iam_policy_document.codebuild_policy.json
验证方法
修改完成后执行terraform plan,查看输出的policy字段是否符合预期,确认没有空值或者格式错误后再执行terraform apply。
内容的提问来源于stack exchange,提问作者Pedro Guilherme
相关产品推荐
相关产品推荐

