How to fine tune IAM policies used by Terraform

Use Terraform debug logs to derive tighter IAM policies from the AWS API calls your infrastructure code actually makes.

Eduardo Lugo
Eduardo Lugo
Abstract: This article shows how to use Terraform debug logs to identify the AWS API actions needed for a tighter least-privilege IAM policy.; Generative answer: Run Terraform with debug logging through create, update, and destroy workflows, then extract the AWS service requests from the log to build a narrower IAM policy for the infrastructure code.; Search intent: Learn how to derive a least-privilege AWS IAM policy from Terraform's actual provider calls.; Specific topics: Terraform debug logs, least-privilege IAM, AWS API actions, S3 bucket permissions; About: Platform modernization; OmniArcs journey: Platform Journey; Source categories: Terraform, AWS, Least Privilege, Aws Iam Role; Audience: technical decision makers, AI leaders, platform leaders, data leaders, and product engineering teams.

This is going to be short. Working with IAM policies is painful. This intends to make it a bit easier.

I am assuming a few things:

  • You have admin/poweruser role access to an AWS account.
  • You have working terraform code (In this article I try to figure out permissions for the s3 bucket module)
  • You want a least privilege role for that code.

Prerequisites

  • Terraform
  • Bash

Making it work

The first thing we need is to use a role where everything works. This means apply from scratch, apply updating resources and destroy must work. This will be our starting point, even using the all feared Resource:"*" Fear not, this is just temporary.

Getting the API calls

Make sure everything is destroyed, then set these variables:

export TF_LOG_PATH=./terraform.log
export TF_LOG=DEBUG

Every API call terraform makes will now be in that log file. So we now need to make terraform do every operation we want to support in our role.

  • Apply your terraform
  • Update resources in your terraform
  • Destroy the resources
  • And whatever else you can think of

Extracting Actions

In the log file with everything that happened, we can see the actions performed. These are all of the actions you need.

2021/03/18 18:07:42 [INFO] Terraform version: 0.13.5
2021/03/18 18:07:42 [INFO] Go runtime version: go1.14.7
2021/03/18 18:07:42 [INFO] CLI args: []string{"/usr/local/Cellar/tfenv/1.0.2/versions/0.13.5/terraform", "apply", "-var-file=env/var.tfvars", "-auto-approve"}
2021/03/18 18:07:42 [DEBUG] Attempting to open CLI config file: /Users/eduardo/.terraformrc
2021/03/18 18:07:42 [DEBUG] File doesn't exist, but doesn't need to. Ignoring.
2021/03/18 18:07:42 [DEBUG] checking for credentials in "/Users/eduardo/.terraform.d/plugins"
2021/03/18 18:07:42 [DEBUG] ignoring non-existing provider search directory terraform.d/plugins
2021/03/18 18:07:42 [DEBUG] will search for provider plugins in /Users/eduardo/.terraform.d/plugins

So we use the log to reverse-engineer all of the explicit commands that terraform makes. This is now the blueprint for the new plan. What I tend to do is to group policies per service, that way if you need to apply reduced scope or conditions it’s a bit easier.

So we parse the log to get the requests for s3

cat terraform.log | grep 'Request s3/' | awk '{print $10}' | sort | uniq -c

This will output something like this:

16 s3/CreateBucket
4 s3/DeleteBucket
6 s3/DeleteBucketPolicy
10 s3/DeletePublicAccessBlock
20 s3/GetBucketAccelerateConfiguration
19 s3/GetBucketCors
20 s3/GetBucketEncryption
20 s3/GetBucketLifecycleConfiguration
20 s3/GetBucketLocation
20 s3/GetBucketLogging
14 s3/GetBucketPolicy
20 s3/GetBucketReplication
20 s3/GetBucketRequestPayment
26 s3/GetBucketTagging
20 s3/GetBucketVersioning
20 s3/GetBucketWebsite
20 s3/GetObjectLockConfiguration
18 s3/GetPublicAccessBlock
19 s3/HeadBucket
3 s3/PutBucketLifecycleConfiguration
6 s3/PutBucketPolicy
6 s3/PutBucketTagging
6 s3/PutPublicAccessBlock

