How to Create IAM Policy in AWS using Terraform: 4 Ways

How to Create IAM Policy in AWS using Terraform

How to Create IAM Policy in AWS using Terraform

Dear reader, hope you are doing great. In this post, you will learn to create an IAM policy in AWS using Terraform.

Although creating an AWS IAM policy using Terraform is not a very difficult task. There are so many ways in which it can be achieved.

Having said that, this tutorial discusses four different ways in which you can create an IAM standalone policy or managed policy using Terraform. Additionally, you will also learn which one to use and why.

Alright…

Let’s go…

Important Note: I assume that you already know terraform. You also know how to create resources using terraform on AWS. If not, I highly recommend you to check my previous post: Getting Started With Terraform on AWS in Right Way.

I also recommend a course that I took in my early days of terraform to get my journey kickstarted. Check it out on Udemy

Prerequisite

  1. An active AWS account: See How to Setup Free Tier Account in AWS in Right Way
  2. An IAM user with permission
  3. Terraform
  4. AWS CLI

What is IAM Policy?

On AWS, there are several identities that access your resources. These identities such as user/role/group can’t do anything on their own. It’s the IAM policy that defines what permissions they have.

In other words, If I say, IAM policies are JSON documents that define which action is allowed or denied on which request for which identity and under what conditions.

For example, the below policy specifies two allow statements that allow the below-mentioned actions on the demo bucket. You can read more about policies in the official documentation.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::demo"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::demo/*"]
    }
  ]
}

Note: Please note that there are many types of policies in AWS IAM. This post focuses on a standalone IAM policy or managed IAM policy.

How to Create IAM Policy in AWS using Terraform

You use  aws_iam_policy resource to create a standalone IAM policy or a managed IAM policy. Here is how you can create a simple IAM policy.

resource "aws_iam_policy" "demo-policy" {
  policy = <Policy JSON String>
}

Here demo-policy is the logical name of the IAM policy resource. You can logical names to refer to the resource throughout the configuration file.

The policy is the only mandatory parameter that you need to create an IAM policy. On top of that, there are many other parameters like name, description etc. that you can use as per your need. Check out the official documentation for up-to-date parameters available to use with aws_iam_policy resource.

Ways to Create IAM Policy in AWS using Terraform

As in the previous section I said, the policy is the only attribute that you need to specify to create an IAM policy. There are many ways in which you can specify a policy JSON string.

  1. Define policy using the heredoc format
  2. Define policy using jsonencode function
  3. Using file function instead of heredoc string or jsonencode
  4. Using  aws_iam_policy_document 

Let’s see them one by one.

Don’t want to miss any posts from us? join us on our Facebook group, and follow us on Facebook, Twitter, LinkedIn, and Instagram. You can also subscribe to our newsletter below to not miss any updates from us.

Way 1: Define policy using the heredoc format

This is the simplest way to create an IAM policy using Terraform. In this, the policy is specified as a multiline string using heredoc format. This works well if this policy is once in a lifetime affair. However, if you would like to use it throughout your applications or your policy becomes complex, it becomes very difficult to manage.

This is what it looks like-

provider "aws" {
  profile = "default"
}

variable "policy_name"{
  type = string
  default = "demo-policy"
}

variable "bucket_name"{
  type = string
  default = "demo-talk-with-anu"
}

resource "aws_iam_policy" "policy" {
  name        = var.policy_name
  description = "Demo Policy using Heredoc string"

  policy = <<EOT
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::var.bucket_name"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::var.bucket_name/*"]
    }
  ]
}
EOT
}

After you run terraform apply, it creates a policy as expected.

How to Create IAM Policy in AWS using Terraform

Way 2: Define policy using jsonencode function

This function converts a terraform expression result into a valid JSON string. You can use jsonencode to define your JSON policy as well. If there are any terraform-specific things, it will take care of evaluating them and giving you back a string representation of JSON.

Here is what it looks like-

provider "aws" {
  profile = "default"
}

variable "policy_name"{
  type = string
  default = "demo-policy"
}

variable "bucket_name"{
  type = string
  default = "demo-talk-with-anu"
}

resource "aws_iam_policy" "policy" {
  name        = var.policy_name
  description = "Demo Policy using jsonencode"

  policy = jsonencode({
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::var.bucket_name"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::var.bucket_name/*"]
    }
  ]
})
}

Way 3: Create IAM policy from JSON file using Terraform

In both heredoc format and jsonencode, both terraform syntax and JSON policy are all mixed up and look ugly.

But worry not, there is a less ugly way to do it.

provider "aws" {
  profile = "default"
}

variable "policy_name"{
  type = string
  default = "demo-policy"
}

variable "bucket_name"{
  type = string
  default = "demo-talk-with-anu"
}

resource "aws_iam_policy" "policy" {
  name        = var.policy_name
  description = "Demo Policy using file function"

  policy = file("s3-policy.json")
}

The file function reads the contents of a file at the given path and returns them as a string

Way 4: Using  aws_iam_policy_document 

The final way I am discussing today is using the IAM policy document. IAM policy document or aws_iam_policy_document is a data source in Terraform which generates an IAM policy document in JSON format. You can use it with resources that expect policy documents such as the IAM policy that we are creating today.

For that, first, you will create an aws_iam_policy_document data source and specify your policy using Hashicorp configuration language or HCL. And this data source returns the JSON representation of the policy.

provider "aws" {
  profile = "default"
}

variable "policy_name"{
  type = string
  default = "demo-policy"
}

variable "bucket_name"{
  type = string
  default = "demo-talk-with-anu"
}

data "aws_iam_policy_document" "demo-policy-document" {
  statement {
    actions   = ["s3:ListBucket"]
    resources = ["arn:aws:s3:::${var.bucket_name}"]
    effect = "Allow"
  }
  statement {
    actions   = [
	  "s3:PutObject",
      "s3:GetObject",
      "s3:DeleteObject"
	]
    resources = ["arn:aws:s3:::${var.bucket_name}"]
    effect = "Allow"
  }
}

resource "aws_iam_policy" "policy" {
  name        = var.policy_name
  description = "Demo Policy using file function"
  policy = data.aws_iam_policy_document.demo-policy-document.json
}

As you can see for variable replacement or interpolation we have used syntax like ${varname}.

Which one do you think is better?

You can use any one of them and the result will be similar. The problem is that using heredoc string or jsonencode uses inline JSON string to define policy.

If you want to reuse it, you have to copy-paste it everywhere. It is going to be really really hard to maintain. Using files is a bit better way and can be reused. Additionally looks a lot cleaner.

Above all, using aws_iam_policy_document has several advantages over all the other ways.

  • Terraform data sources make applying policies to your AWS resources more flexible. You can overwrite, append, or update policies with this resource by using the source_policy_documents and override_policy_documents arguments.
  • You can use it throughout your project/application efficiently.
  • Terraform automatically formats your policy document into the correct JSON when you run your apply.

So clearly, If you are serious about defining your policies using Terraform, do consider using aws_iam_policy_document to define your policies.

Conclusion

In this post, we learnt How to Create IAM Policy in AWS using Terraform

Let’s summarize what we did in this post.

  • We learnt about AWS IAM policy
  • Created IAM policies using 4 different ways
  • We discussed which one is better to use and why

Enjoyed the content?

Subscribe to our newsletter below to get awesome AWS learning materials delivered straight to your inbox.

If you liked reading my post, you ca motivate me by-

  • Adding a comment below on what you liked and what can be improved.
  • Follow us on FacebookTwitterLinkedInInstagram
  • Share this post with your friends and colleagues.

Suggested Read:

Leave a Reply

Your email address will not be published. Required fields are marked *