Files

4.0 KiB

Assignment

The Nautilus DevOps team has been creating a couple of services on AWS cloud. They have been breaking down the migration into smaller tasks, allowing for better control, risk mitigation, and optimization of resources throughout the migration process. Recently they came up with requirements mentioned below.

An IAM user named iamuser_james and a policy named iampolicy_james already exists. Use Terraform to attach the IAM policy iampolicy_james to the IAM user iamuser_james. The Terraform working directory is /home/bob/terraform. Update the main.tf file (do not create a separate .tf file) to attach the specified IAM policy to the IAM user.

Note: Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.

Solution

Attach IAM Policy — iampolicy_jamesiamuser_james

The user (aws_iam_user.user) and the customer-managed policy (aws_iam_policy.policy) already exist in this main.tf. The task is to bind them, which is one appended aws_iam_user_policy_attachment resource referencing both.

main.tf (append this block; leave the existing two resources unchanged)

# Create IAM user
resource "aws_iam_user" "user" {
  name = "iamuser_james"

  tags = {
    Name = "iamuser_james"
  }
}

# Create IAM Policy
resource "aws_iam_policy" "policy" {
  name        = "iampolicy_james"
  description = "IAM policy allowing EC2 read actions for james"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = ["ec2:Read*"]
        Resource = "*"
      }
    ]
  })
}

# Attach the policy to the user
resource "aws_iam_user_policy_attachment" "attach" {
  user       = aws_iam_user.user.name
  policy_arn = aws_iam_policy.policy.arn
}

How to run

cd /home/bob/terraform
terraform plan     # should show only the new attachment to add
terraform apply -auto-approve

How it works

aws_iam_user_policy_attachment

This resource attaches a managed policy (AWS-managed or customer-managed) to an IAM user. It's the right resource here because iampolicy_james is a standalone customer-managed policy with its own ARN — as opposed to an inline policy, which would use aws_iam_user_policy and embed the JSON directly in the user.

  • user = aws_iam_user.user.name — the attachment targets the user by name.
  • policy_arn = aws_iam_policy.policy.arn — managed-policy attachments are made by ARN. The aws_iam_policy resource exposes its generated arn (arn:aws:iam::<account>:policy/iampolicy_james), so referencing the attribute avoids hardcoding the account ID.

Referencing both resources by attribute creates implicit dependencies: Terraform provisions/keeps the user and policy first, then the attachment. The plan shows only the attachment being added — the existing user and policy are untouched.

Managed vs. inline — why this resource

There are three ways to give an IAM user permissions in Terraform:

Resource Use when
aws_iam_user_policy_attachment Attaching an existing managed policy (this task).
aws_iam_policy_attachment Attaching one policy to many users/roles/groups at once — avoid; it's exclusive and will detach principals it doesn't know about.
aws_iam_user_policy Defining an inline policy embedded in the user.

aws_iam_user_policy_attachment is the correct, non-exclusive choice for wiring one managed policy to one user.

Sandbox note

The policy grants only ec2:Read* — read-only actions well within the login user's permission scope, so the attach won't trip the anti-privilege-escalation lockdown. Attaching a policy broader than your login user has is what triggers AccessDenied; that isn't the case here.

Verify

aws iam list-attached-user-policies --user-name iamuser_james \
  --query 'AttachedPolicies[*].{Name:PolicyName,Arn:PolicyArn}'

Expected — a list containing iampolicy_james with its ARN.