Score:2

How do i fix terraform invalid JSON policy

cn flag

I am trying to use a file which contains load balancer iam policy for my AWS in terraform. However when i run the terraform script, i get an error stating:

 Error: "policy" contains an invalid JSON policy
│ 
│   with module.iam.aws_iam_policy.test-AWSLoadBalancerControllerIAMPolicy,
│   on ../resources/IAM/main.tf line 77, in resource "aws_iam_policy" "test-AWSLoadBalancerControllerIAMPolicy":
│   77:  policy = jsonencode(var.policy_file)

I am importing the content of the policy file with jsonencode function.

resource "aws_iam_policy" "test-AWSLoadBalancerControllerIAMPolicy" {
 name = var.aws_loadbalancer_controller_policy
 policy = jsonencode(var.policy_file)
}

the value of the iam_policy_file variable above is passed in like file("../resources/IAM/policy.json") and the content of that file is shown below, i have checked to see if this json file parses online as a valid json and it does, however Terraform throws the error as if there it is badly formatted.

policy.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAddresses",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeVpcs",
                "ec2:DescribeVpcPeeringConnections",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeInstances",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeTags",
                "ec2:GetCoipPoolUsage",
                "ec2:DescribeCoipPools",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeListenerCertificates",
                "elasticloadbalancing:DescribeSSLPolicies",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetGroupAttributes",
                "elasticloadbalancing:DescribeTargetHealth",
                "elasticloadbalancing:DescribeTags"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cognito-idp:DescribeUserPoolClient",
                "acm:ListCertificates",
                "acm:DescribeCertificate",
                "iam:ListServerCertificates",
                "iam:GetServerCertificate",
                "waf-regional:GetWebACL",
                "waf-regional:GetWebACLForResource",
                "waf-regional:AssociateWebACL",
                "waf-regional:DisassociateWebACL",
                "wafv2:GetWebACL",
                "wafv2:GetWebACLForResource",
                "wafv2:AssociateWebACL",
                "wafv2:DisassociateWebACL",
                "shield:GetSubscriptionState",
                "shield:DescribeProtection",
                "shield:CreateProtection",
                "shield:DeleteProtection"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateSecurityGroup"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": "arn:aws:ec2:*:*:security-group/*",
            "Condition": {
                "StringEquals": {
                    "ec2:CreateAction": "CreateSecurityGroup"
                },
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTags",
                "ec2:DeleteTags"
            ],
            "Resource": "arn:aws:ec2:*:*:security-group/*",
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "true",
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:DeleteSecurityGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:CreateTargetGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:CreateListener",
                "elasticloadbalancing:DeleteListener",
                "elasticloadbalancing:CreateRule",
                "elasticloadbalancing:DeleteRule"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:RemoveTags"
            ],
            "Resource": [
                "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*",
                "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*",
                "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
            ],
            "Condition": {
                "Null": {
                    "aws:RequestTag/elbv2.k8s.aws/cluster": "true",
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:RemoveTags"
            ],
            "Resource": [
                "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*",
                "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*",
                "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*",
                "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:ModifyLoadBalancerAttributes",
                "elasticloadbalancing:SetIpAddressType",
                "elasticloadbalancing:SetSecurityGroups",
                "elasticloadbalancing:SetSubnets",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:ModifyTargetGroup",
                "elasticloadbalancing:ModifyTargetGroupAttributes",
                "elasticloadbalancing:DeleteTargetGroup"
            ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:ResourceTag/elbv2.k8s.aws/cluster": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets"
            ],
            "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:SetWebAcl",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:AddListenerCertificates",
                "elasticloadbalancing:RemoveListenerCertificates",
                "elasticloadbalancing:ModifyRule"
            ],
            "Resource": "*"
        }
    ]
}

I downloaded this file from the AWS documentation here

I have also tried to make it work by reading in the file from an http response as shown below and i still get the same issue of Invalid JSON

data "http" "policy_json" {
  url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json"
}

resource "aws_iam_policy" "test-AWSLoadBalancerControllerIAMPolicy" {
  name = var.aws_loadbalancer_controller_policy
  policy = data.http.policy_json.request_body
}
in flag
surely not *request* body, you mean [`.response_body`](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http#response_body) right?
SYN avatar
hk flag
SYN
While in your initial attempt: `jsonencode(var.policy_file)`. I would assume the filename in itself isn't a valid json, should have tried to `data "local_file"` from that variable, then jsonencode the output of that data, as suggested by your error. Otherwise, @mdaniel suggestion might help as well
in flag
I specifically didn't dig into that part of the question, but AIUI `jsonencode(legal_json_str)` is going to emit _double encoded_ JSON, but the bogus http version was easy to spot. I've never gotten `terraform console` to do anything for me in order to quickly test that theory, though
Score:1
ph flag

You must make sure that you are assigning a string containing a JSON representation of an object.

It's hard to follow exactly how you have this set up from your description, but here are some potential problems you should check for:

  1. If var.policy_file contains a filename, then JSON encoding that filename will produce a JSON string containing the filename. For example, if var.policy_file is ../resources/IAM/policy.json then JSON encoding that will produce literally "../resources/IAM/policy.json", which is not a valid IAM policy.
  2. If var.policy_file contains the direct result of file("../resources/IAM/policy.json") then you are asking Terraform to create a JSON encoding of a string that already contains JSON content. For example, if your file contains {"Version": "2012-10-17"} then JSON encoding this will produce "{\"Version\": \"2012-10-17\"}" -- a JSON string which happens to contain more JSON, which is also not a valid IAM policy.

In both of the situations above you would not need to use jsonencode at all, because this file presumably already contains JSON content.

For case 1, you can say policy = file(var.policy_file) to directly assign the contents of the file.

For case 2, you can say policy = var.policy_file to directly assign the JSON string that's in that variable.

You only need to use jsonencode if you are intending to assign a Terraform object value that has not already been JSON encoded, like this:

policy = jsonencode({
  "Version" = "2012-10-17"
  # ...
})

In that case, jsonencode is needed to transform the non-string Terraform object value into a JSON string that the policy argument is expecting.

RicarHincapie avatar
mm flag
You're right. My original file is a .json, so I don't need to `jsonencode`
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.