System Design: Cloud IAM Privilege Escalation Audit System


1. Problem Statement

Design a system that audits cloud IAM configurations across AWS, Azure, and GCP, identifies privilege escalation paths, and generates a prioritized remediation report.

Functional requirements:

  • Ingest IAM configuration exports from AWS (IAM Policy documents + role assignments), Azure (RBAC assignments + management group hierarchy), GCP (IAM bindings + conditions)
  • Model principals, permissions, and resources as a directed graph
  • Find paths from a low-privileged principal to a sensitive action or resource (e.g., from arn:aws:iam::123456789:user/appuser to iam:CreatePolicyVersion or s3:GetObject on a protected bucket)
  • Flag known privilege-escalation permission combinations:
    • AWS: iam:PassRole + lambda:CreateFunction + lambda:InvokeFunction
    • AWS: iam:CreatePolicyVersion alone
    • Azure: Owner assignment on a subscription
    • GCP: resourcemanager.projects.setIamPolicy
  • Show detection: for each escalation path, the CloudTrail/Activity Log event that would fire
  • Output: a prioritized finding list (highest-privilege gain first) with remediation

Non-functional requirements:

  • Offline: operates on policy export files; no live cloud connectivity required
  • Multi-cloud: a single model supports AWS, Azure, and GCP simultaneously
  • Scale: up to 10,000 principals and 100,000 permission assignments per cloud account

2. Constraints

In scope:

  • IAM/RBAC policy evaluation model for each cloud
  • Privilege escalation edge taxonomy
  • Graph-based path finding
  • Detection mapping per edge

Out of scope:

  • Live API calls to cloud provider control planes
  • Automated remediation (applying changes)
  • Data plane access (actual S3 object reads, etc.)

3. High-Level Architecture

┌──────────────────────────────────────────────────────────────────────────┐
│  IAM Export Files                                                        │
│  AWS: iam-policies.json + role-assignments.json                          │
│  Azure: rbac-assignments.json + management-group-hierarchy.json          │
│  GCP: iam-bindings.json + org-policy.json                                │
└───────────────────────────────┬──────────────────────────────────────────┘
                                │
                                ▼
┌──────────────────────────────────────────────────────────────────────────┐
│  Cloud-Specific Parsers (per-cloud policy evaluation)                    │
│  AWS Parser: deny > SCP > resource policy > identity policy              │
│  Azure Parser: RBAC assignment scope + inherited permissions             │
│  GCP Parser: binding + condition evaluation                              │
└───────────────────────────────┬──────────────────────────────────────────┘
                                │
                                ▼
┌──────────────────────────────────────────────────────────────────────────┐
│  Unified Graph Model                                                     │
│  Nodes: principals (users, roles, service accounts, groups)             │
│  Edges: effective permissions (action → resource)                       │
│  Edge metadata: cloud provider, escalation risk, detection event        │
└───────────────────────────────┬──────────────────────────────────────────┘
                                │
                     ┌──────────┴───────────┐
                     │                      │
                     ▼                      ▼
          ┌─────────────────┐   ┌──────────────────────┐
          │ Escalation Path │   │ Known-Pattern Matcher │
          │ Finder          │   │ (flag known combos   │
          │ (graph walk)    │   │ without graph search) │
          └────────┬────────┘   └───────────┬──────────┘
                   │                        │
                   └───────────┬────────────┘
                               ▼
                  ┌────────────────────────────┐
                  │  Finding Prioritizer        │
                  │  + Detection Mapper         │
                  │  + Remediation Generator    │
                  └────────────────────────────┘

4. Component Deep-Dives

4.1 Policy Evaluation Models

AWS (most complex): the evaluation algorithm in order:

  1. Explicit Deny in any policy → denied
  2. If inside an AWS Organization: SCP must allow the action → if SCP does not explicitly allow, denied
  3. Resource-based policy: if it has an explicit Allow for the principal → allowed (even without identity policy, for same-account; for cross-account, needs both)
  4. Identity-based policy (attached to the principal): if Allow → allowed
  5. Default: implicit deny

The parser must implement this evaluation order to determine effective permissions.

Azure (simpler): role assignments are additive; most permissive role wins. Deny assignments (available but rarely used) override allows. The inheritance chain: management group → subscription → resource group → resource. The parser walks up the scope chain to collect all inherited assignments.

GCP (condition-aware): IAM bindings grant a role to a member at a resource scope. Conditions (e.g., "only during business hours") restrict when the binding applies. The parser applies binding + condition evaluation.

4.2 Escalation Edge Taxonomy

