Skip to content
Back to skills

Aws Iam Patterns

ASecurity

AWS IAM reference: policy evaluation logic, policy types, least-privilege Lambda roles, permission boundaries, SCP guardrails, cross-account access with external ID, and IAM anti-patterns such as unconstrained PassRole. Use when writing or reviewing IAM policies.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
securitygorailsawsgitapisecurity

Works with

  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add HermeticOrmus/LibreSecOps-Claude-Code --skill aws-iam-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Aws Iam Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Aws Iam Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hermeticormus-aws-iam-patterns/badge)](https://www.skillsdirectory.com/skills/hermeticormus-aws-iam-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "aws-iam-patterns"
description: "AWS IAM reference: policy evaluation logic, policy types, least-privilege Lambda roles, permission boundaries, SCP guardrails, cross-account access with external ID, and IAM anti-patterns such as unconstrained PassRole. Use when writing or reviewing IAM policies."
---

# AWS IAM Patterns

> Secure IAM policy patterns, least-privilege templates, and the policy evaluation logic that governs all AWS access control.

## Knowledge Base

### IAM Policy Evaluation Logic

This is the most important concept in AWS security. Every API call is evaluated as follows:

1. **Explicit Deny** -- If ANY policy says Deny, the action is denied. Period. No override.
2. **Organizations SCP** -- If no SCP allows it, denied (SCPs are allowlists for member accounts).
3. **Resource-based policy** -- If a resource policy grants access, it can allow cross-account access without an identity policy (except for IAM roles in the same account).
4. **Identity-based policy** -- The policies attached to the user/role/group.
5. **Permissions boundary** -- If set, the effective permissions are the INTERSECTION of the identity policy and the boundary.
6. **Session policy** -- For assumed roles or federated users, further restricts to the intersection.
7. **Implicit Deny** -- If nothing explicitly allows it, denied.

Understanding this chain is what separates a secure AWS environment from a breached one.

### Policy Types and When to Use Each

| Policy Type | Attached To | Use Case |
|-------------|-------------|----------|
| Identity-based (managed) | Users, roles, groups | Standard permissions for principals |
| Identity-based (inline) | Single user/role/group | Exception permissions that should not be reusable |
| Resource-based | S3 buckets, KMS keys, SQS queues, Lambda, etc. | Cross-account access, service principal access |
| Permissions boundary | Users, roles | Delegation -- let developers create roles within a boundary |
| SCP | Organization OU/account | Guardrails -- prevent entire categories of actions |
| Session policy | AssumeRole, GetFederationToken | Further restrict a specific session |

## Patterns

### Pattern 1: Least-Privilege Role for a Lambda Function

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadSpecificDynamoDBTable",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query",
        "dynamodb:BatchGetItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/orders"
    },
    {
      "Sid": "WriteToSpecificS3Prefix",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::reports-bucket/lambda-output/*"
    },
    {
      "Sid": "AllowLogging",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/my-function:*"
    }
  ]
}
```

**Why this works**: Each statement names the exact actions, targets the exact resource ARN, and includes only what the function needs. No wildcards in actions or resources.

### Pattern 2: Permissions Boundary for Developer Self-Service

Allow developers to create IAM roles for their applications, but constrain what those roles can do:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCommonServices",
      "Effect": "Allow",
      "Action": [
        "s3:*",
        "dynamodb:*",
        "sqs:*",
        "sns:*",
        "logs:*",
        "xray:*",
        "lambda:InvokeFunction"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenyPrivilegeEscalation",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:CreateRole",
        "iam:AttachRolePolicy",
        "iam:PutRolePolicy",
        "iam:AddUserToGroup",
        "iam:CreateAccessKey",
        "organizations:*",
        "account:*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenySecurityServiceChanges",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:StopLogging",
        "cloudtrail:DeleteTrail",
        "guardduty:DeleteDetector",
        "config:StopConfigurationRecorder"
      ],
      "Resource": "*"
    }
  ]
}
```

**Why this works**: Developers can create roles that use common services, but the boundary prevents those roles from modifying IAM, disabling security tools, or escalating privileges. The explicit denies cannot be overridden.

### Pattern 3: SCP Guardrails for an Organization

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyLeavingOrganization",
      "Effect": "Deny",
      "Action": "organizations:LeaveOrganization",
      "Resource": "*"
    },
    {
      "Sid": "ProtectCloudTrail",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:StopLogging",
        "cloudtrail:DeleteTrail",
        "cloudtrail:PutEventSelectors"
      ],
      "Resource": "arn:aws:cloudtrail:*:*:trail/organization-trail",
      "Condition": {
        "StringNotLike": {
          "aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdmin"
        }
      }
    },
    {
      "Sid": "RequireIMDSv2",
      "Effect": "Deny",
      "Action": "ec2:RunInstances",
      "Resource": "arn:aws:ec2:*:*:instance/*",
      "Condition": {
        "StringNotEquals": {
          "ec2:MetadataHttpTokens": "required"
        }
      }
    },
    {
      "Sid": "DenyPublicS3",
      "Effect": "Deny",
      "Action": "s3:PutBucketPublicAccessBlock",
      "Resource": "*",
      "Condition": {
        "StringNotLike": {
          "aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdmin"
        }
      }
    }
  ]
}
```

**Why this works**: SCPs operate at the organization level and cannot be bypassed by any IAM policy in member accounts. These prevent the most dangerous actions organization-wide while allowing a specific security role to make exceptions when needed.

### Pattern 4: Cross-Account Access with External ID

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCrossAccountAssume",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/vendor-integration"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-secret-per-customer-abc123"
        }
      }
    }
  ]
}
```

**Why this works**: The External ID prevents the "confused deputy" problem -- where a third party could trick the role into assuming access on behalf of a different customer. Always require External ID for third-party cross-account access.

## Anti-Patterns

### Anti-Pattern 1: The Admin Policy

```json
{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}
```

**Why it is dangerous**: Grants full access to every AWS service and every resource. A single compromised credential means full account takeover. Even "admin" users should have bounded permissions with explicit denies on the most dangerous actions.

### Anti-Pattern 2: PassRole Without Resource Constraint

```json
{
  "Effect": "Allow",
  "Action": "iam:PassRole",
  "Resource": "*"
}
```

**Why it is dangerous**: `iam:PassRole` allows a user to assign an IAM role to a service (e.g., Lambda, EC2). With `Resource: *`, the user can pass a high-privilege role to a service they control, effectively escalating to that role's permissions. Always constrain to specific role ARNs.

### Anti-Pattern 3: Wildcard Principal in Resource Policy

```json
{
  "Effect": "Allow",
  "Principal": "*",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}
```

**Why it is dangerous**: This makes every object in the bucket accessible to anyone on the internet. If the bucket contains any sensitive data, this is a breach. Use specific account IDs, role ARNs, or VPC endpoint conditions instead.

### Anti-Pattern 4: Not Using Conditions

Policies without conditions are usually too broad. Key conditions to use:
- `aws:SourceIp` -- Restrict by IP range (for human users)
- `aws:PrincipalOrgID` -- Restrict to your organization
- `aws:RequestedRegion` -- Restrict to approved regions
- `aws:SecureTransport` -- Require TLS
- `ec2:MetadataHttpTokens` -- Require IMDSv2

## References

- [IAM Policy Evaluation Logic](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html)
- [IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
- [AWS IAM Access Analyzer](https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html)
- [Parliament -- IAM Policy Linting](https://github.com/duo-labs/parliament)
- [Cloudsplaining -- IAM Security Assessment](https://github.com/salesforce/cloudsplaining)
- [Rhino Security Labs -- AWS IAM Privilege Escalation](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…