9

In my current terraform configuration I am using a static JSON file and importing into terraform using the file function to create an AWS IAM policy.

Terraform code:

resource "aws_iam_policy" "example" {
  policy = "${file("policy.json")}"
}

AWS IAM Policy definition in JSON file (policy.json):

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-2",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111122223333:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::777788889999:root"
                ]
            },
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::444455556666:root"
                ]
            },
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "*"
        }
    ]
}

My goal is to use a list of account numbers stored in a terraform variable and use that to dynamically build the aws_iam_policy resource in terraform. My first idea was to try and use the terraform jsonencode function. However, it looks like there might be a way to implement this using the new terraform dynamic expressions foreach loop.

The sticking point seems to be appending a variable number of resource blocks in the IAM policy.

Pseudo code below:

var account_number_list = ["123","456","789"]
policy = {"Statement":[]}
for each account_number in account_number_list:
    policy["Statement"].append(policy block with account_number var reference)

Any help is appreciated.

Best, Andrew

4

3 回答 3

9

The aws_iam_policy_document data source from aws gives you a way to create json policies all in terraform, without needing to import raw json from a file or from a multiline string.

Because you define your policy statements all in terraform, it has the benefit of letting you use looping/filtering on your principals array.

In your example, you could do something like:

data "aws_iam_policy_document" "example_doc" {
  statement {
    sid = "Enable IAM User Permissions"
    effect = "Allow"

    actions = [
      "kms:*"
    ]

    resources = [
      "*"
    ]

    principals {
      type = "AWS"
      identifiers = [
        for account_id in account_number_list:
        account_id
      ]
    }
  }

  statement {
    ...other statements...
  }
}

resource "aws_iam_policy" "example" {
  // For terraform >=0.12
  policy = data.aws_iam_policy_document.example_doc.json

  // For terraform <0.12
  policy = "${data.aws_iam_policy_document.example_doc.json}"
}
于 2019-09-06T18:04:51.183 回答
3

1st option:

if you don't want to rebuild the policy in aws_iam_policy_document you can use templatefile see https://www.terraform.io/docs/language/functions/templatefile.html

resource "aws_iam_policy" "example" {
  policy = templatefile("policy.json",{account_number_list = ["123","456","789"]})
}
...
%{ for account in account_number_list ~}
   {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::${account}:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
%{ endfor ~}
...

2nd option:

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#policy-vars-infotouse

AWS's IAM policy document syntax allows for replacement of policy variables within a statement using ${...}-style notation, which conflicts with Terraform's interpolation syntax. In order to use AWS policy variables with this data source, use &{...} notation for interpolations that should be processed by AWS rather than by Terraform.

...
       {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::&{aws:userid}:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },

Like in: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document

于 2021-07-20T11:52:44.590 回答
0

This was great and is a good pattern to be able to hold onto. Unfortunately, I ran into an issue with it going up against the quota limit:

Assume Role Policy: LimitExceeded: Cannot exceed quota for ACLSizePerRole: 2048

You can request an increase on this quota size but supposedly the max is 4098. the assume role policy I am attempting to create is needed for every AWS account we have so we will eventually hit that limit as well.

It's unfortunate that you can use wild cards within arns of an assume role policy but you can use "*" which I would argue is much much riskier.

于 2021-06-30T14:30:46.843 回答