Lab: Implementing Least-Privilege Authorization with IAM Roles and Policies
Authorization Mechanisms
Lab: Implementing Least-Privilege Authorization with IAM Roles and Policies
This hands-on lab guides you through the process of implementing granular authorization mechanisms in AWS. You will learn to move away from using long-lived IAM user credentials and instead leverage IAM roles with custom policies to achieve the Principle of Least Privilege.
[!WARNING] This lab involves creating AWS resources. Remember to run the teardown commands at the end to avoid ongoing charges, although most tasks are within the Free Tier.
Prerequisites
- An active AWS Account.
- AWS CLI installed and configured on your local machine with administrator access.
- Basic knowledge of S3 and JSON syntax.
- IAM permissions to create roles, policies, and S3 buckets.
Learning Objectives
- Understand the IAM Evaluation Logic (Implicit Deny vs. Explicit Allow).
- Create a Custom IAM Policy for specific resource-level access.
- Provision and assume an IAM Role to access data securely.
- Verify Least Privilege by attempting unauthorized actions.
Architecture Overview
Step-by-Step Instructions
Step 1: Create a Target S3 Bucket
We need a resource to protect. We will create a private S3 bucket and upload a sample file.
# Replace <YOUR_ACCOUNT_ID> with your actual ID or a unique string
aws s3 mb s3://brainybee-lab-data-<YOUR_ACCOUNT_ID>
echo "Sensitive Data" > lab-file.txt
aws s3 cp lab-file.txt s3://brainybee-lab-data-<YOUR_ACCOUNT_ID>/▶Console Alternative
- Navigate to S3 > Create bucket.
- Enter Bucket name: `brainybee-lab-data-
. 3. Keep defaults (Block all public access) and click **Create bucket**. 4. Upload lab-file.txt` into the bucket.
Step 2: Create a Least-Privilege IAM Policy
We will create a JSON policy that only allows s3:GetObject on our specific bucket.
- Create a file named
policy.jsonlocally:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::brainybee-lab-data-<YOUR_ACCOUNT_ID>/*"
}
]
}- Create the policy in AWS:
aws iam create-policy --policy-name S3RestrictedReadPolicy --policy-document file://policy.jsonStep 3: Create an IAM Role and Attach Policy
Roles are the recommended way for applications and users to perform authorized actions without long-term keys.
- Create a Trust Policy (
trust-policy.json) allowing your user to assume the role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<YOUR_ACCOUNT_ID>:root" },
"Action": "sts:AssumeRole"
}
]
}- Create the Role:
aws iam create-role --role-name DataReaderRole --assume-role-policy-document file://trust-policy.json- Attach the Policy to the Role:
aws iam attach-role-policy --role-name DataReaderRole --policy-arn arn:aws:iam::<YOUR_ACCOUNT_ID>:policy/S3RestrictedReadPolicyCheckpoints
| Action | Expected Result | Reason |
|---|---|---|
aws s3 ls s3://brainybee-lab-data-... | Access Denied | The policy only allows GetObject, not ListBucket. |
aws s3 cp s3://.../lab-file.txt . | Success (after assuming role) | Explicit Allow for GetObject resource. |
| Attempt to delete the file | Access Denied | No s3:DeleteObject permission (Implicit Deny). |
Concept Review
IAM Evaluation Logic
Understanding how AWS decides to allow or deny a request is critical for the DEA-C01 exam. Use the diagram below to visualize the priority.
\begin{tikzpicture}[node distance=1.5cm, every node/.style={fill=white, font=\small}, box/.style={rectangle, draw, minimum width=3cm, minimum height=1cm, align=center}] \node (start) [box] {Incoming Request}; \node (deny) [box, below of=start] {Explicit Deny?}; \node (allow) [box, below of=deny] {Explicit Allow?}; \node (final) [box, below of=allow] {Final Decision};
\draw [->] (start) -- (deny);
\draw [->] (deny) -- node[anchor=west] {No} (allow);
\draw [->] (deny) -- node[anchor=south] {Yes} +(4,0) node[right, color=red] {DENIED};
\draw [->] (allow) -- node[anchor=west] {Yes} (final);
\draw [->] (allow) -- node[anchor=south] {No} +(-4,0) node[left, color=orange] {IMPLICIT DENY};
\node at (final) [fill=green!20] {ALLOWED};\end{tikzpicture}
Troubleshooting
| Common Error | Likely Cause | Fix |
|---|---|---|
An error occurred (AccessDenied) | Missing policy or incorrect Resource ARN | Double check the Bucket ARN in policy.json. |
InvalidClientTokenId | Expired temporary credentials | Re-run the aws sts assume-role command to refresh. |
| Policy won't create | Invalid JSON syntax | Ensure no trailing commas and valid quotes in policy.json. |
Cost Estimate
- S3 Storage: < $0.01 (Well within the 5GB Free Tier).
- IAM/STS: $0.00 (IAM is a global free service).
- Total: $0.00 for most users.
Stretch Challenge
Modify your policy.json to include an Explicit Deny for a specific file suffix (e.g., .conf). Test if you can read a .txt file but are blocked from reading a .conf file even though you have a general GetObject allow. This demonstrates that Explicit Deny always overrides Explicit Allow.
Clean-Up / Teardown
To avoid any future charges, delete the resources created:
# 1. Remove the S3 Bucket and its contents
aws s3 rb s3://brainybee-lab-data-<YOUR_ACCOUNT_ID> --force
# 2. Detach policy and delete the role
aws iam detach-role-policy --role-name DataReaderRole --policy-arn arn:aws:iam::<YOUR_ACCOUNT_ID>:policy/S3RestrictedReadPolicy
aws iam delete-role --role-name DataReaderRole
# 3. Delete the policy
aws iam delete-policy --policy-arn arn:aws:iam::<YOUR_ACCOUNT_ID>:policy/S3RestrictedReadPolicy