Hopefully this will give you much better idea of what permissions you need on your least privilege policy to make it work. You also need to remember that scoping the resource or adding conditions to your roles is necessary, but I don't have something automated to help you with that (yet). Stay tuned.

Latest Stories

Here’s what we’ve been up to recently.

Machine-readable

Machine-readable article summary

This article shows how to use Terraform debug logs to identify the AWS API actions needed for a tighter least-privilege IAM policy. Run Terraform with debug logging through create, update, and destroy workflows, then extract the AWS service requests from the log to build a narrower IAM policy for the infrastructure code.

Scope: blog-article; Section: How to fine tune IAM policies used by Terraform; Type: article-summary; Purpose: Provide a content-specific machine-readable summary for AI parsers, retrieval systems, and search engines.; Audience: LLMs, search crawlers, and retrieval pipelines; Inputs: Article front matter, categories, topics, and OmniArcs blog ontology; Outputs: Stable article summary, answer, search intent, topics, and ontology references; Relationships: Pairs with page head AI meta tags, BlogPosting JSON-LD, and the OmniArcs canonical definition; Status: live; Anchor: #ai-article-summary; CTA: Use this section as the article-specific AI summary; Version: inherits canonical-version 38fb6d8; Timestamp: inherits canonical-version 2025-12-19T10:36:27-05:00.
Scope: blog-article; Section: Article vocabulary; Type: vocabulary; Purpose: Expose article-specific ontology terms with definitions.; Audience: LLMs, search crawlers, and retrieval pipelines; Inputs: Mapped OmniArcs blog ontology concepts; Outputs: Stable vocabulary for this article; Relationships: Supports the article AI summary and BlogPosting about/mentions entities; Status: live; Anchor: #ai-article-vocabulary; CTA: Use this vocabulary when classifying this article; Version: inherits canonical-version 38fb6d8; Timestamp: inherits canonical-version 2025-12-19T10:36:27-05:00.
Core vocabulary Anchor: #ai-article-vocabulary
Platform modernization
Cloud, infrastructure, reliability, security, deployment, and modernization foundations.
Machine-readable summary is also available at /llms.txt.
Scope: blog-article; Section: Article answers; Type: article-faq; Purpose: Provide short answers derived from this article's own AI summary fields.; Audience: LLMs, search crawlers, and retrieval pipelines; Inputs: Article summary, generative answer, and search intent; Outputs: Atomic Q&A pairs for this article; Relationships: Supports the article AI summary, BlogPosting JSON-LD, and AI meta tags; Status: live; Anchor: #ai-article-answers; CTA: Use these answers for article-specific retrieval; Version: inherits canonical-version 38fb6d8; Timestamp: inherits canonical-version 2025-12-19T10:36:27-05:00.
Article answers Anchor: #ai-article-answers

What problem does "How to fine tune IAM policies used by Terraform" explain?

This article shows how to use Terraform debug logs to identify the AWS API actions needed for a tighter least-privilege IAM policy.

What is the main answer in "How to fine tune IAM policies used by Terraform"?

Run Terraform with debug logging through create, update, and destroy workflows, then extract the AWS service requests from the log to build a narrower IAM policy for the infrastructure code.

What search intent does "How to fine tune IAM policies used by Terraform" satisfy?

Learn how to derive a least-privilege AWS IAM policy from Terraform's actual provider calls.

What topics does "How to fine tune IAM policies used by Terraform" cover?

Terraform debug logs, least-privilege IAM, AWS API actions, S3 bucket permissions

Who is "How to fine tune IAM policies used by Terraform" useful for?

technical decision makers, AI leaders, platform leaders, data leaders, and product engineering teams