0
0
Terraformcloud~5 mins

Least privilege for Terraform service accounts - Commands & Configuration

Choose your learning style9 modes available
Introduction
When Terraform manages cloud resources, it needs permission to do so. Giving it only the exact permissions it needs keeps your cloud safe from mistakes or attacks.
When you want Terraform to create and manage resources but limit what it can change.
When you have multiple teams using Terraform and want to keep their access separate.
When you want to reduce risk by not giving Terraform full admin rights.
When you want to follow security rules that require minimal access.
When you want to audit and control what Terraform can do in your cloud.
Config File - main.tf
main.tf
provider "aws" {
  region = "us-east-1"
  assume_role {
    role_arn = aws_iam_role.terraform_role.arn
  }
}

resource "aws_iam_role" "terraform_role" {
  name = "terraform-service-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "ec2.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy" "terraform_policy" {
  name        = "terraform-least-privilege-policy"
  description = "Policy with least privilege for Terraform to manage S3 buckets"

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "s3:ListBucket",
          "s3:GetBucketLocation"
        ],
        Resource = ["arn:aws:s3:::example-terraform-bucket"]
      },
      {
        Effect = "Allow",
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject"
        ],
        Resource = ["arn:aws:s3:::example-terraform-bucket/*"]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "attach_policy" {
  role       = aws_iam_role.terraform_role.name
  policy_arn = aws_iam_policy.terraform_policy.arn
}

This Terraform file creates a service role for Terraform with a policy that only allows managing a specific S3 bucket.

aws_iam_role: Defines the role Terraform will use.

assume_role_policy: Allows EC2 service to assume this role (common for Terraform running on EC2).

aws_iam_policy: Defines the least privilege permissions for S3 bucket actions.

aws_iam_role_policy_attachment: Attaches the policy to the role.

Commands
Initializes Terraform in the current directory to download providers and prepare the environment.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/aws... - Installing hashicorp/aws v4.0.0... - Installed hashicorp/aws v4.0.0 (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure.
Shows what Terraform will do based on the configuration, so you can review permissions and resources before applying.
Terminal
terraform plan
Expected OutputExpected
An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_iam_role.terraform_role will be created + resource "aws_iam_role" "terraform_role" { + arn = (known after apply) + assume_role_policy = jsonencode(...) + id = (known after apply) + name = "terraform-service-role" + unique_id = (known after apply) } # aws_iam_policy.terraform_policy will be created + resource "aws_iam_policy" "terraform_policy" { + arn = (known after apply) + description = "Policy with least privilege for Terraform to manage S3 buckets" + id = (known after apply) + name = "terraform-least-privilege-policy" + policy = jsonencode(...) } # aws_iam_role_policy_attachment.attach_policy will be created + resource "aws_iam_role_policy_attachment" "attach_policy" { + id = (known after apply) + policy_arn = (known after apply) + role = "terraform-service-role" } Plan: 3 to add, 0 to change, 0 to destroy.
Applies the configuration to create the role and policy with least privilege permissions without asking for confirmation.
Terminal
terraform apply -auto-approve
Expected OutputExpected
aws_iam_role.terraform_role: Creating... aws_iam_policy.terraform_policy: Creating... aws_iam_role.terraform_role: Creation complete after 2s [id=terraform-service-role] aws_iam_policy.terraform_policy: Creation complete after 2s [id=terraform-least-privilege-policy] aws_iam_role_policy_attachment.attach_policy: Creating... aws_iam_role_policy_attachment.attach_policy: Creation complete after 1s [id=terraform-service-role-terraform-least-privilege-policy] Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
-auto-approve - Skip confirmation prompt to apply changes immediately
Verifies the IAM role exists and shows its details to confirm creation.
Terminal
aws iam get-role --role-name terraform-service-role
Expected OutputExpected
{ "Role": { "Path": "/", "RoleName": "terraform-service-role", "RoleId": "AROAXXXXXXXXEXAMPLE", "Arn": "arn:aws:iam::123456789012:role/terraform-service-role", "CreateDate": "2024-06-01T12:00:00Z", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } } }
Key Concept

If you remember nothing else from this pattern, remember: always give Terraform only the permissions it absolutely needs to reduce risk.

Common Mistakes
Giving Terraform full admin permissions instead of least privilege.
This exposes your cloud to accidental or malicious changes beyond what Terraform needs.
Create and attach a policy that only allows the specific actions Terraform requires.
Not attaching the policy to the service account role.
Terraform will not have any permissions and will fail to create or manage resources.
Always attach the least privilege policy to the Terraform service role.
Using overly broad resource ARNs in the policy.
This grants more access than necessary, defeating least privilege.
Specify exact resource ARNs that Terraform should manage.
Summary
Create an IAM role for Terraform with an assume role policy.
Define a policy with only the permissions Terraform needs.
Attach the policy to the IAM role to enforce least privilege.
Use terraform init, plan, and apply to deploy the configuration.
Verify the role and permissions exist with AWS CLI commands.