Surface Scan - baeziy/AWSault GitHub Wiki
Surface Scan
The surface scan is Phase 1 of AWSault. It runs by default (no flags needed) and is the foundation for everything else.
What it does
AWSault fires read-only, parameterless API calls (List, Get, Describe) across 120+ AWS services and records which ones succeed vs. which ones get denied. Think of it as a bulk permission check.
# run a surface scan
awsault
# surface scan with specific services only
awsault --services iam,s3,ec2,lambda
# surface scan across all regions
awsault --all-regions
How it works
Execution flow
- Load the service registry — 120+ services, 500+ API calls
- Filter to requested services (if
--servicesis used) - Spin up a thread pool (default 10 threads, configurable with
--threads) - Fire every API call concurrently
- Classify each response as OK, DENIED, or ERROR
- Save results to
~/.awsault/last_scan.json - Display summary table
Concurrency
Each API call runs as a separate task in a ThreadPoolExecutor. The default is 10 concurrent threads. Increase for faster scans on high-bandwidth connections:
awsault --threads 20
Pagination
For API calls that support pagination (e.g., list_users can return thousands of users), AWSault uses boto3's built-in paginators. It collects all pages before reporting the total count.
If a paginator isn't available for a given API, it falls back to a direct call.
Error classification
| Status | What it means | Examples |
|---|---|---|
| OK | Call succeeded, data was returned | list_buckets returned 5 buckets |
| DENIED | Permission error — you don't have access | AccessDenied, UnauthorizedAccess, ForbiddenException |
| ERROR | Real failure unrelated to permissions | Network timeout, invalid region, service not available |
Denied error codes (classified as permission issues, not failures):
AccessDeniedAccessDeniedExceptionUnauthorizedAccessAuthorizationErrorUnauthorizedOperationForbiddenExceptionInvalidClientTokenIdAuthorizationException
Permissions vs resources
IAM permissions are region-independent. If an API call succeeds in us-east-1, it will succeed in every other region too. What changes across regions is which resources exist (instances, snapshots, buckets, etc.).
The surface scan checks permissions, so it only needs to run once regardless of how many regions you're scanning. The --all-regions flag affects deep enumeration (Phase 2+), which checks each region for actual resources.
When --all-regions is used, AWSault:
- Runs the surface scan once to map permissions (since they're the same everywhere)
- Runs deep enumeration, security audit, and loot extraction per-region to discover resources
- Shows combined findings across all regions at the end
Output
The surface scan produces a table showing each service with:
- Service name (uppercase)
- OK count — how many API calls succeeded
- Denied count — how many were blocked by IAM
- Error count — how many had non-permission errors
- Total calls — total API calls attempted
Services with at least one OK call are highlighted — these are your entry points for deeper enumeration. After the scan, AWSault also generates Suggested Next Steps with ready-to-copy AWS CLI commands for every service that returned OK.
Verbose mode
awsault --verbose
With --verbose, AWSault prints the actual API response data for each successful call during the scan. Useful for quick manual inspection without needing --show.
Data persistence
Results are automatically saved to ~/.awsault/last_scan.json. This allows you to:
- Browse results later with
--show(see Browsing Results) - Export to different formats with
--output(see Output Formats) - Skip rescanning when you just want to look at old data
What happens next
If you ran with --godeep, the surface scan results feed into:
- Deep Enumeration — pulls detailed configs for discovered resources
- Security Audit — checks configs against security rules
- Loot Extraction — harvests secrets
- Identity Recon — maps your full permission set