Search code examples
jsonamazon-web-servicesterraformterraform-provider-aws

Policy JSON gets lost (MalformedPolicyDocument: Policy statement must contain resources)


My Goal

I am trying to download a specific version (later itll be the latest version) of a IAM Policy for AWS-Load-Balancer-Controller at runtime in Terraform. Then use that downloaded JSON policy as a source document for my final policy document, that includes some constraints for security purposes.

What should be happening

  1. The policy should be downloaded by my data.http.policy object
  2. The final policy doc should reference the data.http.policy.response_body as a source doc, and add some additional details. (Some conditions for security)
  3. The IAM Policy Resource should reference the data.aws_iam_policy_document.aws_load_balancer_controller for the Policy JSON

Error

creating IAM Policy aws-load-balancer-controller: MalformedPolicyDocument: Policy statement must contain resources.
Somehow, somewhere the value I generated is getting lost... Any thoughts or ideas would be appreciated here.

locals {
  policy = data.aws_partition.current.partition == "aws-us-gov" ? "iam_policy_us-gov" : "iam_policy"
  version = "2.5.1"
}

data "http" "policy" {
  url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v${local.version}/docs/install/${local.policy}.json"
}

# What can this do?
data "aws_iam_policy_document" "aws_load_balancer_controller" {
  source_policy_documents = [data.http.policy.response_body]

  statement {
    effect = "Allow"
    actions = [
      "ec2:AuthorizeSecurityGroupIngress",
      "ec2:RevokeSecurityGroupIngress"
    ]

    condition {
      test     = "ArnEquals"
      variable = "ec2:Vpc"
      values   = ["arn:${data.aws_partition.current.partition}:ec2:${var.region}:${data.aws_caller_identity.me.id}:vpc/${var.vpc_id}"]
    }

    condition {
      test     = "Null"
      variable = "aws:ResourceTag/kubernetes.io/cluster/${var.cluster}"
      values   = ["false"]
    }
  }
  depends_on = [
    data.http.policy
  ]
}

# Make the "Permissions" into a Policy
resource "aws_iam_policy" "aws_load_balancer_controller" {
  count = var.chart.name == "aws-load-balancer-controller" ? 1 : 0

  name        = var.chart.name
  path        = "/"
  description = "Policy for enabling access by ${var.chart.name}"

  policy = data.aws_iam_policy_document.aws_load_balancer_controller.json

  depends_on = [
    data.aws_iam_policy_document.aws_load_balancer_controller
  ]
}

Solution (Credit to @luk2302)

locals {
  policy = data.aws_partition.current.partition == "aws-us-gov" ? "iam_policy_us-gov" : "iam_policy"
  version = "2.5.1"
}

data "http" "policy" {
  url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v${local.version}/docs/install/${local.policy}.json"
}

# What can this do?
data "aws_iam_policy_document" "aws_load_balancer_controller" {
  source_policy_documents = [data.http.policy.response_body]

  statement {
    effect = "Allow"
    actions = [
      "ec2:AuthorizeSecurityGroupIngress",
      "ec2:RevokeSecurityGroupIngress"
    ]
    resources = ["*"]


    condition {
      test     = "ArnEquals"
      variable = "ec2:Vpc"
      values   = ["arn:${data.aws_partition.current.partition}:ec2:${var.region}:${data.aws_caller_identity.me.id}:vpc/${var.vpc_id}"]
    }

    condition {
      test     = "Null"
      variable = "aws:ResourceTag/kubernetes.io/cluster/${var.cluster}"
      values   = ["false"]
    }
  }
  depends_on = [
    data.http.policy
  ]
}

# Make the "Permissions" into a Policy
resource "aws_iam_policy" "aws_load_balancer_controller" {
  count = var.chart.name == "aws-load-balancer-controller" ? 1 : 0

  name        = var.chart.name
  path        = "/"
  description = "Policy for enabling access by ${var.chart.name}"

  policy = data.aws_iam_policy_document.aws_load_balancer_controller.json

  depends_on = [
    data.aws_iam_policy_document.aws_load_balancer_controller
  ]
}

Solution

  • Credit to @luk2302

    This was a very simple error, I was just an idiot this morning :face-palm:
    The aws_iam_policy_document just needed some resources in the statement, so I added resources = ["*"], and it works now.

    data "aws_iam_policy_document" "aws_load_balancer_controller" {
      source_policy_documents = [data.http.policy.response_body]
    
      statement {
        effect = "Allow"
        actions = [
          "ec2:AuthorizeSecurityGroupIngress",
          "ec2:RevokeSecurityGroupIngress"
        ]
        resources = ["*"]
    
    
        condition {
          test     = "ArnEquals"
          variable = "ec2:Vpc"
          values   = ["arn:${data.aws_partition.current.partition}:ec2:${var.region}:${data.aws_caller_identity.me.id}:vpc/${var.vpc_id}"]
        }
    
        condition {
          test     = "Null"
          variable = "aws:ResourceTag/kubernetes.io/cluster/${var.cluster}"
          values   = ["false"]
        }
      }
      depends_on = [
        data.http.policy
      ]
    }