DEV Community

Cover image for The script worked. The CISO needed something else. iam-audit v2: interactive dashboard, root account detection and Docker.
Gerardo Castro Arica for AWS Heroes

Posted on

The script worked. The CISO needed something else. iam-audit v2: interactive dashboard, root account detection and Docker.

From raw CSVs to a visual dashboard anyone can run with a single Docker command — and how each feature came from a real need.

The hook

The first script worked. It iterated through 20+ AWS accounts, assumed roles with minimum privilege, and produced two CSVs with everything you needed to know about Access Keys and remediation events. Technically correct. Complete. Useful.

But when the time came to share the results with the team, I realized something uncomfortable: a CSV is an answer for someone who knows how to ask the right questions. For everyone else, it's noise.

The engineer opens the CSV and sees data. The CISO opens the CSV and sees rows. It's the same file — but it's not the same experience.

That led me to a question that changed the direction of the project: what if findings could be viewed, filtered, and understood without opening a single spreadsheet?

The context

When you work in security in enterprise environments, you quickly learn that technical findings have two distinct lives. The first is the technical life — raw data, fields, values, dates. The second is the executive life — risk, impact, urgency. The problem is that most tools only speak one of those two languages.

A CSV speaks the first. And that's fine — for the CloudSec Engineer who needs to triage, filter by account, sort by key age, and export for a ticket. But for the CISO who needs to understand the security posture of the organization in 30 seconds, a CSV is a barrier, not an answer.

This tension isn't new. Commercial security tools have been solving it for years — CSPMs like Wiz or Prisma Cloud have polished executive dashboards. But not every team has budget for those platforms, and even less so in LATAM where many organizations are still building their security baseline.

With that clear, the next step was obvious: the data was already there. What was missing was the presentation layer — no cost, no external dependencies, no friction.

Feature 1: The dashboard

From data to visibility: the HTML dashboard

The decision to use pure HTML was intentional. I could have used Grafana, QuickSight, or any visualization tool — but they all have the same problem: they require infrastructure, configuration, or an account on some service. An HTML file requires nothing. You open it in any browser, on any machine, without installing anything.

The mechanism is simple: the script generates the CSVs as usual, but before finishing it embeds them directly inside the HTML as strings. The dashboard parses them in the browser with JavaScript and converts them into interactive widgets. No backend, no database, no dependencies — a single self-contained file.

An important warning: the generated HTML contains real data from your organization. Treat it with the same sensitivity as a CSV with account and user information — don't share it through unsecured channels, don't upload it to public repositories, and make sure the output/ directory is in your .gitignore. The script already handles this, but it's worth keeping in mind.

The dashboard has four main views:

  • Executive summary — total accounts audited, total Access Keys, active vs inactive keys, users without MFA
  • Risk scoring per user — automatic prioritization based on key age, active status, and absence of MFA
  • Remediation trend — CloudTrail events chart over time, to see if the team is actually remediating
  • Findings table — filterable by account, status, and risk level

The filters are global — when you filter by account, all widgets update simultaneously. That's what makes it useful for a presentation: you can show the status of a specific account in seconds, without exporting anything or switching tools.

Interactive dashboard generated by iam-audit v2

"Interactive dashboard generated by iam-audit v2"

Feature 2: Root account detection

The account everyone ignores: root account detection

There's a user in every AWS account that doesn't appear in any IAM Users listing. It doesn't have mandatory MFA by default. It generates no alerts if someone uses it. And it has unrestricted access to absolutely everything in the account. Unlike any other IAM user, its permissions cannot be reduced with identity policies — though certain actions can be restricted at the organizational level through SCPs. AWS Control Tower includes two specific preventive guardrails for this: one that prevents enabling Access Keys on the root account, and another that prevents executing actions as root. To detect whether MFA is enabled, there's also a detective guardrail — Detect Whether MFA for the Root User is Enabled — implemented via AWS Config Rule. However, none of these mechanisms give you consolidated visibility of root status across all your accounts in one place. That's exactly the gap this feature solves.

The AWS Security Maturity Model v2 is explicit about this. In its Phase 1 — Quick Wins, within the Identity and Access Management domain, one of the fundamental controls is Root Account Protection — ensuring the root account has active MFA, no active Access Keys, and that its usage is monitored. This isn't an advanced recommendation. It's baseline. It's the first thing you should have resolved before anything else.

Adding this control to the script was a logical decision: if you were already auditing IAM Users in each account, not auditing the root account meant leaving the most critical finding out of the report.

What the script audits per account:

  • MFA enabled — whether the root account has active MFA or not
  • Active Access Keys — whether any Access Key associated with root exists, which AWS explicitly recommends avoiding
  • Last login — cross-referenced with ConsoleLogin CloudTrail events filtered by root identity, to detect if anyone has used the root account recently

This last point is the most valuable for a CISO: it's not just knowing whether root has MFA — it's knowing whether someone used it in the last 90 days. That's what turns a technical finding into a real risk conversation.

Root account detection widget — MFA, Access Keys and last login per account

"Root account detection widget — MFA, Access Keys and last login per account"

Feature 3: Docker

