Least-Privilege IAM Permissions for Terraform

We write a lot of labs here at Skillmix. We need to make sure the labs sessions have only the permissions needed for the student to complete their work.

We used to write lab IAM Policies by hand, starting off with a best guess, and then trial and error our way through it. Suffice to say, this was brutal. Especially when creating labs for tools like Terraform.

Then, one day, the clouds parted and iamlive descended. It took a little bit of time to learn how it works, but now that we have it working, it is a big productivity booster.

Of course, labs aren't the only reason why you'd want this. Overall, it's a security best practice to create least-privilege IAM policies.

How iamlive Works

There are two iamlive modes. The first is called Client Side Monitoring (CSM) mode. According to the repo, this is the default mode, and "...will use metrics delivered locally via UDP to capture policy statements with the IAM Action key only...". This means you'll only get the "Action": "ec2:RunInstances"... part of the IAM policy.

The other mode is Proxy Mode. This mode starts up a local web server at http://127.0.0.1:10080 that will intercept and inspect requests sent to AWS endpoints to generate the IAM Policy statements. It includes both the Action and Resource parts of the IAM Policy.

We will show you how to use the Proxy Mode.

Step 1 - Setup a Test Terraform Project

Open a terminal window. We will refer to this as Terminal #1. Create a directory somewhere, and create a file named main.tf, and paste in these contents:

Terminal #1 (contents of main.tf)

variable "region" {
  type = string
  default = "us-west-2"
}

provider "aws" {
  region = var.region
}

resource "aws_s3_bucket" "app" {}

After the project is created, run the init command. It's important that you only run this command for now.

Terminal #1

$ terraform init

Step 2 - Install iamlive

There are several ways to install iamlive. Please review the repo's Installation docs and select the one that suits you best. We used Macs and used the brew installation method. It worked well.

The rest of these steps assume that you are able to access iamlive from your terminal or command prompt.

Step 3 - Start iamlive

Open another terminal window, Terminal #2, and start iamlive. After executing it, nothing will show up in the window yet.

Terminal #2

$ iamlive --mode proxy

Step 4 - Set Environment Variables

Switch over to Terminal #1 (the one where you created the Terraform project) set these environment variables. Change the access key and secret keys to your own IAM User.

Terminal #1

$ export AWS_CA_BUNDLE=~/.iamlive/ca.pem
$ export HTTP_PROXY=http://127.0.0.1:10080
$ export HTTPS_PROXY=http://127.0.0.1:10080
$ export AWS_ACCESS_KEY_ID="Real Key"
$ export AWS_SECRET_ACCESS_KEY="Real Key"

Regarding the access key and secret key permissions, there are a couple options:

  • Full Admin Policy: If you wan to move fast, you can give the IAM User full admin rights. If you do this, it's best to be on a non-prod account, and to manage your keys according to best practices
  • Limited Policy: You can also start with a limited policy for the IAM User. However, when you run terraform init, it will fail, and you will need to iterate adding permissions to this policy until you get the full policy

Step 5 - Run Terraform Init

We are not at the moment of truth! It's time to run terraform init from Terminal #1, and watch the the policies generate in Terminal #2.

Terminal #1

$ terraform apply
$ terraform destroy

Terminal #2

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:GetCallerIdentity",
                "ec2:DescribeAccountAttributes"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:ListBucket",
                "s3:DeleteBucket"
            ],
            "Resource": "arn:aws:s3:::terraform-20210916234458844600000001"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketAcl",
                "s3:GetBucketCORS",
                "s3:GetBucketWebsite",
                "s3:GetBucketVersioning",
                "s3:GetAccelerateConfiguration",
                "s3:GetBucketRequestPayment",
                "s3:GetBucketLogging",
                "s3:GetReplicationConfiguration",
                "s3:GetEncryptionConfiguration",
                "s3:GetBucketObjectLockConfiguration",
                "s3:GetBucketTagging"
            ],
            "Resource": "arn:aws:s3:::terraform-20210916234458844600000001"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetLifecycleConfiguration"
            ],
            "Resource": "arn:aws:s3:::terraform-20210916234458844600000001"
        }
    ]
}

Newsletter subscription