Mastering IAM with Terraform: Comparing Heredoc, jsonencode(), and aws_iam_policy_document
When managing AWS Identity and Access Management (IAM) policies with Terraform, choosing the proper method to define and render policy documents can significantly affect readability, maintainability, and validation. Three popular approaches are:
Heredoc syntax with inline JSON
jsonencode() function
aws_iam_policy_document data source
This post compares these methods, discusses their pros and cons, and provides practical examples to help you choose the most suitable option for your use case.
1. Heredoc Syntax with Inline JSON
Use Case
Quick prototyping or when working with pre-existing IAM JSON files.
Example
resource "aws_iam_policy" "inline_heredoc" {
name = "heredoc-example"
description = "IAM Policy using heredoc"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket"
}]
}
EOF
}
Pros
Mirrors AWS IAM JSON directly
Fast to implement
Easy to copy/paste from existing policies
Cons
No Terraform validation
High risk of syntax errors
Not DRY: no variable interpolation or reusability.
2. jsonencode() Function
Use Case
When you need dynamic values and prefer working with Terraform-native structures.
Example
resource "aws_iam_policy" "jsonencoded" {
name = "jsonencode-example"
description = "IAM Policy using jsonencode"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = ["s3:GetObject"],
Resource = "arn:aws:s3:::example-bucket/*"
}
]
})
}
Pros
Validates the structure at the Terraform plan time
Supports interpolation and conditionals
Cleaner and more readable for developers
Cons
Nested JSON can get verbose
Harder to align with IAM JSON documentation
Not as readable for non-developers
3. aws_iam_policy_document Data Source
Use Case
Best for complex policies, dynamic values, modular infrastructure, and DRY principles.
Example
data "aws_iam_policy_document" "example" {
statement {
actions = ["s3:PutObject"]
resources = ["arn:aws:s3:::example-bucket/*"]
effect = "Allow"
}
}
resource "aws_iam_policy" "structured" {
name = "structured-policy"
policy = data.aws_iam_policy_document.example.json
}
Pros
Highly modular and dynamic
Prevents invalid configurations
Easy to read and debug
Recommended for production environments
Cons
Slightly more verbose
More learning curve for new Terraform users
Comparison Table.
Comparison of Terraform Methods for Defining IAM Policies
Heredoc
Human Readable: Yes
Terraform Validation: No
Supports Interpolation: No
Best for Dynamic Policies: No
Recommended for Production: No
jsonencode()
Human Readable: Moderate
Terraform Validation: Yes
Supports Interpolation: Yes
Best for Dynamic Policies: Yes
Recommended for Production: Maybe
aws_iam_policy_document
Human Readable: Yes
Terraform Validation: Yes
Supports Interpolation: Yes
Best for Dynamic Policies: Yes
Recommended for Production: Yes
Conclusion: Choose What Fits Your Context
Use Heredoc if you're just pasting in JSON from AWS docs for a quick test.
Use jsonencode() if you're comfortable with HCL and want dynamic values.
Use aws_iam_policy_document when building production-grade, scalable IAM policies with reusability and validation.
You can manage IAM policies at any scale with Terraform by mastering these three approaches.

Comments
Post a Comment