Defining IAM Policies with Terraform safely

Andreas Wittig – 31 Mar 2021

Are you still defining IAM policies using heredoc syntax (<<EOF ... EOF) or jsonencode()? You can do better! As a result, terraform validate can tell you about typos before you apply them, and you get better auto-complete support from your IDE. Read on to learn how to define IAM policies in Terraform safely.

Defining IAM Policies with Terraform

When looking at Terraform code I still see the following two ways to define IAM policies:


Looking for a new challenge?

  • tecRacer

    Cloud Consultant

    tecRacer • Premier AWS Consulting Partner • Germany, Austria, Spain, and Switzerland
    AWS only Infrastructure as Code EC2 Containers Serverless
  • tecRacer

    Cloud Migration Specialist

    tecRacer • Premier AWS Consulting Partner • Germany, Austria, Spain, and Switzerland
    Lift&Shift Transformation EC2 RDS VPC

resource "aws_iam_policy" "inline" {
name = "tf-inline"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "${aws_s3_bucket.example.arn}/*"
}
]
}
EOF
}

The second approach looks like this:

resource "aws_iam_policy" "jsonencode" {
name = "tf-jsonencode"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject"
]
Resource = [
"${aws_s3_bucket.example.arn}/*"
]
}
]
})
}

The problem with both approaches: If your policy is malformed, you have to terraform apply before you realize the mistake. Besides that, your IDE’s auto-complete can not help you much when using those approaches.

How can we do better? The following video demonstrates using the data source aws_iam_policy_document. This way, Terraform can validate your IAM policy (at least from a structural perspective), and your IDE can do a much better job of increasing your productivity.

resource "aws_iam_policy" "policydocument" {
name = "tf-policydocument"
policy = data.aws_iam_policy_document.example.json
}

data "aws_iam_policy_document" "example" {
statement {
effect = "Allow"
actions = [
"s3:ListBucket"
]
resources = [
aws_s3_bucket.example.arn
]
}
statement {
effect = "Allow"
actions = [
"s3:GetObject",
"s3:PutObject"
]
resources = [
"${aws_s3_bucket.example.arn}/*"
]
}
}

Become a cloudonaut supporter

Andreas Wittig

Andreas Wittig ( Email, Twitter, or LinkedIn )

We launched the cloudonaut blog in 2015. Since then, we have published 347 articles, 45 podcast episodes, and 37 videos. It's all free and means a lot of work in our spare time. We enjoy sharing our AWS knowledge with you.

Please support us

Have you learned something new by reading, listening, or watching our content? With your help, we can spend enough time to keep publishing great content in the future. Learn more

$
Amount must be a multriply of 5. E.g, 5, 10, 15.

Thanks to Alan Leech, Alex DeBrie, ANTHONY RAITI, Christopher Hipwell, Jaap-Jan Frans, Jason Yorty, Jeff Finley, Jens Gehring, jhoadley, Johannes Grumböck, John Culkin, Jonas Mellquist, Juraj Martinka, Kamil Oboril, Ken Snyder, Ross Mohan, Ross Mohan, sam onaga, Satyendra Sharma, Shawn Tolidano, Thorsten Hoeger, Todd Valentine, Victor Grenu, and all anonymous supporters for your help! We also want to thank all supporters who purchased a cloudonaut t-shirt.