Mastering Custom IAM Policies: Beyond AWS Managed Defaults
Create custom IAM policies when a managed policy does not meet the needs
Mastering Custom IAM Policies: Beyond AWS Managed Defaults
This study guide focuses on the critical skill of crafting custom Identity and Access Management (IAM) policies. While AWS provides hundreds of managed policies, security-conscious data engineers must often create tailored permissions to adhere to the principle of least privilege.
Learning Objectives
After studying this guide, you should be able to:
- Differentiate between AWS Managed, Customer Managed, and Inline policies.
- Identify the four essential elements of a JSON IAM policy statement.
- Construct a custom policy that restricts access to specific ARNs (Amazon Resource Names).
- Implement the principle of least privilege to minimize security risks.
- Manage policy versioning and rollbacks for customer-managed policies.
Key Terms & Glossary
- IAM Principal: An entity (User or Role) that can perform actions on AWS resources.
- JSON Policy: A JavaScript Object Notation document that defines permissions.
- Least Privilege: The security practice of providing only the minimum permissions necessary to perform a task.
- Implicit Deny: The default state where every action is forbidden unless a policy explicitly allows it.
- Explicit Deny: A statement in a policy that specifically forbids an action, which overrides any "Allow" statements.
The "Big Idea"
IAM policies are the Access Control Lists (ACLs) of the AWS cloud. In a professional environment, AWS Managed Policies are often too broad (e.g., PowerUserAccess). Custom policies allow you to treat security as code, enabling granular control that protects sensitive data from unauthorized access or accidental deletion, even if credentials are compromised.
Formula / Concept Box
The Anatomy of an IAM Statement
Every statement in a custom policy is defined by these core keys:
| Element | Description | Example |
|---|---|---|
| Effect | Whether the statement results in an Allow or a Deny. | "Effect": "Allow" |
| Action | The specific API operation being permitted or forbidden. | "Action": "s3:GetObject" |
| Resource | The specific AWS objects the action applies to (using ARNs). | "Resource": "arn:aws:s3:::my-bucket/*" |
| Condition | (Optional) Rules for when the policy is in effect (IP, MFA, Time). | "Condition": {"IpAddress": {"aws:SourceIp": "1.2.3.4/32"}} |
Hierarchical Outline
- Policy Types Overview
- AWS Managed Policies: Created/maintained by AWS; read-only; broad use-cases.
- Customer Managed Policies: Created by you; reusable; supports versioning (up to 5 versions).
- Inline Policies: Embedded directly into a single principal; not reusable; high risk of accidental deletion.
- The JSON Structure
- Version: Always use
"2012-10-17"for the modern policy language. - Statement Array: A container for one or more permission blocks.
- Version: Always use
- Policy Evaluation Logic
- Start with Implicit Deny.
- Search for an Explicit Deny (if found, result is Deny).
- Search for an Allow (if found, result is Allow).
- If no Allow is found, the final result is Deny.
Visual Anchors
IAM Policy Evaluation Logic
Policy Document Structure
\begin{tikzpicture}[node distance=1.5cm, every node/.style={draw, rectangle, rounded corners, fill=blue!10, align=center}] \node (doc) {Policy Document$JSON)}; \node (ver) [below of=doc] {Version$2012-10-17)}; \node (stat) [below of=ver] {Statement$Array)}; \node (eff) [below left of=stat, xshift=-1cm] {Effect}; \node (act) [below left of=stat, xshift=1cm] {Action}; \node (res) [below right of=stat, xshift=-1cm] {Resource}; \node (con) [below right of=stat, xshift=1cm, fill=green!10] {Condition$Optional)};
\draw[->] (doc) -- (ver);
\draw[->] (ver) -- (stat);
\draw[->] (stat) -- (eff);
\draw[->] (stat) -- (act);
\draw[->] (stat) -- (res);
\draw[->] (stat) -- (con);\end{tikzpicture}
Definition-Example Pairs
- Resource-Level Control: Restricting an action to a specific instance of a service.
- Example: Instead of allowing
s3:*on all buckets, a custom policy allowss3:PutObjectonly onarn:aws:s3:::company-uploads.
- Example: Instead of allowing
- Action-Level Control: Restricting the specific verb/operation used.
- Example: A developer can
DescribeInstances(see them) but cannotTerminateInstances(delete them).
- Example: A developer can
Worked Examples
Problem: Create a policy for a Data Analyst
Requirement: The analyst needs to read data from a specific S3 bucket named clinical-data-2023, but must not be able to delete anything or access any other buckets.
Step 1: Identify Actions
We need s3:ListBucket (to see files) and s3:GetObject (to read files).
Step 2: Identify Resources
- Bucket itself:
arn:aws:s3:::clinical-data-2023 - Objects inside:
arn:aws:s3:::clinical-data-2023/*
Step 3: Craft JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::clinical-data-2023"
},
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::clinical-data-2023/*"
}
]
}Checkpoint Questions
- If a user has an AWS Managed Policy that allows
s3:*but a Customer Managed Policy that explicitly deniess3:DeleteBucket, can they delete a bucket? (Answer: No, Explicit Deny always wins). - How many versions of a Customer Managed Policy does IAM maintain? (Answer: 5).
- Why are Inline Policies generally discouraged for standard roles? (Answer: They are not reusable and are harder to manage at scale).
Comparison Tables
| Feature | AWS Managed | Customer Managed | Inline |
|---|---|---|---|
| Created By | AWS | You | You |
| Editable | No | Yes | Yes |
| Reusable | Yes (across account) | Yes (across account) | No (Principal only) |
| Versioning | Managed by AWS | Managed by You (5) | None |
| Recommended Use | Common Job Functions | Least Privilege Security | One-off exceptions |
Muddy Points & Cross-Refs
- IAM Group vs. Principal: Remember, a Group is NOT a principal. You cannot sign in as a group; it is just a container to attach policies to multiple users at once.
- Permissions Boundaries: A boundary does NOT grant permissions; it sets the maximum ceiling. If the boundary allows S3 but the identity policy allows EC2, the user has zero access because there is no overlap.
- KMS Nuance: Even if you have
kms:CreateKeyin your IAM policy, you do not automatically have permission to use the key you just created unless the Key Policy also allows it. See Chapter 13: Data Encryption for details.