All Mermaid validated in Mermaid Live Editor. n8n JSON is structurally valid and importable.
Type: n8n workflow (importable JSON) Purpose: The primary visual — the full discovery harness from provider APIs through normalization, AI-workload tagging, reconciliation, and output to the asset graph.
{
"name": "S09 — Cloud Asset Discovery Harness",
"nodes": [
{ "name": "Provider APIs", "type": "n8n-nodes-base.manualTrigger", "position": [200, 300], "notes": "AWS Security Hub + Config, Azure Resource Graph, GCP SCC" },
{ "name": "AWS Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 150], "notes": "Enumerate resources via AWS Config + Security Hub findings" },
{ "name": "Azure Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 280], "notes": "Resource Graph Kusto query across subscription" },
{ "name": "GCP Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 410], "notes": "SCC asset list + findings" },
{ "name": "Normalize to CloudAsset", "type": "n8n-nodes-base.set", "position": [680, 300], "notes": "All resources → unified schema. Provider-agnostic." },
{ "name": "AI Workload Tagging", "type": "n8n-nodes-base.set", "position": [920, 300], "notes": "Flag model endpoints, agents, vector DBs, embedding services. endpoint_publicly_reachable." },
{ "name": "Diff vs Last Inventory", "type": "n8n-nodes-base.set", "position": [1160, 300], "notes": "New/changed/deleted assets. Drift detection." },
{ "name": "New/Changed → Assess", "type": "n8n-nodes-base.set", "position": [1400, 200], "notes": "Run benchmark checks on changed resources only" },
{ "name": "Deleted → Mark Stale", "type": "n8n-nodes-base.set", "position": [1400, 400], "notes": "Remove from active graph, retain for audit" },
{ "name": "Asset Graph Store", "type": "n8n-nodes-base.set", "position": [1640, 300], "notes": "Updated graph. Feeds attack-path analysis (S09.2) and monitoring (S09.3)." }
],
"connections": {
"Provider APIs": { "main": [[{ "node": "AWS Discovery", "type": "main", "index": 0 }], [{ "node": "Azure Discovery", "type": "main", "index": 0 }], [{ "node": "GCP Discovery", "type": "main", "index": 0 }]] },
"AWS Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"Azure Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"GCP Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"Normalize to CloudAsset": { "main": [[{ "node": "AI Workload Tagging", "type": "main", "index": 0 }]] },
"AI Workload Tagging": { "main": [[{ "node": "Diff vs Last Inventory", "type": "main", "index": 0 }]] },
"Diff vs Last Inventory": { "main": [[{ "node": "New/Changed → Assess", "type": "main", "index": 0 }], [{ "node": "Deleted → Mark Stale", "type": "main", "index": 0 }]] },
"New/Changed → Assess": { "main": [[{ "node": "Asset Graph Store", "type": "main", "index": 0 }]] },
"Deleted → Mark Stale": { "main": [[{ "node": "Asset Graph Store", "type": "main", "index": 0 }]] }
}
}
Reading the diagram: Provider APIs fan out to three cloud-specific discovery nodes. Each enumerates resources natively — AWS via Config + Security Hub, Azure via Resource Graph, GCP via SCC. Results normalize to the unified CloudAsset schema regardless of provider. AI Workload Tagging flags model endpoints, agent deployments, vector stores, and embedding services with the endpoint_publicly_reachable field that distinguishes internal tools from public attack surface. The diff against last-known inventory detects drift — new, changed, and deleted assets. New and changed assets get benchmark-assessed; deleted assets are marked stale and removed from the active graph. The output is a continuously-reconciled asset graph that feeds attack-path analysis and posture monitoring.
Type: Mermaid (flowchart) Purpose: Shows the cloud attack surface as a graph, with paths from externally reachable entry points to sensitive data stores through IAM escalation and public-exposure chains.
flowchart LR
subgraph ENTRY["Entry points (publicly reachable)"]
API["Public API Gateway<br/>network_exposure: public"]
BUCKET["Public S3 Bucket<br/>is_public: true"]
MODEL["Public Model Endpoint<br/>AI asset, endpoint_publicly_reachable"]
end
subgraph MID["Internal resources"]
LAMBDA["Lambda Function<br/>assumes Role-A"]
ROLEA["IAM Role-A<br/>over-privileged<br/>can-write to DB"]
EC2["EC2 Instance<br/>in shared VPC"]
ROLEB["IAM Role-B<br/>can-read sensitive"]
end
subgraph TARGET["Sensitive targets (crown jewels)"]
DB["RDS Database<br/>data_classification: regulated"]
VDB["Vector Database<br/>sensitive embeddings"]
DATA["Training Data Store<br/>regulated dataset"]
end
API -->|"can-invoke"| LAMBDA
BUCKET -->|"public read"| MODEL
MODEL -->|"assumes"| ROLEA
LAMBDA -->|"assumes"| ROLEA
ROLEA -->|"can-write"| DB
ROLEA -->|"can-assume"| ROLEB
EC2 -->|"shared VPC"| ROLEB
ROLEB -->|"can-read"| DATA
ROLEB -->|"can-query"| VDB
style ENTRY fill:#2a1810,stroke:#a04000,color:#f0a868
style TARGET fill:#2a0d0d,stroke:#a00000,color:#f08080
style ROLEA fill:#14141f,stroke:#5eead4,color:#5eead4
style ROLEB fill:#14141f,stroke:#5eead4,color:#5eead4
style API fill:#2a1810,stroke:#a04000,color:#f0a868
style BUCKET fill:#2a1810,stroke:#a04000,color:#f0a868
style MODEL fill:#2a1810,stroke:#a04000,color:#f0a868
style DB fill:#2a0d0d,stroke:#a00000,color:#f08080
style VDB fill:#2a0d0d,stroke:#a00000,color:#f08080
style DATA fill:#2a0d0d,stroke:#a00000,color:#f08080
Reading the diagram: The attack surface is a graph. Entry points (orange, left) are publicly reachable assets — a public API Gateway, a public S3 bucket, a public model endpoint. Internal resources (center) are connected by access relationships. The arrows are edges: can-invoke, can-assume, can-read, can-write. Sensitive targets (red, right) hold regulated data — the RDS database, the vector database with sensitive embeddings, the training data store. The attack paths are traversals from entry to target. Path one: Public API Gateway → Lambda → Role-A → RDS Database. Path two: Public Model Endpoint → Role-A → Role-B → Training Data Store. The harness finds all such paths via BFS and scores them. A three-hop path to regulated data scores higher than a five-hop path to internal docs. Fixing one node on a critical path (e.g., removing an over-permissive trust from Role-A) breaks every path through it.
Type: Mermaid (flowchart) Purpose: Shows the event-driven monitoring loop — CloudTrail/Activity Log events trigger targeted re-assessment of changed resources, not full-estate scans.
flowchart TD
EVENTS["Cloud Audit Log stream<br/>CloudTrail / Activity Log / Cloud Audit Logs"]
FILTER{"Security-relevant<br/>event?"}
FETCH["Re-fetch changed<br/>resource state"]
ASSESS["Assess against<br/>CIS benchmark controls"]
GRAPH["Update attack graph<br/>(may add/remove paths)"]
SCORE["Score finding:<br/>exploitability × impact × reachability"]
ROUTE{"Route by severity"}
CRITICAL["CRITICAL<br/>on active attack path<br/>→ page immediately"]
MEDIUM["MEDIUM<br/>→ daily report batch"]
LOW["LOW<br/>→ weekly posture review"]
NOOP["Not security-relevant<br/>→ log only, no re-assessment"]
EVENTS --> FILTER
FILTER -->|"yes: IAM/S3/EC2/AI change"| FETCH
FILTER -->|"no"| NOOP
FETCH --> ASSESS
ASSESS --> GRAPH
GRAPH --> SCORE
SCORE --> ROUTE
ROUTE --> CRITICAL
ROUTE --> MEDIUM
ROUTE --> LOW
style EVENTS fill:#2a1810,stroke:#a04000,color:#f0a868
style FILTER fill:#14141f,stroke:#5eead4,color:#5eead4
style SCORE fill:#14141f,stroke:#5eead4,color:#5eead4
style CRITICAL fill:#2a0d0d,stroke:#a00000,color:#f08080
style MEDIUM fill:#2a1810,stroke:#a04000,color:#f0a868
style LOW fill:#0d2818,stroke:#1e8449,color:#82e0aa
style NOOP fill:#1a1a24,stroke:#5a5a68,color:#5a5a68
Reading the diagram: The monitoring loop is event-driven, not scheduled. The cloud audit log stream (CloudTrail on AWS, Activity Log on Azure, Cloud Audit Logs on GCP) feeds every API call. The filter checks whether the event is security-relevant — IAM changes (AttachRolePolicy, AssumeRole), public exposure changes (PutBucketAcl, AuthorizeSecurityGroupIngress), AI workload changes (CreateEndpoint, CreateAgent). Security-relevant events trigger a targeted re-fetch of the changed resource's current state, a benchmark assessment, and an attack-graph update that may add or remove paths. Findings are scored by exploitability (is the resource on an active path?), impact (what data class?), and reachability (is it publicly exposed?). Critical findings on active attack paths page immediately. Medium findings batch into the daily report. Low findings accumulate for the weekly review. Non-security-relevant events are logged but do not trigger re-assessment — the loop is efficient, not exhaustive.
Type: Mermaid (flowchart) Purpose: Shows how one finding store produces three report views — engineer, CISO, auditor — plus the remediation workflow with the approval gate.
flowchart LR
STORE["Unified Finding Store<br/>(findings + attack paths<br/>+ asset graph + history)"]
subgraph REPORTS["Multi-audience reports"]
ENG["Engineer Report<br/>per-finding: ARN, control,<br/>current vs expected,<br/>remediation command"]
CISO["CISO Report<br/>risk score, trend,<br/>top 5 attack paths,<br/>business-impact framing"]
AUDIT["Auditor Report<br/>control → finding map,<br/>pass/fail, evidence TS,<br/>assessor identity"]
end
REMED["Remediation Library<br/>deterministic fixes:<br/>public bucket, open SG,<br/>missing encryption"]
GATE{"Approval Gate"}
PROD["Production<br/>→ propose only<br/>(human must approve)"]
NONPROD["Staging/Dev<br/>→ auto-apply<br/>per policy"]
TICKET["Ticketing System<br/>(JIRA/Linear)<br/>with full context"]
STORE --> ENG
STORE --> CISO
STORE --> AUDIT
STORE --> REMED
REMED --> GATE
GATE -->|"production"| PROD
GATE -->|"non-prod"| NONPROD
PROD --> TICKET
NONPROD --> TICKET
style STORE fill:#14141f,stroke:#5eead4,color:#5eead4
style REPORTS fill:#0d1418,stroke:#1e8449,color:#82e0aa
style GATE fill:#14141f,stroke:#5eead4,color:#5eead4
style PROD fill:#2a0d0d,stroke:#a00000,color:#f08080
style NONPROD fill:#0d2818,stroke:#1e8449,color:#82e0aa
Reading the diagram: One finding store, three report views. The engineer report projects per-finding detail: resource ARN, violated control, current vs expected configuration, the exact remediation command. The CISO report projects the executive view: overall risk score, trend over time, the top 5 attack paths, business-impact framing — answering "are we getting better or worse, and what matters this week." The auditor report projects compliance evidence: each control mapped to findings, pass/fail status, evidence timestamps, assessor identity. Same data, different projections — no drift between views. The remediation library contains deterministic fixes for common issues. The approval gate is the load-bearing control: production findings are proposed only (the harness generates the fix, attaches it to the ticket, but does not apply it without human approval); non-production may auto-apply per policy. Tickets carry full context including attack-path membership so engineers can prioritize.
Type: Mermaid (flowchart) Purpose: Shows how cloud posture degrades silently between scheduled assessments, and why event-driven monitoring closes the gap.
flowchart LR
subgraph SCHEDULED["Scheduled-only monitor (the gap)"]
S1["Assess Day 1<br/>posture: clean"]
DRIFT1["Day 2: console change<br/>opens SG port"]
DRIFT2["Day 3: permission creep<br/>role gains policy"]
DRIFT3["Day 4: ephemeral Lambda<br/>debug auth disabled"]
BREACH["Day 5: exploited<br/>breach via open path"]
S2["Assess Day 7<br/>posture: breached"]
S1 -.-> DRIFT1 -.-> DRIFT2 -.-> DRIFT3 -.-> BREACH -.-> S2
end
subgraph EVENT["Event-driven monitor (the fix)"]
E1["Day 2: SG change event<br/>→ re-assess in seconds<br/>→ alert + remediate"]
E2["Day 3: IAM event<br/>→ re-assess<br/>→ catch privilege creep"]
E3["Day 4: Lambda deploy<br/>→ re-assess<br/>→ flag debug auth"]
CLEAN["Posture stays clean<br/>drift caught at change time"]
E1 --> E2 --> E3 --> CLEAN
end
style SCHEDULED fill:#2a0d0d,stroke:#a00000,color:#f08080
style BREACH fill:#2a0d0d,stroke:#a00000,color:#f08080
style EVENT fill:#0d2818,stroke:#1e8449,color:#82e0aa
style CLEAN fill:#0d2818,stroke:#1e8449,color:#82e0aa
style DRIFT1 fill:#2a1810,stroke:#a04000,color:#f0a868
style DRIFT2 fill:#2a1810,stroke:#a04000,color:#f0a868
style DRIFT3 fill:#2a1810,stroke:#a04000,color:#f0a868
Reading the diagram: The drift problem, top to bottom. The scheduled-only monitor (red, top) assesses on Day 1 and Day 7. Between them, posture degrades silently: Day 2 an engineer opens a security group port via console and forgets to close it; Day 3 a role accumulates an extra policy (permission creep); Day 4 a Lambda deploys with debug auth disabled. None of these look like attacks — they are drift. By Day 5, the accumulated misconfigurations form an attack path that is exploited. The Day 7 assessment discovers the breach path that already led to a breach. The event-driven monitor (green, bottom) subscribes to the audit log. Each change event triggers a targeted re-assessment in seconds. The security group opening is caught and alerted at Day 2. The IAM change is assessed at Day 3. The Lambda deploy is flagged at Day 4. Drift is caught at change time, before it compounds into an exploitable path. The difference is latency: days (scheduled) vs seconds (event-driven).
Type: Mermaid (flowchart) Purpose: Shows the decision logic for the approval gate — when the harness proposes-only, when it applies, and why production always requires human approval.
flowchart TD
FIND["High-severity finding<br/>on active attack path"]
REMED["Generate remediation<br/>(deterministic fix from library)"]
ENV{"Environment?"}
PROD{"Production?"}
APPR{"Human approval<br/>received?"}
AUTO{"Policy allows<br/>auto-apply?"}
PROPOSE["PROPOSE ONLY<br/>attach fix to ticket<br/>do NOT apply<br/>wait for approval"]
APPLY["APPLY FIX<br/>evidence-logged<br/>rollback plan attached"]
BLOCK["BLOCKED<br/>fix not applied<br/>escalate to human"]
FIND --> REMED --> ENV
ENV -->|"production"| PROD
ENV -->|"staging/dev/sandbox"| AUTO
PROD -->|"no approver"| PROPOSE
PROD -->|"approver present"| APPR
APPR -->|"approved"| APPLY
APPR -->|"denied"| BLOCK
AUTO -->|"yes"| APPLY
AUTO -->|"no"| PROPOSE
style FIND fill:#14141f,stroke:#5eead4,color:#5eead4
style ENV fill:#14141f,stroke:#5eead4,color:#5eead4
style PROPOSE fill:#2a1810,stroke:#a04000,color:#f0a868
style APPLY fill:#0d2818,stroke:#1e8449,color:#82e0aa
style BLOCK fill:#2a0d0d,stroke:#a00000,color:#f08080
style PROD fill:#14141f,stroke:#5eead4,color:#5eead4
style APPR fill:#14141f,stroke:#5eead4,color:#5eead4
style AUTO fill:#14141f,stroke:#5eead4,color:#5eead4
Reading the diagram: A high-severity finding on an active attack path triggers remediation generation. The harness builds the deterministic fix from the remediation library. The approval gate is the decision point. In production, the harness proposes only — it generates the fix, attaches it to a ticket with full context, and waits for human approval. No approver means no application, full stop. The approver (a human with the required role) reviews and either approves (the fix is applied, evidence-logged, with a rollback plan attached) or denies (blocked, escalated). In non-production (staging, dev, sandbox), the policy may allow auto-apply — the fix is applied directly if the policy permits, still evidence-logged and with a rollback plan. The load-bearing rule: production and no approver equals propose-only. Automated remediation that breaks production is worse than the misconfiguration it fixes.
# Diagrams — Module S09: Cloud Posture Harnesses
> All Mermaid validated in Mermaid Live Editor. n8n JSON is structurally valid and importable.
---
## Diagram 1 — Cloud Asset Discovery Harness (n8n)
**Type**: n8n workflow (importable JSON)
**Purpose**: The primary visual — the full discovery harness from provider APIs through normalization, AI-workload tagging, reconciliation, and output to the asset graph.
```json
{
"name": "S09 — Cloud Asset Discovery Harness",
"nodes": [
{ "name": "Provider APIs", "type": "n8n-nodes-base.manualTrigger", "position": [200, 300], "notes": "AWS Security Hub + Config, Azure Resource Graph, GCP SCC" },
{ "name": "AWS Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 150], "notes": "Enumerate resources via AWS Config + Security Hub findings" },
{ "name": "Azure Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 280], "notes": "Resource Graph Kusto query across subscription" },
{ "name": "GCP Discovery", "type": "n8n-nodes-base.executeCommand", "position": [440, 410], "notes": "SCC asset list + findings" },
{ "name": "Normalize to CloudAsset", "type": "n8n-nodes-base.set", "position": [680, 300], "notes": "All resources → unified schema. Provider-agnostic." },
{ "name": "AI Workload Tagging", "type": "n8n-nodes-base.set", "position": [920, 300], "notes": "Flag model endpoints, agents, vector DBs, embedding services. endpoint_publicly_reachable." },
{ "name": "Diff vs Last Inventory", "type": "n8n-nodes-base.set", "position": [1160, 300], "notes": "New/changed/deleted assets. Drift detection." },
{ "name": "New/Changed → Assess", "type": "n8n-nodes-base.set", "position": [1400, 200], "notes": "Run benchmark checks on changed resources only" },
{ "name": "Deleted → Mark Stale", "type": "n8n-nodes-base.set", "position": [1400, 400], "notes": "Remove from active graph, retain for audit" },
{ "name": "Asset Graph Store", "type": "n8n-nodes-base.set", "position": [1640, 300], "notes": "Updated graph. Feeds attack-path analysis (S09.2) and monitoring (S09.3)." }
],
"connections": {
"Provider APIs": { "main": [[{ "node": "AWS Discovery", "type": "main", "index": 0 }], [{ "node": "Azure Discovery", "type": "main", "index": 0 }], [{ "node": "GCP Discovery", "type": "main", "index": 0 }]] },
"AWS Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"Azure Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"GCP Discovery": { "main": [[{ "node": "Normalize to CloudAsset", "type": "main", "index": 0 }]] },
"Normalize to CloudAsset": { "main": [[{ "node": "AI Workload Tagging", "type": "main", "index": 0 }]] },
"AI Workload Tagging": { "main": [[{ "node": "Diff vs Last Inventory", "type": "main", "index": 0 }]] },
"Diff vs Last Inventory": { "main": [[{ "node": "New/Changed → Assess", "type": "main", "index": 0 }], [{ "node": "Deleted → Mark Stale", "type": "main", "index": 0 }]] },
"New/Changed → Assess": { "main": [[{ "node": "Asset Graph Store", "type": "main", "index": 0 }]] },
"Deleted → Mark Stale": { "main": [[{ "node": "Asset Graph Store", "type": "main", "index": 0 }]] }
}
}
```
**Reading the diagram**: Provider APIs fan out to three cloud-specific discovery nodes. Each enumerates resources natively — AWS via Config + Security Hub, Azure via Resource Graph, GCP via SCC. Results normalize to the unified CloudAsset schema regardless of provider. AI Workload Tagging flags model endpoints, agent deployments, vector stores, and embedding services with the `endpoint_publicly_reachable` field that distinguishes internal tools from public attack surface. The diff against last-known inventory detects drift — new, changed, and deleted assets. New and changed assets get benchmark-assessed; deleted assets are marked stale and removed from the active graph. The output is a continuously-reconciled asset graph that feeds attack-path analysis and posture monitoring.
---
## Diagram 2 — Attack Path Analysis (Graph)
**Type**: Mermaid (flowchart)
**Purpose**: Shows the cloud attack surface as a graph, with paths from externally reachable entry points to sensitive data stores through IAM escalation and public-exposure chains.
```mermaid
flowchart LR
subgraph ENTRY["Entry points (publicly reachable)"]
API["Public API Gateway<br/>network_exposure: public"]
BUCKET["Public S3 Bucket<br/>is_public: true"]
MODEL["Public Model Endpoint<br/>AI asset, endpoint_publicly_reachable"]
end
subgraph MID["Internal resources"]
LAMBDA["Lambda Function<br/>assumes Role-A"]
ROLEA["IAM Role-A<br/>over-privileged<br/>can-write to DB"]
EC2["EC2 Instance<br/>in shared VPC"]
ROLEB["IAM Role-B<br/>can-read sensitive"]
end
subgraph TARGET["Sensitive targets (crown jewels)"]
DB["RDS Database<br/>data_classification: regulated"]
VDB["Vector Database<br/>sensitive embeddings"]
DATA["Training Data Store<br/>regulated dataset"]
end
API -->|"can-invoke"| LAMBDA
BUCKET -->|"public read"| MODEL
MODEL -->|"assumes"| ROLEA
LAMBDA -->|"assumes"| ROLEA
ROLEA -->|"can-write"| DB
ROLEA -->|"can-assume"| ROLEB
EC2 -->|"shared VPC"| ROLEB
ROLEB -->|"can-read"| DATA
ROLEB -->|"can-query"| VDB
style ENTRY fill:#2a1810,stroke:#a04000,color:#f0a868
style TARGET fill:#2a0d0d,stroke:#a00000,color:#f08080
style ROLEA fill:#14141f,stroke:#5eead4,color:#5eead4
style ROLEB fill:#14141f,stroke:#5eead4,color:#5eead4
style API fill:#2a1810,stroke:#a04000,color:#f0a868
style BUCKET fill:#2a1810,stroke:#a04000,color:#f0a868
style MODEL fill:#2a1810,stroke:#a04000,color:#f0a868
style DB fill:#2a0d0d,stroke:#a00000,color:#f08080
style VDB fill:#2a0d0d,stroke:#a00000,color:#f08080
style DATA fill:#2a0d0d,stroke:#a00000,color:#f08080
```
**Reading the diagram**: The attack surface is a graph. Entry points (orange, left) are publicly reachable assets — a public API Gateway, a public S3 bucket, a public model endpoint. Internal resources (center) are connected by access relationships. The arrows are edges: can-invoke, can-assume, can-read, can-write. Sensitive targets (red, right) hold regulated data — the RDS database, the vector database with sensitive embeddings, the training data store. The attack paths are traversals from entry to target. Path one: Public API Gateway → Lambda → Role-A → RDS Database. Path two: Public Model Endpoint → Role-A → Role-B → Training Data Store. The harness finds all such paths via BFS and scores them. A three-hop path to regulated data scores higher than a five-hop path to internal docs. Fixing one node on a critical path (e.g., removing an over-permissive trust from Role-A) breaks every path through it.
---
## Diagram 3 — Continuous Posture Monitoring Loop
**Type**: Mermaid (flowchart)
**Purpose**: Shows the event-driven monitoring loop — CloudTrail/Activity Log events trigger targeted re-assessment of changed resources, not full-estate scans.
```mermaid
flowchart TD
EVENTS["Cloud Audit Log stream<br/>CloudTrail / Activity Log / Cloud Audit Logs"]
FILTER{"Security-relevant<br/>event?"}
FETCH["Re-fetch changed<br/>resource state"]
ASSESS["Assess against<br/>CIS benchmark controls"]
GRAPH["Update attack graph<br/>(may add/remove paths)"]
SCORE["Score finding:<br/>exploitability × impact × reachability"]
ROUTE{"Route by severity"}
CRITICAL["CRITICAL<br/>on active attack path<br/>→ page immediately"]
MEDIUM["MEDIUM<br/>→ daily report batch"]
LOW["LOW<br/>→ weekly posture review"]
NOOP["Not security-relevant<br/>→ log only, no re-assessment"]
EVENTS --> FILTER
FILTER -->|"yes: IAM/S3/EC2/AI change"| FETCH
FILTER -->|"no"| NOOP
FETCH --> ASSESS
ASSESS --> GRAPH
GRAPH --> SCORE
SCORE --> ROUTE
ROUTE --> CRITICAL
ROUTE --> MEDIUM
ROUTE --> LOW
style EVENTS fill:#2a1810,stroke:#a04000,color:#f0a868
style FILTER fill:#14141f,stroke:#5eead4,color:#5eead4
style SCORE fill:#14141f,stroke:#5eead4,color:#5eead4
style CRITICAL fill:#2a0d0d,stroke:#a00000,color:#f08080
style MEDIUM fill:#2a1810,stroke:#a04000,color:#f0a868
style LOW fill:#0d2818,stroke:#1e8449,color:#82e0aa
style NOOP fill:#1a1a24,stroke:#5a5a68,color:#5a5a68
```
**Reading the diagram**: The monitoring loop is event-driven, not scheduled. The cloud audit log stream (CloudTrail on AWS, Activity Log on Azure, Cloud Audit Logs on GCP) feeds every API call. The filter checks whether the event is security-relevant — IAM changes (AttachRolePolicy, AssumeRole), public exposure changes (PutBucketAcl, AuthorizeSecurityGroupIngress), AI workload changes (CreateEndpoint, CreateAgent). Security-relevant events trigger a targeted re-fetch of the changed resource's current state, a benchmark assessment, and an attack-graph update that may add or remove paths. Findings are scored by exploitability (is the resource on an active path?), impact (what data class?), and reachability (is it publicly exposed?). Critical findings on active attack paths page immediately. Medium findings batch into the daily report. Low findings accumulate for the weekly review. Non-security-relevant events are logged but do not trigger re-assessment — the loop is efficient, not exhaustive.
---
## Diagram 4 — Multi-Audience Reporting Pipeline
**Type**: Mermaid (flowchart)
**Purpose**: Shows how one finding store produces three report views — engineer, CISO, auditor — plus the remediation workflow with the approval gate.
```mermaid
flowchart LR
STORE["Unified Finding Store<br/>(findings + attack paths<br/>+ asset graph + history)"]
subgraph REPORTS["Multi-audience reports"]
ENG["Engineer Report<br/>per-finding: ARN, control,<br/>current vs expected,<br/>remediation command"]
CISO["CISO Report<br/>risk score, trend,<br/>top 5 attack paths,<br/>business-impact framing"]
AUDIT["Auditor Report<br/>control → finding map,<br/>pass/fail, evidence TS,<br/>assessor identity"]
end
REMED["Remediation Library<br/>deterministic fixes:<br/>public bucket, open SG,<br/>missing encryption"]
GATE{"Approval Gate"}
PROD["Production<br/>→ propose only<br/>(human must approve)"]
NONPROD["Staging/Dev<br/>→ auto-apply<br/>per policy"]
TICKET["Ticketing System<br/>(JIRA/Linear)<br/>with full context"]
STORE --> ENG
STORE --> CISO
STORE --> AUDIT
STORE --> REMED
REMED --> GATE
GATE -->|"production"| PROD
GATE -->|"non-prod"| NONPROD
PROD --> TICKET
NONPROD --> TICKET
style STORE fill:#14141f,stroke:#5eead4,color:#5eead4
style REPORTS fill:#0d1418,stroke:#1e8449,color:#82e0aa
style GATE fill:#14141f,stroke:#5eead4,color:#5eead4
style PROD fill:#2a0d0d,stroke:#a00000,color:#f08080
style NONPROD fill:#0d2818,stroke:#1e8449,color:#82e0aa
```
**Reading the diagram**: One finding store, three report views. The engineer report projects per-finding detail: resource ARN, violated control, current vs expected configuration, the exact remediation command. The CISO report projects the executive view: overall risk score, trend over time, the top 5 attack paths, business-impact framing — answering "are we getting better or worse, and what matters this week." The auditor report projects compliance evidence: each control mapped to findings, pass/fail status, evidence timestamps, assessor identity. Same data, different projections — no drift between views. The remediation library contains deterministic fixes for common issues. The approval gate is the load-bearing control: production findings are proposed only (the harness generates the fix, attaches it to the ticket, but does not apply it without human approval); non-production may auto-apply per policy. Tickets carry full context including attack-path membership so engineers can prioritize.
---
## Diagram 5 — The Drift Problem (Posture Degradation Timeline)
**Type**: Mermaid (flowchart)
**Purpose**: Shows how cloud posture degrades silently between scheduled assessments, and why event-driven monitoring closes the gap.
```mermaid
flowchart LR
subgraph SCHEDULED["Scheduled-only monitor (the gap)"]
S1["Assess Day 1<br/>posture: clean"]
DRIFT1["Day 2: console change<br/>opens SG port"]
DRIFT2["Day 3: permission creep<br/>role gains policy"]
DRIFT3["Day 4: ephemeral Lambda<br/>debug auth disabled"]
BREACH["Day 5: exploited<br/>breach via open path"]
S2["Assess Day 7<br/>posture: breached"]
S1 -.-> DRIFT1 -.-> DRIFT2 -.-> DRIFT3 -.-> BREACH -.-> S2
end
subgraph EVENT["Event-driven monitor (the fix)"]
E1["Day 2: SG change event<br/>→ re-assess in seconds<br/>→ alert + remediate"]
E2["Day 3: IAM event<br/>→ re-assess<br/>→ catch privilege creep"]
E3["Day 4: Lambda deploy<br/>→ re-assess<br/>→ flag debug auth"]
CLEAN["Posture stays clean<br/>drift caught at change time"]
E1 --> E2 --> E3 --> CLEAN
end
style SCHEDULED fill:#2a0d0d,stroke:#a00000,color:#f08080
style BREACH fill:#2a0d0d,stroke:#a00000,color:#f08080
style EVENT fill:#0d2818,stroke:#1e8449,color:#82e0aa
style CLEAN fill:#0d2818,stroke:#1e8449,color:#82e0aa
style DRIFT1 fill:#2a1810,stroke:#a04000,color:#f0a868
style DRIFT2 fill:#2a1810,stroke:#a04000,color:#f0a868
style DRIFT3 fill:#2a1810,stroke:#a04000,color:#f0a868
```
**Reading the diagram**: The drift problem, top to bottom. The scheduled-only monitor (red, top) assesses on Day 1 and Day 7. Between them, posture degrades silently: Day 2 an engineer opens a security group port via console and forgets to close it; Day 3 a role accumulates an extra policy (permission creep); Day 4 a Lambda deploys with debug auth disabled. None of these look like attacks — they are drift. By Day 5, the accumulated misconfigurations form an attack path that is exploited. The Day 7 assessment discovers the breach path that already led to a breach. The event-driven monitor (green, bottom) subscribes to the audit log. Each change event triggers a targeted re-assessment in seconds. The security group opening is caught and alerted at Day 2. The IAM change is assessed at Day 3. The Lambda deploy is flagged at Day 4. Drift is caught at change time, before it compounds into an exploitable path. The difference is latency: days (scheduled) vs seconds (event-driven).
---
## Diagram 6 — Remediation Approval Gate Logic
**Type**: Mermaid (flowchart)
**Purpose**: Shows the decision logic for the approval gate — when the harness proposes-only, when it applies, and why production always requires human approval.
```mermaid
flowchart TD
FIND["High-severity finding<br/>on active attack path"]
REMED["Generate remediation<br/>(deterministic fix from library)"]
ENV{"Environment?"}
PROD{"Production?"}
APPR{"Human approval<br/>received?"}
AUTO{"Policy allows<br/>auto-apply?"}
PROPOSE["PROPOSE ONLY<br/>attach fix to ticket<br/>do NOT apply<br/>wait for approval"]
APPLY["APPLY FIX<br/>evidence-logged<br/>rollback plan attached"]
BLOCK["BLOCKED<br/>fix not applied<br/>escalate to human"]
FIND --> REMED --> ENV
ENV -->|"production"| PROD
ENV -->|"staging/dev/sandbox"| AUTO
PROD -->|"no approver"| PROPOSE
PROD -->|"approver present"| APPR
APPR -->|"approved"| APPLY
APPR -->|"denied"| BLOCK
AUTO -->|"yes"| APPLY
AUTO -->|"no"| PROPOSE
style FIND fill:#14141f,stroke:#5eead4,color:#5eead4
style ENV fill:#14141f,stroke:#5eead4,color:#5eead4
style PROPOSE fill:#2a1810,stroke:#a04000,color:#f0a868
style APPLY fill:#0d2818,stroke:#1e8449,color:#82e0aa
style BLOCK fill:#2a0d0d,stroke:#a00000,color:#f08080
style PROD fill:#14141f,stroke:#5eead4,color:#5eead4
style APPR fill:#14141f,stroke:#5eead4,color:#5eead4
style AUTO fill:#14141f,stroke:#5eead4,color:#5eead4
```
**Reading the diagram**: A high-severity finding on an active attack path triggers remediation generation. The harness builds the deterministic fix from the remediation library. The approval gate is the decision point. In production, the harness proposes only — it generates the fix, attaches it to a ticket with full context, and waits for human approval. No approver means no application, full stop. The approver (a human with the required role) reviews and either approves (the fix is applied, evidence-logged, with a rollback plan attached) or denies (blocked, escalated). In non-production (staging, dev, sandbox), the policy may allow auto-apply — the fix is applied directly if the policy permits, still evidence-logged and with a rollback plan. The load-bearing rule: production and no approver equals propose-only. Automated remediation that breaks production is worse than the misconfiguration it fixes.