The most critical AWS privilege escalation paths (each is an edge in the graph):

Edge (permission set)Escalation targetCloudTrail eventRisk
iam:CreatePolicyVersionAny policy → AdminCreatePolicyVersionCRITICAL
iam:SetDefaultPolicyVersionRotate to admin versionSetDefaultPolicyVersionCRITICAL
iam:CreateAccessKey on any userAccess as that userCreateAccessKeyHIGH
iam:PassRole + lambda:CreateFunction + lambda:InvokeFunctionAdmin via Lambda execution roleCreateFunction, InvokeFunctionCRITICAL
iam:PassRole + ec2:RunInstancesAdmin via EC2 instance profileRunInstancesHIGH
iam:AttachUserPolicyAttach admin policy to selfAttachUserPolicyCRITICAL
iam:AddUserToGroupAdd self to admin groupAddUserToGroupHIGH
sts:AssumeRole on an admin roleDirect role assumptionAssumeRoleCRITICAL

For each, the Known-Pattern Matcher flags any principal that holds the permission set without requiring a full graph traversal.

4.3 Detection Mapping

Every escalation edge maps to a CloudTrail or platform audit event:

EDGE_DETECTION = {
    "aws:iam:CreatePolicyVersion": {
        "event_source": "iam.amazonaws.com",
        "event_name": "CreatePolicyVersion",
        "cloudtrail_key": "requestParameters.policyArn",
        "anomaly_signal": "new policy version within 1 hour of principal creation",
    },
    "aws:iam:PassRole:lambda": {
        "event_source": "lambda.amazonaws.com",
        "event_name": "CreateFunction20150331",
        "cloudtrail_key": "requestParameters.role",
        "anomaly_signal": "PassRole with admin ARN from non-admin principal",
    },
    # ... etc
}

The report includes, for each finding: "This escalation path would generate CloudTrail event X. To detect it, create a CloudWatch Metric Filter on X with condition Y."

4.4 Finding Prioritizer

Priority scoring per finding:

score = (privilege_gain_weight × 3) + (path_length_inverse × 2) + (detection_cost_inverse × 1)
  • privilege_gain_weight: CRITICAL (admin access) = 10, HIGH (elevated access) = 7, MEDIUM = 4
  • path_length_inverse: single-step escalation scores higher (1 / path_length)
  • detection_cost_inverse: low-noise escalation scores higher (1 / total_detection_cost)

Output: findings sorted by score descending. Top finding = easiest-to-exploit, highest-privilege, hardest-to-detect escalation path.


5. Tradeoffs

Unified graph vs. per-cloud models:

  • Unified: cross-cloud lateral movement paths (e.g., AWS role assumed from a GCP service account) can be modeled as edges across cloud boundaries.
  • Unified: higher implementation complexity; each cloud's policy semantics are different.
  • Decision: unified graph with cloud-provider labels on edges; cross-cloud edges added when the export includes trust relationships between providers.

Known-pattern matcher vs. graph search:

  • Known-pattern matcher is O(1) per principal against a fixed list — very fast, catches the "hot" escalation paths documented by Rhino Security Labs.
  • Graph search finds novel paths the known-pattern list misses.
  • Decision: both; the known-pattern matcher runs first as a fast pass, graph search runs after for comprehensive coverage.

Full policy simulation vs. approximation:

  • Full AWS IAM policy simulation requires the full policy document, conditions, resource tags, and session context. AWS provides the SimulatePrincipalPolicy API for this, but that requires live connectivity.
  • For offline mode, we approximate by evaluating explicit deny → SCP allow → identity allow. This may produce false positives (overcounting permissions) but never false negatives (never misses a real escalation path).
  • Decision: conservative approximation (overcount) for offline mode; document the limitation.

6. Detection-Forward Perspective

Every escalation path has a CloudTrail event. The report structure is:

  1. Finding: "Principal X can reach admin via iam:CreatePolicyVersion"
  2. CloudTrail signal: "Event iam.amazonaws.com/CreatePolicyVersion from non-admin principal"
  3. Remediation: "Remove iam:CreatePolicyVersion from principal X's attached policies; add a deny SCP for iam:CreatePolicyVersion except for named IAM admin roles"
  4. Detection rule: "CloudWatch metric filter: { $.eventName = "CreatePolicyVersion" && $.userIdentity.type != "AssumedRole:IAMAdmin" }"

This is the output that makes the audit actionable. A finding without the detection rule tells the client what is broken but not how to detect its exploitation. A finding with the detection rule gives the client both the remediation and the monitoring it needs while remediation is in progress.