Home > other >  Pass variables into Terraform IAM Policy Document
Pass variables into Terraform IAM Policy Document

Time:09-22

Editing This Question.

I'm using Terraform v0.12.9 and I'm trying to conditionally create bucket policies with the custom policy stored as an IAM policy document.

data "aws_iam_policy_document" "my_policy" {
  statement {
    sid     = "IPALLOW"
    effect  = "Deny"
    actions = ["s3:*"]
    resources = [
      "arn:aws:s3:::${var.my_bucket}/*",
      "arn:aws:s3:::${var.my_bucket}"
    ]
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    condition {
      test     = "NotIpAddress"
      variable = "aws:SourceIp"
      values = [
        "${concat(var.ip_one,
        var.ip_two,
        var.ip_three)}"
      ]
    }
  }

}
resource "aws_s3_bucket_policy" "my-bucket-policy" {
  count  = length(var.buckets)
  bucket = element(values(var.buckets[count.index]), 0)
  policy = (
    element(values(var.buckets[count.index]), 0) == "bar_bucket" ?
    data.aws_iam_policy_document.my_policy.json : <<POLICY
  {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "HTTP",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "*",
    REST OF POLICY REDACTED
    POLICY
   )
 }


}

However this fails and throws an error

Inappropriate value for attribute "values": element 0: string required.

But when I hardcode the ip addresses in the policy like this,

["100.0.0.100","100.0.0.101","100.0.0.102/24","100.0.0.103/24","100.0.0.104"]

It works.

Is there a way to pass the IP addresses as a variable in the IAM policy document?

I've tried jsonencode on the values, but it add a bunch of \ which doesn't work.

These are what the variables look like.

variable "ip_one" {
  type = list(string)
  default = [
    "100.0.0.100",
    "100.0.0.101"
  ]
}

variable "ip_two" {
  type = list(string)
  default = [
    "100.0.0.102/24",
    "100.0.0.103/24"
  ]
}

variable "ip_three" {
  type = list(string)
  default = [
    "100.0.0.104"
  ]
}

CodePudding user response:

As I see it, there are a couple of problems:

  1. The IPs have to have the subnet mask as well, i.e., you cannot mix IP addresses with and without subnet mask. For example, in ip_one you are using 100.0.0.100 while in ip_two you have 100.0.0.102/24.
  2. The variables are already lists of strings, so concatenating lists will create a list and then values is supposed to be a list as well.

What I would suggest is using a local variable for any value manipulation and then using the local variable in the values argument. So you could do the following:

locals {
  ips = concat(var.ip_one, var.ip_two, var.ip_three)
}

data "aws_iam_policy_document" "my_policy" {
  statement {
    sid     = "IPALLOW"
    effect  = "Deny"
    actions = ["s3:*"]
    resources = [
      "arn:aws:s3:::${var.my_bucket}/*",
      "arn:aws:s3:::${var.my_bucket}"
    ]
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    condition {
      test     = "NotIpAddress"
      variable = "aws:SourceIp"
      values = local.ips
    }
  }

}

Also, if you want to limit access to only a set of IPs or subnets, you should definitely consider adding the subnet mask to IPs in ip_one and ip_three. If you do not do that, the access will probably be allowed from the IP addresses you do not want to allow access from.

CodePudding user response:

Can you try something like

 values = [
 join(",", concat(var.ip_one,
 var.ip_two,
 var.ip_three))
 ]
  • Related