2

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
}
3
  • 1
    surely not request body, you mean .response_body right?
    – mdaniel
    Oct 26, 2022 at 15:38
  • 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
    – SYN
    Oct 26, 2022 at 16:22
  • 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
    – mdaniel
    Oct 26, 2022 at 20:51

1 Answer 1

2

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.

1
  • You're right. My original file is a .json, so I don't need to jsonencode Feb 23, 2023 at 18:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .