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=DEBUGEvery 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/pluginsSo 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 -cThis 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.




