Skip to main content

How to Generate Terraform IAM Policies with Autopilot

· By Pankajbhai Chavda · 3 min read

If you have deployed infrastructure on AWS, you know the pain of writing the Terraform IAM policies required to run a successful apply. Most of us just slap AdministratorAccess on a role to get the pipeline working and promise to "fix it later." The alternative is spending hours running terraform apply, hitting an AccessDenied error, adding a permission, and repeating the cycle until it works.

AWS open-sourced a tool called IAM Policy Autopilot a while back to help with this, but it scanned only application source code. Now, they finally bring that feature we actually wanted. It can generate least-privilege IAM policies directly from a Terraform plan. No more guessing which random ec2:Describe* permissions Terraform needs under the hood just to read your state.

Here is how to set it up and test it with a realistic deployment.

Install IAM Policy Autopilot 

You will need Terraform installed first. For Autopilot, AWS provides an easy one-liner to pull the latest release and drop the binary into /usr/local/bin.

curl -sSL https://github.com/awslabs/iam-policy-autopilot/raw/refs/heads/main/install.sh | sudo sh

Write a Realistic Terraform Config

Let's test this with a realistic production scenario. We will deploy an EC2 web server, a custom Security Group and an IAM role. Drop this into a scratch folder as main.tf:

provider "aws" {
  region = "us-east-1"
}

resource "aws_security_group" "web_sg" {
  name        = "prod-web-sg"
  description = "Allow HTTP and SSH"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_iam_role" "web_role" {
  name = "prod-web-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = { Service = "ec2.amazonaws.com" }
    }]
  })
}

resource "aws_instance" "web" {
  ami           = "ami-0c7217cdde317cfec" # Ubuntu 22.04 LTS
  instance_type = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = {
    Name        = "prod-web-server"
    Environment = "production"
  }
}

Export Your AWS Credentials

For Terraform to run a plan against your live AWS account and verify the current state, it needs authentication. Export your AWS access keys directly into your terminal session. In the below command, replace your access key and secret key.

export AWS_ACCESS_KEY_ID="AKIA_YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"

Generate the Plan

Autopilot does not analyze your .tf files. It reads a compiled JSON plan.

Terraform plans capture your exact infrastructure state; they often contain secrets like database passwords or API keys. You need to lock down your file permissions before running this.

umask 077
terraform init
terraform plan -out=prod.tfplan

Convert and Run

Convert the binary plan to JSON using the Terraform CLI, then feed it straight into Autopilot.

terraform show -json prod.tfplan > prod.json
chmod 600 prod.tfplan prod.json

iam-policy-autopilot generate-policies $(pwd)/prod.json --region us-east-1 --account 123456789012

Note: Make sure to use the absolute path to your JSON file (using $(pwd) handles this for you). Including your --region and --account flags helps ensure the generated ARNs are as accurate as possible.

The Result

When you run that, Autopilot spits out a massive JSON policy. Instead of a lazy * resource block, it locks the IAM permissions strictly to arn:aws:iam::123456789012:role/prod-web-role. It maps out exactly which EC2 actions the Terraform AWS provider needs to manage the security group and server. You can literally copy-paste the output into an IAM policy and hand it to your CI/CD runner.

A Warning on Cleanup

Treat that prod.json file like a leaked password. Don't commit it to Git, and don't leave it sitting on a shared build server. Delete both the binary and JSON plan files as soon as you have your policy. Since Autopilot runs locally and only looks at resource changes, your secrets never leave your machine. It makes locking down Terraform IAM permissions practically effortless, but you still don't want plan files laying around.

About the author

Pankajbhai Chavda Pankajbhai Chavda
Updated on Sep 9, 2026
-