Files
kodekloud-engineer/terraform/task-27.md

107 lines
4.0 KiB
Markdown

# 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)
```hcl
# 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
```bash
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
```bash
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.