Lab 01 — Cloud IAM Attack Path Solver
Operation Cedar Lattice, Phase 09. FIN-LATTICE has a foothold on the Meridian Freight
CI/CD runner. The runner has the meridian-cicd-runner IAM role. Your job is to implement
a graph-solver that finds the lowest-detection-cost path through the IAM permission graph
from the compromised principal to the target resource — and maps every edge to its CloudTrail
event.
Safety boundary. This lab operates entirely on synthetic Python dictionaries representing IAM permission graphs. No real cloud credentials. No real API calls. No deployable exploit. The output is an attack path report and CloudTrail detection mapping.
Objective
Implement four functions in lab.py:
| Function | Description |
|---|---|
can_reach(graph, start, target) | BFS: is there any permission path from start to target? |
attack_path(graph, start, target) | Dijkstra: find lowest-detection-cost path |
privilege_escalation_edges(graph) | Filter edges whose action is a known privesc primitive |
detection_for_edge(edge) | Return CloudTrail event description for an edge |
Graph Format
graph = {
"nodes": ["dev-user", "ec2-role", "admin-role", "s3-data"],
"edges": [
{"principal": "dev-user", "action": "sts:AssumeRole",
"resource": "ec2-role", "condition": None},
{"principal": "ec2-role", "action": "iam:AttachUserPolicy",
"resource": "admin-role", "condition": None},
{"principal": "admin-role", "action": "s3:GetObject",
"resource": "s3-data", "condition": None},
]
}
An edge {principal: A, action: X, resource: B} means: principal A has permission X on resource B.
When resource B is itself a principal (e.g., an IAM role), reaching B means you can use B's edges.
This is the IAM sts:AssumeRole mechanic: assuming a role gives you that role's permissions.
Visibility Costs
Each action has a detection cost (lower = less visible in SIEM):
| Action | Cost | Reason |
|---|---|---|
sts:AssumeRole, s3:GetObject, s3:ListBucket, ec2:DescribeInstances | 1 | Extremely common; low signal |
lambda:InvokeFunction | 2 | Common in automated workloads |
lambda:CreateFunction, iam:PassRole | 3 | Less common, moderate signal |
iam:CreateLoginProfile | 4 | High signal — creating console access |
iam:CreatePolicyVersion, iam:AttachUserPolicy, iam:AttachRolePolicy, etc. | 5 | Very high signal IAM writes |
attack_path minimizes total cost across the path.
Running the Lab
pip install -r requirements.txt
# Run your implementation (should raise NotImplementedError until you implement):
pytest -q
# Run reference solution:
LAB_MODULE=solution pytest -q
Deliverable
When all 12 tests pass with LAB_MODULE=solution pytest -q, you understand how to:
- Model IAM as a directed graph and perform BFS reachability analysis
- Apply Dijkstra to find the stealthiest path (fewest SIEM-detectable events)
- Identify privilege escalation primitives in a permission graph
- Map each attack step to its specific CloudTrail event