Calvin Zhang
Calvin Zhang

Reputation: 956

Conditionally set IAM policy based on whether a certain resource exists or not in Terraform

I'm trying to set the KMS key policy based on whether an IAM role exists or not. The yaml file looks like this.

data "aws_iam_policy_document" "key_policy" {
  statement {
    sid = "Give Access to the my Role"

    actions = [
      "kms:GenerateDateKey",
      "kms:Decrypt"
    ]

    resources = ["*"]

    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${var.account_id}:role/myrole"]
    }
  }
}

The issue with this terraform script is that it would fail if myrole doesn't exist in my account. We have multiple AWS accounts and only part of them has this myrole. Our CI will run this same script for all the accounts. Is there a way to apply this statement only if myrole exists?

Upvotes: 1

Views: 3785

Answers (1)

Marcin
Marcin

Reputation: 238637

The design principles of terraform (TF) dictate the a current TF configuration file should explicitly define your infrastructure. This means that resources that define your solution are only managed by a given configuration files and current TF state. If some resource is not in TF state, it simply is considered outside of the scope of TF and as non-existent.

As a consequence, TF does not directly support checking for existence of any resources nor conditional creation of resources based on such conditions. This would lead to issues as your TF would not fully represent your architectures.

Therefor, TF docs recommend:

Rather than trying to write a module that itself tries to detect whether something exists and create it if not, we recommend applying the dependency inversion approach: making the module accept the object it needs as an argument, via an input variable.

Based on the above, you should aim to develop your aws_iam_policy_document.key_policy so that it creates the statement in question based on an input variable. This means that your CICD pipeline would have to check for the existence of the role and pass this information to your CF file as an input variable, e.g. my_role_exists with true and false values.

Then, you could use dynamic blocks to make the statement conditional:

data "aws_iam_policy_document" "key_policy" {

  dynamic "statement" {

    for_each = var.my_role_exists == true ? [1] : [] 

    content {
      sid = "Give Access to the my Role"

      actions = [
        "kms:GenerateDateKey",
        "kms:Decrypt"
      ]

      resources = ["*"]

      principals {
        type        = "AWS"
        identifiers = ["arn:aws:iam::${var.account_id}:role/myrole"]
      }
    }
   } 
}

Upvotes: 6

Related Questions