# 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.
