AWSHound — AWS BloodHound OpenGraph Collector
AWSHound is a Go CLI/container tool that collects AWS IAM and authorization data across profiles, config-file opt-ins, or an entire AWS Organization (via cross-account role assumption), and outputs a BloodHound OpenGraph for attack-path analysis. It supports phased collection with on-disk artifacts, offline graph building from previously collected data, and safeguards like --max-api-requests and --max-api-requests-per-minute to bound AWS API traffic during collection.
What it is
AWSHound is a Go collector (cmd/awshound, also published as ghcr.io/awshound/awshound:latest) that gathers AWS IAM/authorization data and emits a BloodHound OpenGraph JSON. Collection is split into three phases exposed as standalone subcommands (with on-disk artifacts between them) or as a single all run.
How it works
Live collection (collect/all) picks target accounts from at least one source, which can be combined and are de-duplicated:
--profile— one or more named CLI profiles (repeatable or comma-separated); credentials resolve through the normal AWS chain (shared config/credentials, SSO, assumed roles).--aws-config— collects every profile in a config file whose section carriesbloodhound_collect = true, so the collection set lives in the config rather than in flags.--org-role ROLE— org-wide collection. The base identity must enumerate the org; AWSHound callssts:GetCallerIdentity+organizations:ListAccounts, collects the management account directly, then assumesarn:aws:iam::<account-id>:role/ROLEinto each child.ROLEhas no default — passOrganizationAccountAccessRoleor your own audit role. Child accounts whose role can't be assumed are logged and skipped; the run still produces a graph.
Regions auto-discover per account unless narrowed with --regions.
What to do
Rate-limit safeguards matter in authorized/shared environments — both count retries, both default to unlimited (0):
awshound collect --profile prod --metrics metrics.json \
--max-api-requests 20000 \
--max-api-requests-per-minute 600--max-api-requests stops with non-zero status before exceeding the total, writing the report with awsApi.limitExceeded: true. --max-api-requests-per-minute instead throttles to that many attempt-starts per rolling 60-second window.
Build offline from prior data without touching AWS:
awshound all --input-dir raw/ -o graph.json
awshound all --gaad auth-details.json -o graph.jsonUse --metrics <path> to record per-service/operation API activity (attempts, retries, throttles, limiter wait time, latency).
Caveats
- These limits govern only this process's aggregate traffic. AWS quotas are scoped by service/operation/account/region and shared with other workloads, so pick a conservative value for the authorized environment.
--max-concurrencyis a worker bound, not an API request-rate limit.- An "attempt" is one admitted SDK HTTP send — paginator pages, retries, redirects, and per-account/region calls count separately; a local transport failure conservatively consumes a budget slot even if AWS never processed it.
- On a
--max-api-requestscancellation, raw files already written remain usable with--resume, but the active account batch is not marked complete.
Technologies named here
Techniques named here
- Live AWS collection via CLI profiles
- Config-based profile opt-in collection
- Organization-wide role assumption collection
- Region-scoped collection restriction
- API request metrics tracking
- Offline graph building from prior artifacts
Related in Cloud & Infra


Orca Security: GenAI Risks in Cloud Environments
.png)
Google API keys keep working after you delete them