One command. No installation required. That's what was missing.

The script was already auditing. The dashboard was already visualizing. But there was a step that remained an invisible barrier: to run it, you needed Python installed, boto3 installed, and the repo cloned. For a CloudSec Engineer that's trivial. For someone who wants to evaluate the tool quickly, or for a team that doesn't want to manage Python dependencies on their machines, that's enough friction to not even try.

Docker eliminates that friction entirely.

The decision to dockerize wasn't about technology — it was about accessibility. If the goal was to build something any team in LATAM could use regardless of their local stack, the image had to be the unit of distribution. Not the repo, not the requirements.txt, not the installation instructions. The image.

The result is this command:

docker run --rm \
  -v ~/.aws:/root/.aws \
  -v $(pwd)/output:/app/output \
  -p 8000:8000 \
  gerardokaztro/iam-audit \
  --profile YOUR-AWS-PROFILE \
  --role YOUR-AUDIT-ROLE
Enter fullscreen mode Exit fullscreen mode

That's it. Docker downloads the image from Docker Hub, mounts your local AWS credentials, runs the audit, generates the dashboard, and serves it at http://localhost:8000. When you're done, Ctrl+C and that's it — no residue, no dependencies installed on your machine.

Two design decisions worth mentioning:

The first is credential mounting. Instead of passing Access Keys as environment variables — which would be exactly the opposite of what the script audits — the container mounts the ~/.aws directory from your local machine. Your credentials are never hardcoded, never in the image, and expire if you use roles with aws sso login.

The second is the output volume. The output/ directory is mounted as an external volume, which means the generated files — CSVs and HTML dashboard — stay on your local machine even after the container is destroyed. Without a volume, you'd lose the reports when you hit Ctrl+C.

The image is published on Docker Hub at gerardokaztro/iam-audit and is built automatically from the Dockerfile in the repository.

From a terminal command to a dashboard in the browser

"From a terminal command to a dashboard in the browser"

The findings

What the dashboard shows when you run it in production

Running iam-audit v2 against the same AWS Organization from the first post produced something qualitatively different from the original CSV. Not because the data was different — but because the presentation completely changed the conversation.

The executive summary of the dashboard showed the state of the organization at a glance:

Finding Result
Accounts audited 20+ active accounts
Access Keys found Dozens
Oldest key Created in 2018 — active in production
Users without MFA + console access Dozens
Root accounts without MFA Several
Root accounts with active Access Keys None
Total execution time Minutes

The risk scoring widget was the most useful for prioritizing remediation. Seeing which users combined old key + no MFA + active console access — all in a single filterable view by account — is what turns a report into an action plan.

Executive dashboard view — organization status at a glance

"Risk scoring per user — automatic findings prioritization"

The root account widget had the biggest impact for the executive conversation. Not because there were critical findings in every account — but because for the first time there was an immediate visual answer to the question: what's the root status across the entire organization? Before this feature, that question had no consolidated answer.

Root account status per account — MFA, Access Keys and last login

"Root account status per account — MFA, Access Keys and last login"

The most striking data point wasn't technical — it was process-related. The remediation trend in CloudTrail showed that DeleteAccessKey events increased significantly after sharing the first report. The script didn't just find the problem — it created the mechanism to measure whether it was being solved.

Remediation trend via CloudTrail — DeleteAccessKey events increased after the first report

"Remediation trend via CloudTrail — DeleteAccessKey events increased after the first report"

The closing

What I learned building this

That tools evolve when you use them in production with real people. The script from the first post was technically correct — but the reality of the field kept pushing it toward something more complete. The dashboard was born because a CSV didn't communicate for all audiences. Root account detection was born because the ASMM required it and no one had it solved in a consolidated way. Docker was born because accessibility matters as much as functionality.

None of those decisions came from a planned roadmap. They came from using the tool, listening to what was missing, and building the next layer.

That's exactly what I want to document in Road to CloudSec LATAM — not the polished final result, but the real process of iterative construction. The design decisions, the mistakes, the adjustments. Because that's what actually teaches.

If you want to run iam-audit v2 in your own AWS Organization, everything you need is in the repository. No cost, no additional infrastructure, no dependencies beyond Docker and an audit role with minimum privilege.

docker run --rm \
  -v ~/.aws:/root/.aws \
  -v $(pwd)/output:/app/output \
  -p 8000:8000 \
  gerardokaztro/iam-audit \
  --profile YOUR-AWS-PROFILE \
  --role YOUR-AUDIT-ROLE
Enter fullscreen mode Exit fullscreen mode

🔗 GitHub: github.com/gerardokaztro/iam-audit

If you run it, find something interesting, or have feedback — reach out. The CloudSec community in LATAM is built by sharing what works in real environments.

About the author

Gerardo Castro is an AWS Security Hero and Cloud Security Engineer focused on LATAM. He believes the best way to learn cloud security is by building real things — not memorizing frameworks. He writes about what he builds, what he finds, and what he learns along the way.

🔗 LinkedIn: linkedin.com/in/gerardokaztro
🔗 Blog: roadtocloudsec.la

Top comments (0)