Architecture - baeziy/AWSault GitHub Wiki

Architecture

Project structure

src/awsault/
β”œβ”€β”€ __init__.py                 version string
β”œβ”€β”€ __main__.py                 python -m awsault entry point
β”œβ”€β”€ cli.py                     CLI argument parsing, scan orchestration, terminal output
β”œβ”€β”€ services.py                service registry (120+ AWS services, 500+ API calls)
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ creds.py               credential loading, validation, region discovery
β”‚   β”œβ”€β”€ scanner.py             surface scan engine with concurrency and pagination
β”‚   └── store.py               local result persistence (~/.awsault/)
β”œβ”€β”€ recon/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ deep.py                deep enumeration chains (11) + privesc detection (14)
β”‚   β”œβ”€β”€ audit.py               security finding detection (16 rules)
β”‚   β”œβ”€β”€ loot.py                secret and credential extraction (7 sources)
β”‚   └── suggestions.py         context-aware next-step commands (240+ across 121 services)
└── output/
    β”œβ”€β”€ __init__.py
    └── formatters.py          JSON, CSV, and HTML export

Data flow

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚        cli.py            β”‚
                         β”‚   (argument parsing,     β”‚
                         β”‚    orchestration,         β”‚
                         β”‚    terminal output)       β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚             β”‚             β”‚
                    v             v             v
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚ creds.py β”‚  β”‚services.pyβ”‚  β”‚   store.py   β”‚
            β”‚          β”‚  β”‚           β”‚  β”‚              β”‚
            β”‚ load     β”‚  β”‚ service   β”‚  β”‚ save/load    β”‚
            β”‚ session  β”‚  β”‚ registry  β”‚  β”‚ last_scan    β”‚
            β”‚ validate β”‚  β”‚ API defs  β”‚  β”‚ .json        β”‚
            β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 β”‚              β”‚
                 v              v
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚      scanner.py       β”‚
            β”‚                       β”‚
            β”‚  ThreadPoolExecutor   β”‚
            β”‚  500+ API calls       β”‚
            β”‚  pagination           β”‚
            β”‚  error classification β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
                       β”‚ quick_results
                       β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚            β”‚                β”‚
          v            v                v
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ deep.py  β”‚ β”‚ audit.py β”‚   β”‚ loot.py  β”‚
    β”‚          β”‚ β”‚          β”‚   β”‚          β”‚
    β”‚ 11 chainsβ”‚ β”‚ 16 rules β”‚   β”‚ 7 sourcesβ”‚
    β”‚ privesc  β”‚ β”‚ findings β”‚   β”‚ secrets  β”‚
    β”‚ identity β”‚ β”‚          β”‚   β”‚          β”‚
    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
         β”‚            β”‚              β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      v
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚formatters.py β”‚
              β”‚              β”‚
              β”‚ JSON / CSV   β”‚
              β”‚ HTML report  β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Module responsibilities

cli.py β€” Orchestrator

The CLI is the only module that imports from all others. It:

  • Parses command-line arguments
  • Routes to the appropriate command handler (scan, show, export, list-services)
  • Orchestrates the 5-phase scan pipeline
  • Formats terminal output using the rich library
  • Builds the export payload and calls formatters
  • Generates suggested next steps from recon data

services.py β€” Service Registry

A pure data module. Contains the definition of every AWS service AWSault can scan:

  • Boto3 client name
  • Whether it's global or regional
  • List of API calls with method names, response keys, pagination support, and fixed parameters

No logic β€” just data. Adding a new service means adding a dict entry.

core/creds.py β€” Credential Manager

Wraps boto3 session creation and validation:

  • load_session() creates a boto3 Session with optional profile and region
  • validate() calls sts:GetCallerIdentity to confirm credentials work
  • get_enabled_regions() queries EC2 for the list of enabled regions

core/scanner.py β€” Surface Scanner

The concurrent scan engine:

  • Takes a dict of service targets from the service registry
  • Spins up a ThreadPoolExecutor
  • Fires each API call as a separate task
  • Handles pagination via boto3 paginators
  • Classifies errors (denied vs. real errors)
  • Returns structured results per service

core/store.py β€” Persistence

Simple file-based storage:

  • Saves scan results as JSON to ~/.awsault/last_scan.json
  • Loads previous results for --show and --output
  • Handles the ~/.awsault/ directory creation

recon/deep.py β€” Deep Enumerator

Contains 11 enumeration chains plus the identity recon engine:

  • Each chain is a function taking (session, quick_results) and returning enriched data
  • Chains run in parallel via ThreadPoolExecutor
  • The chain_iam_self chain is the most complex β€” it builds the full identity permission map and runs privilege escalation detection
  • Contains the _PRIVESC_TECHNIQUES registry and _detect_privesc() scanner

recon/audit.py β€” Security Auditor

Contains 16 detection rules:

  • Each rule is a function taking (quick_results, deep_results, findings_list)
  • Rules append Finding objects with severity, service, resource, title, detail, and recommendation
  • run_audit() runs all rules and returns findings sorted by severity

recon/loot.py β€” Loot Extractor

Contains 7 extraction functions:

  • Each function takes a boto3 session and returns a list of extracted items
  • Functions run in parallel via ThreadPoolExecutor
  • Returns a dict mapping source names to item lists

output/formatters.py β€” Report Generator

Three export functions:

  • save_json() β€” full JSON dump
  • save_csv() β€” flat CSV with section headers
  • save_html() β€” self-contained HTML with embedded CSS/JS, dark theme, interactive tabs

Key design decisions

Decoupled formatters

Formatters accept plain dicts, not internal objects. This keeps them independent of the scanner's data structures.

Parallel everything

Surface scan, deep chains, and loot extractors all run in thread pools. Each task is independent β€” one failure doesn't block others.

Read-only by default

All API calls are read-only. The only "active" calls are GetSecretValue and GetParameter in loot mode, which read (not write) data.

No external services

AWSault makes no network calls except to AWS APIs. No telemetry, no update checks, no phone home.

Single-file HTML

The HTML report is completely self-contained β€” CSS and JavaScript are inline. No CDN dependencies, no external assets. Works offline.

Adding new components

See Extending AWSault for step-by-step guides on adding:

  • New services to the registry
  • New deep enumeration chains
  • New security audit rules
  • New loot extraction sources