I built an inventory tool for AWS Organizations
👋 Hi, I’m @hpfpv ☁️ I’m a Cloud Infrastructure Architect | 8x AWS Certified 🚀 I build secure, scalable, and automated solutions on AWS using Terraform, CloudFormation, and CI/CD 📚 Always exploring hybrid cloud, serverless, and AI-driven architectures
Hi guys! So a few months ago I was helping out on a public-sector AWS Landing Zone, and one day the leadership team came to me with what sounded like a small request. They wanted one document that summarised the state of the cloud environment. Inventory, costs, security, all of it in one place.
I told them I'd have something by end of day. Optimistic.
I ended up flipping between different AWS consoles, exporting CSVs, pasting them into a workbook, and trying to reconcile numbers that never quite line up the way you want them to. By the time I had something half-decent it was already late afternoon, and I knew I'd be repeating the same exercise the next quarter. Probably the quarter after that too.
That's the kind of moment where you start thinking there has to be a tool for this. So I built one. It's a small Python module called aws-ri.
The recurring ask
That request wasn't a one-off, and that's what bothered me. The same kind of overview keeps coming back. Security reviews need what's compliant and what Trusted Advisor is flagging. FinOps reviews need cost broken down by account, region, and service.
The data is all there. AWS isn't hiding any of it. It's just spread across five separate consoles (Cost Explorer, Security Hub, Trusted Advisor, Config, and Resource Explorer), and each one is scoped per account or per service (unless you've things up corretly for your landing zone with delegated administrator accounts - which should be the case).
If you want one document at the end, somebody is doing the stitching by hand. Usually you.
Before writing any code, I looked at the obvious alternatives:
An AWS-native pipeline — Config Aggregator, the Cost and Usage Report, Athena, QuickSight. Solid stack. But it's standing infrastructure, a few days of setup, and another thing to keep running afterwards.
Commercial CMDB tools like CloudHealth, Apptio, or Spot. Good products. You'll probably spend more time on procurement than on the tool itself (remember, public sector).
CloudQuery or Steampipe. Open source, but they want a database and an ETL pipeline alongside.
Doing it by hand. Which is what I was already doing, and which is what had produced the document I wasn't proud of.
None of these is "install a Python module, run it, hand the Excel to leadership" That's the gap aws-ri fills.
aws-ri is a small Python CLI you run locally. You give it a config file pointing at your AWS Organization, run one command, and a few minutes later you get an Excel workbook with everything in one place.
The workbook covers:
Organization-wide inventory, pulled from AWS Config Aggregator or AWS Resource Explorer (you pick which one)
Costs broken down by account, region, and service over a configurable window
Security posture from Security Hub, Trusted Advisor, and Config compliance
Identity Center activity and organization policies
An executive dashboard sitting on top of the rest, with KPIs and charts
The command itself is:
aws-ri generate --access-config profiles.yaml
Here's the executive dashboard sheet of a generated workbook:
That's the whole interface. Nothing is deployed in your AWS accounts. You install aws-ri locally, run it when you need a fresh report, and the workbook is the only thing it produces.
The architecture
Let me walk through how it works.
The workbook
The output is one Excel file with a small set of focused sheets. They're not dashboards in the BI sense — they're spreadsheets you can open, share, archive, and diff against last month's run.
The executive summary sheet sits on top: metadata cards, the headline KPIs, and a few charts. The rest is split by domain.
The organizational units sheet shows the OU tree of your Organization with parent/child info and how many accounts sit in each branch. The accounts sheet gives you one row per account, with email, region coverage, total cost over the window, and a tag-compliance score.
The security posture sheet is the heaviest one. It covers Config compliance, the at-risk accounts and rules, Security Hub findings broken down by severity, and the open Trusted Advisor recommendations. The identity center sheet has one section per Identity Center instance with user and group counts and sampled permission-set assignments.
And finally the resource type sheets: a summary, plus an individual sheet for each of the top resource types in the org. That's where you go when someone asks "how many EC2 instances do we actually have?".
The data flow
Under the hood, aws-ri makes calls to a handful of AWS APIs and assembles the results into a single workbook. The calls are all read-only, parallelised where it makes sense, and the workbook itself is built with openpyxl.
Roughly in order:
AWS Organizations gives the list of accounts and the OU tree.
AWS Config Aggregator or AWS Resource Explorer gives the inventory: what resources exist, in which account and region. You pick one of the two when you set up your
profiles.yaml(more on that below).Cost Explorer gives the cost data, broken down by account, region, and service.
Security Hub, Trusted Advisor, and AWS Config give the posture data: findings, recommendations, compliance status.
IAM Identity Center gives the user, group, and permission-set view.
The takeaway from the diagram is what's not in it. There's no Lambda function, no central database, no IaC stack. aws-ri is just an API client running on your machine. The Excel file is the only durable artefact, and once the run is done, nothing keeps running afterwards.
The one interesting decision sits on the inventory line. AWS Config Aggregator and AWS Resource Explorer both answer the question "what's in my org?", but they get there very differently. aws-ri supports both, and which one you pick has real consequences. More on that in a minute.
Delegated admins and profiles.yaml
AWS Organizations of any real size don't run on one account. You usually have a Security Hub delegated admin, a Config delegated admin, a FinOps account, and so on. The IAM permissions to query each capability live in different accounts, intentionally.
A tool that assumes "one account, one profile" doesn't survive contact with that reality. So aws-ri reads a small YAML file that maps each capability to its own AWS profile, environment file, or set of inline credentials:
organizations:
profile: org-master # Org hierarchy + policies
inventory:
profile: config-admin # Config Aggregator OR Resource Explorer
resource_explorer_view: my-resource-explorer-view
posture:
env_file: ~/.aws/security-admin.env # Security Hub + Config compliance
costs:
env_file: ~/.aws/finops.env # Cost Explorer
Each capability gets independent credentials. A security team can review this one YAML file and know exactly which accounts the tool is allowed to touch.
One thing worth flagging: aws-ri does not call sts:AssumeRole itself. Credential resolution is fully delegated to boto3. If you give it a profile name, boto3 handles whatever the profile is configured to do (long-lived keys, SSO, role assumption via source_profile, and so on). The only STS call in the codebase is sts.get_caller_identity() for a sanity check at startup.
Two inventory backends
When I first put this together, the inventory came from AWS Config Aggregator only. A few days in, I wanted to also support AWS Resource Explorer for the orgs that already had it set up. I really didn't want to fork the rest of the pipeline to do that.
The codebase is organised along the lines of Domain-Driven Design: four bounded contexts (org, inventory, cost, posture), an application layer that defines ports, infrastructure adapters that implement those ports, and a CLI on top.
src/aws_ri/
├── domain/ # bounded contexts: org, inventory, cost, posture
├── application/ # use cases + ports (interfaces)
├── infrastructure/ # adapters: boto3 clients, Excel writers
└── cli/ # command-line entry point
The inventory bounded context exposes one port — "give me the resources in this org." The Config Aggregator adapter implements that port one way, the Resource Explorer adapter implements it another way, and the rest of the pipeline (cost, posture, the workbook writer) doesn't know which one is plugged in.
Adding the second backend was an afternoon of work, not a refactor. That's the practical payoff of bounded contexts: external services that overlap in capability can plug into the same hole without disturbing anything around them.
Which backend you should actually pick has real consequences, though. That's where the next section comes in.
Tradeoffs
aws-ri gives you a point-in-time snapshot, not a live dashboard. That's the central trade-off, and it's deliberate. For security reviews and monthly FinOps cycles, point-in-time is exactly what you want. The workbook becomes the artefact of the meeting. If you need a live view, the AWS-native pipeline I mentioned earlier is where you'd go instead.
Three things are worth being honest about:
AWS Config doesn't distinguish between live and deleted resources. When you query the aggregator you can get back resources that were deleted last week. Reports drift a bit on actual footprint as a result. Switching the inventory backend to Resource Explorer gives a fresher view but trades away some metadata Config carries. No free lunch yet on this one.
Security Hub gets heavy at org scale. A large Organization can hold thousands of findings per region, and a naïve "paginate everything" loop falls over quickly. There's a wire-level reason for that, and it's worth a short detour.
When you go over a per-region API rate limit, AWS doesn't fail silently. It returns an HTTP
429 Too Many Requestswith aRetry-Afterheader telling you how long to wait. The message is straightforward: slow down, you're over quota.What was breaking. aws-ri was paginating Security Hub findings in a tight loop, across several regions in parallel. In a large org, that hit the per-region rate limit fast, and every regional worker was retrying on the same schedule, so they kept tripping the limit together. boto3's default retry budget ran out before the run could stabilise, and collection runs died mid-way through.
What I changed :
Switched boto3 to standard retry mode with a higher max-attempts, so the client respects
Retry-After.Batched the pagination by severity instead of fetching everything in one go.
Kept parallelism across regions, but serialised the calls inside each region.
Why it worked. Jitter is the load-bearing piece. Plain exponential backoff doesn't help when many clients hit the same limit, because they all retry in sync and trip it again. The random jitter staggers them, which is what stabilises the run. The batching and per-region serialisation just reduce how often the limit gets hit in the first place.
Some services need richer per-service attributes. Generic resource attributes are thin for certain types — RDS-specific configuration, Lambda runtime details, that sort of thing. It's on the roadmap to add enrichment for the most-requested types, but for now the inventory is broad and shallow rather than deep.
Takeaways
A few things I'd take away from building this:
Read-only is a feature, not a constraint. It's also what made aws-ri easy to get past the security review. No mutating calls means a much shorter list of permissions to justify, and a lot less to argue about.
The delivery format is the gap. The AWS APIs are fine. What's missing for governance work isn't more data — it's one artefact you can hand to leadership and have them actually look at it.
A monthly report doesn't need a live dashboard. Live views are great until you need to archive a snapshot, diff it against last month, and email it to someone. Cadence is a real product requirement.
Delegated admin can't be an afterthought. Tools that assume "one account, one profile" don't survive first contact with a real Organization. Plan for that on day one.
Wrapping up
aws-ri sits in the same family of tools as Microsoft's Azure Resource Inventory — a small thing you run on demand to get one good document out of a multi-account environment. If you do AWS governance, FinOps, or security reviews and you keep hitting the same "give me one document" question, give it a try. The repo lives at https://github.com/hpfpv/aws-resource-inventory — install it, point it at your Organization, and let me know how it lands.
Feedback welcome. Issues, ideas, and PRs all read.