Skip to content
wiki-sync[bot] edited this page Jul 23, 2026 · 1 revision

NWAF Agent — High-Level Design

Status: v1.0 · Last updated: 2026-07-23 Diagram: diagrams/nwaf-agent-hld.png (v2.3) · Decisions: adr/00010009 Governance: governance.md · Value: business-case.md

This is the narrative companion to the HLD diagram. It walks the components, the nightly execution sequence, the data flows and their classification, and the trust boundaries. It records what the architecture is; the ADRs record why each choice was made, and this document links to them rather than re-arguing.


1. Overview

The NWAF Agent is an autonomous nightly pipeline that reviews a single workload's Terraform (declared state) and live AWS account (actual state) against the AWS Well-Architected Framework, classifies drift, updates a Well-Architected Tool posture, and reports risk to the team.

Scope: single workload / account per run; the cross-account trust model (§6) makes fleet operation a matter of running the pipeline per target.

Guiding principle: deterministic where determinism exists; the LLM only for the reasoning nothing else can do. Detection is done by mature scanners; an LLM reconciles their output. Orchestration is code, not a model (ADR-0003).


2. Architecture at a glance

A code-orchestrated pipeline (buildspec) runs five phases inside one ephemeral compute boundary:

trigger → ① scan (live + code) → ② reconcile (LLM) → ③ score / write-back → ④ deliver

Everything between the phases is deterministic code; only phase ② uses the LLM, and it consumes structured findings, not raw configuration.


3. Components

Component Responsibility Tech ADR
Trigger Nightly kick-off, no orchestrator EventBridge Scheduler → CodeBuild StartBuild (direct target) 0001
Runtime Ephemeral pipeline host AWS CodeBuild project; image pins scanners + terraform CLI + Strands SDK 0001, 0004
① Live scanners Read-only detection of actual state Prowler · Steampipe/Powerpipe (WA/Thrifty) · Compute Optimizer 0004
① Code scanners Detection of declared state Checkov (SARIF) · Infracost · (+ tfstate) 0004
Finding normaliser Uniform record across tools canonical {pillar, resource, check_id, source, origin, severity, evidence} 0004
② Reconcile Correlate live vs code, classify drift, map to pillars, prioritise, draft remediation, answer judgment items Claude via provider layer (Bedrock default), bounded structured output 0002, 0003
WA reference Supply WA criteria to Reconcile bundled, versioned local index — no vector DB 0005
③ Scorer / write-back Update WA posture, extract risk counts, generate report UpdateAnswer + CreateMilestone to a dedicated automation workload 0006
Delivery Fan-out notification + tracked work S3 (full report) + SNS → Slack / Jira / Email adapters 0009

Inputs: Git repo (Terraform HCL, the CodeBuild source), S3 (tfstate), the live AWS environment (read-only). Outputs: the dedicated WA-Tool workload, S3 logs/report, and the delivery channels.


4. Execution sequence (one nightly run)

  1. Trigger. At 23:00 the EventBridge Scheduler invokes StartBuild directly — no orchestrator Lambda (ADR-0001).
  2. Hydrate. CodeBuild natively clones the Git source (HCL); the code-scan stage pulls tfstate from S3. Live scanning assumes the cross-account read-only role (ADR-0007).
  3. ① Scan (deterministic). Live scanners assess the running account; code scanners assess the HCL/tfstate. Each emits structured findings, normalised to the canonical schema.
  4. ② Reconcile (bounded LLM). Claude consumes the findings (not raw config), queries the bundled WA reference for criteria, and:
    • classifies drift — code + matching live → code-origin HRI; live-only → out-of-band drift; code-only → not-yet-applied;
    • maps findings to WA pillars/questions, dedupes, prioritises, drafts remediation, and reasons over the judgment items no scanner covers (labelled as judgment, per ADR-0004).
  5. ③ Score / write-back. The Scorer writes scanner-backed answers to the dedicated automation workload, records a milestone, and reads back AWS's authoritative HRI/MRI counts. Judgment items are proposed, not written (ADR-0006). If advisory_pr mode is on, a draft PR is opened for scanner-backed fixes only — never merged (ADR-0008).
  6. ④ Deliver. The full report goes to S3; a thin summary + link is published to SNS; adapters route to Slack (digest), Jira (idempotent tickets), and Email (ADR-0009). The container terminates.

5. Data flows & classification

Data Classification Handling
Terraform HCL (Git) internal cloned as build source; read-only
tfstate (S3) sensitive (may contain secrets) read via a scoped role + one KMS key; encrypted at rest (0007)
Live account config sensitive (topology, security posture) control-plane reads only — explicit data-plane deny; values never read (0007)
Scanner findings internal normalised; the only thing the LLM sees
LLM prompts/responses contains sensitive context in-region Bedrock, not used for training, PrivateLink (0002)
Report / logs internal S3 (encrypted); thin link over SNS

The LLM never receives raw secrets or object/secret values — it reasons over config-level findings. Sensitive data stays in-region and inside the AWS trust boundary end-to-end.


6. Trust boundaries & identity

  • Two accounts (general case): a tooling account runs the pipeline; each target workload lives in its own account. Single-account is the degenerate case.
  • Cross-account access is via sts:AssumeRole into a read-only role deployed in each target account (trust = tooling role + ExternalId), so the agent is structurally incapable of writing to the reviewed account.
  • Per-stage roles: the CodeBuild base role is near-empty; each phase assumes only its scope (scan = read-only; reconcile = Bedrock invoke only; scorer = WA-write to the automation workload + SNS + S3). A prompt-injection in Reconcile cannot reach scan or write credentials — they never exist in that stage.
  • No long-lived credentials anywhere; all STS-temporary, capped to the build.

See ADR-0007 for the full identity model; governance.md §7 for the AI-security controls this enables.


7. Cross-cutting concerns

Detailed in governance.md; summarised here:

  • Reproducibility — deterministic pipeline + versioned reference; same inputs → same review (0003, 0005).
  • Least-privilege — read-anything / write-nothing in the target; single write scope, single stage (0006, 0007).
  • Responsible AI — deterministic detection; judgment labelled; no invented findings; no fabricated "fixed" status; human disposition (0004, 0008).
  • Portability — provider layer keeps the LLM swappable on a per-run flag (0002).
  • Cost — pay-per-run compute, no always-on tier (0001, 0005).

8. Assumptions & constraints

  • The target account owner deploys the read-only role (via StackSet/IaC).
  • The dedicated WA-Tool automation workload is provisioned out-of-band (IaC), so the agent's runtime write scope stays minimal (ADR-0006).
  • Live scanning is control-plane only — no VPC / data-plane access required (ADR-0001/0007).
  • Scanners cover Security/Cost and a config subset of Reliability/Ops; Performance Efficiency, process-side Operational Excellence, and Sustainability are judgment-assessed and labelled as such (ADR-0004).
  • Runtime ≤ CodeBuild's ceiling; the nightly cadence is non-urgent by design.

9. Known gaps & out of scope

  • Run-failure alerting is not yet designed — a failed nightly run is currently silent until the next success (tracked in governance.md §4; candidate follow-on ADR).
  • Runtime provider fallback (surviving a mid-run provider/region outage) is deferred (ADR-0002 revisit).
  • The agent does not remediate the environment (structural, ADR-0007); advisory_pr only proposes code changes for humans to merge.

10. References

  • Decision records: adr/0001adr/0009
  • Governance: governance.md · Business case: business-case.md
  • Diagram: diagrams/nwaf-agent-hld.png / .drawio (v2.3)

Clone this wiki locally