Skip to main content
Fix Terraform Error - Error Creating IAM Role - MalformedPolicyDocument

Fix Terraform Error - Error Creating IAM Role - MalformedPolicyDocument

Key Takeaway

How to fix MalformedPolicyDocument errors when creating IAM roles in Terraform. Fix assume role policies, trust relationships, and JSON syntax.

Table of Contents

The Error

Error creating IAM Role: MalformedPolicyDocument: Invalid principal in policy

What Causes This

The IAM assume role policy (trust relationship) contains invalid JSON, references a non-existent principal, or has syntax errors. Common mistakes include using the wrong ARN format, missing quotes, or referencing deleted accounts/services.

How to Fix It

Solution 1: Fix the Trust Policy JSON

# BAD — common mistakes
resource "aws_iam_role" "lambda" {
  name = "lambda-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action    = "sts:AssumeRole"
      Effect    = "Allow"
      Principal = {
        Service = "lambda"  # Wrong! Missing .amazonaws.com
      }
    }]
  })
}

# GOOD — correct service principal
resource "aws_iam_role" "lambda" {
  name = "lambda-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action    = "sts:AssumeRole"
      Effect    = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"  # Correct!
      }
    }]
  })
}

Solution 2: Validate JSON Before Applying

# Check your policy is valid JSON
terraform console
> jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = { Service = "ec2.amazonaws.com" }
      Action = "sts:AssumeRole"
    }]
  })

Common Service Principals

# Lambda:        lambda.amazonaws.com
# EC2:           ec2.amazonaws.com
# ECS Tasks:     ecs-tasks.amazonaws.com
# API Gateway:   apigateway.amazonaws.com
# CloudWatch:    events.amazonaws.com
# S3:            s3.amazonaws.com
# SNS:           sns.amazonaws.com
# CodeBuild:     codebuild.amazonaws.com
# CodePipeline:  codepipeline.amazonaws.com

Solution 3: Cross-Account Trust

resource "aws_iam_role" "cross_account" {
  name = "cross-account-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = {
        AWS = "arn:aws:iam::123456789012:root"  # Account ID must exist!
      }
      Action    = "sts:AssumeRole"
    }]
  })
}

Prevention Tips

  1. Pin provider versions — avoid surprise breaking changes
  2. Use CI/CD — catch errors before they hit production
  3. Test with terraform plan — always review before applying
  4. Keep Terraform updated — newer versions have better error messages
  5. Use terraform validate — catches syntax errors early

Hands-On Courses

Learn to avoid these errors with interactive, project-based courses:

Conclusion

Related: Fix the Terraform inconsistent dependency lock file error — quick fix for this common issue.

This error is common and fixable. Follow the solutions above, and check our Terraform course for hands-on training that covers real-world troubleshooting scenarios.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.