# AWS Inventory

> AWS Infrastructure Inventory — discovers all resources across configured regions and services, then generates a comprehensive Excel workbook with one sheet per service category. Supports full scan, category-based scan, quick scan, multi-region, configurable scope, and resource tagging. Use when the user says "inventory my AWS", "list all resources", "generate infrastructure report", "what's in my account", "export AWS resources to Excel", "full scan", "scan everything", "scan by category", or any request to discover and catalog AWS infrastructure.

- Skill: `aquavis12/aws-inventory` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add aquavis12/aws-inventory`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aquavis12/aws-inventory/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: aquavis12 (https://skillmd.com/u/aquavis12)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aquavis12/aws-inventory

---


# AWS Infrastructure Inventory

Ported from the `power-aws-inventory` Kiro Power (github.com/aquavis12/power-aws-inventory). Same 109-category scan logic and Excel output — adapted here to run over the Bash tool and AWS CLI/boto3 directly, since Claude Code doesn't need an MCP proxy for this: it already has native shell access.

## Step 1: Validate AWS Session

1. Run `aws sts get-caller-identity` via Bash to confirm credentials.
2. Record **account ID**, **caller ARN**, and **default region**.
3. Report: "Authenticated as `<arn>` in account `<accountId>`"

**Profile handling**: If the default profile points to the wrong account, check `aws configure list-profiles`, verify with `aws sts get-caller-identity --profile <name>`, and ask the user which profile/region to use — pass `--profile` explicitly on every subsequent call rather than mutating their environment.

If credentials are expired, tell the user to re-authenticate (`aws sso login` or equivalent) and stop.

## Step 2: Configure Scope & Regions

Load `context-templates/inventory-scope.json` if the user has copied it into their workspace; otherwise ask:

| Setting | Options | Default |
|---------|---------|---------|
| Scan mode | `full` / `category` / `quick` | full |
| Region scope | `single` / `multi` / `all` | all |
| Include tags | yes / no | yes |
| Include cost data | yes / no (requires Cost Explorer) | no |
| Output dir | path | `./inventory-reports` |

**Region resolution:**
- `single` → use the specified region directly
- `multi` → validate via `aws ec2 describe-regions`, use the listed regions
- `all` → call `aws ec2 describe-regions` to discover all enabled regions, then **exclude** `me-south-1` and `me-central-1` (Bahrain/Dubai — historically outage-prone for this power; skip unless the user explicitly asks to include them)

Global services (IAM, S3, Route53, CloudFront, Organizations, Shield, GlobalAccelerator, TrustedAdvisor, HealthDashboard, Cost Management) always scan once regardless of region scope.

**Category-based scanning** (`category` mode): user can specify groups ("Scan all Security services"), individual services ("Scan EC2 and RDS"), or mixed. See `references/inventory-workflow.md` for the full category groupings.

Present the scope summary and confirm before proceeding on any `full` or `all`-region scan — these can take 10-20 minutes and make hundreds of API calls.

## Step 3: Execute Inventory Scan

Full per-service API call reference: `references/inventory-workflow.md` (all 109 categories, exact operations and columns).

**Execution approach:**
- Use the Bash tool to call AWS CLI (`--output json`) or a small boto3 script per service.
- For multi-region scans, batch regions (e.g. 8-10 at a time in a single Python/boto3 script using `concurrent.futures` or a simple loop) rather than one Bash call per region — far fewer tool round-trips.
- Handle pagination fully: watch for `NextToken` / `Marker` / `IsTruncated` and keep paging. Never truncate results.
- Report progress as groups complete: "Scanning [Service] in [Region]... found N resources"

### Critical implementation notes (carried over from the original power)

| Service | Gotcha | Solution |
|---------|--------|----------|
| **S3** | `ListBuckets` has no region | Call `GetBucketLocation` per bucket. `null`/`None` = `us-east-1`. Batch to avoid throttling. |
| **ECS** | `ListClusters` returns ARNs only | Follow with `DescribeClusters(clusters=<arns>)` for details. |
| **EBS** | Attachment is nested | Access `Attachments[0].InstanceId`. State `available` = orphaned volume. |
| **EC2** | Instances nested in Reservations | Flatten `Reservations[].Instances[]`. Name comes from `Tags[?Key=='Name'].Value`. |
| **DynamoDB** | `ListTables` returns names only | Follow with `DescribeTable` per table for item count/size. |
| **EKS** | `ListClusters` returns names only | Follow with `DescribeCluster` per name for version/status/endpoint. |

### Handling errors

- **AccessDenied** → log in ScanNotes, continue — never fail the whole scan for one denied call.
- **No resources found** → skip that sheet (don't create an empty one).
- **Region unreachable / timeout** → note and continue with other regions.
- **Service not available in region** → note as `NOT_AVAILABLE`, continue.
- **Throttled** → back off 2-5s, retry up to 3 times.

## Step 4: Generate Excel Report

1. Write the collected data to `inventory-reports/inventory-data.json`.
2. Run `scripts/generate_excel.py --input inventory-reports/inventory-data.json --output inventory-reports/aws-inventory-<accountId>-<YYYYMMDD-HHMM>.xlsx` (requires `pip install openpyxl --break-system-packages` if not already present).
3. Delete the temp JSON after success.

Formatting rules (headers, colors, freeze panes, column widths): `references/excel-output.md`.

**File locking**: if the target file is open elsewhere, write to a new filename rather than failing.

**Completeness**: every sheet must contain every discovered resource — never sample or truncate.

## Step 5: Present Results

Report:
- Path to the Excel file
- Total resources discovered
- Top 5 categories by count
- Regions scanned
- Any errors or skipped services from ScanNotes

## Guardrails

- **Read-only, always.** Only ever call `List*`, `Describe*`, `Get*` operations. Never create, modify, tag, or delete any AWS resource under any circumstance in this skill.
- **No secrets in output** — mask any tag whose key contains "password", "secret", "key", "token", or "credential".
- **Environment variable values**: for Lambda/ECS/Batch, record only variable **names**, never values.
- **IAM policy documents**: capture name/ARN/attachment count only — never embed full policy JSON.
- **Secrets Manager / SSM SecureString**: metadata only (name, ARN, rotation status). Never call with decryption or `GetSecretValue`.
- **Output stays local** — everything lands in `inventory-reports/` on the user's machine; nothing is uploaded anywhere.
- **Complete pagination** — never truncate.

## Scan mode quick reference

| Mode | Categories scanned | Estimated time |
|------|--------------------|--------|
| `full` | All 109 | 5-15 min (all regions) |
| `category` | User-specified groups/services | Varies |
| `quick` | EC2, SGs, Lambda, ECS, EKS, S3, EBS, EFS, VPC, LBs, Route53, CloudFront | < 2 min |

## Large account strategy

For large accounts (many regions, 500+ resources), write incrementally instead of waiting for the full scan:
1. One workbook per category group as it finishes (`*-Compute.xlsx`, `*-Storage.xlsx`, etc.)
2. Generate a MASTER workbook at the end with every sheet plus Summary and ScanNotes.

Use this for `full` mode or `category` mode with 3+ groups; not needed for `quick`.

