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_james → iamuser_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. Theaws_iam_policyresource exposes its generatedarn(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.