Skip to content

A fast, comprehensive tool for mapping and inventorying AWS resources across 150+ services and all regions.

License

Notifications You must be signed in to change notification settings

sonatype/awsmap

 
 

Repository files navigation

AWS Inventory Tool

PyPI version Downloads Docker Docker Pulls License: MIT Python 3.8+ AWS Services

awsmap

A fast, comprehensive tool for mapping and inventorying AWS resources across 150+ services and all regions.

Features

  • 150+ AWS Services: Covers compute, storage, database, networking, security, and more
  • Multi-Region: Parallel scanning across all enabled regions
  • Local Database: Every scan auto-stored in SQLite — query your inventory offline
  • SQL Query Engine: Run SQL against your inventory history (awsmap query "SELECT ...")
  • Pre-Built Query Library: 30 ready-to-use security and compliance queries (awsmap query -n admin-users)
  • Natural Language Queries: Ask questions in plain English — zero dependencies, works out of the box (awsmap ask show me all EC2 without Owner tag)
  • Examples Library: 1381 ready-to-run questions organized by service (awsmap examples lambda)
  • Multi-Account: Scan multiple accounts, query across all of them
  • Tag Filtering: Filter by tags — multiple values for same tag match ANY (Owner=John OR Jane), different tags match ALL (Owner=John AND Environment=Production)
  • Beautiful HTML Reports: Interactive reports with search, filters, dark mode, and export
  • Multiple Outputs: JSON, CSV, and HTML formats
  • Fast: Parallel execution with 40 workers (~2 minutes for typical accounts)
  • Console Login Support: Works with aws login credential provider

Installation

PyPI

pip install awsmap

Requirements: Python 3.8+, AWS credentials configured

Docker

docker pull tarekcheikh/awsmap

Or build locally:

git clone https://github.com/TocConsulting/awsmap.git
cd awsmap
docker build -t awsmap .

Development Installation

git clone https://github.com/TocConsulting/awsmap.git
cd awsmap
pip install -e .

Docker Usage

# Using AWS credentials file
docker run --rm \
  -v ~/.aws:/root/.aws:ro \
  -v $(pwd)/output:/app/output \
  -v ~/.awsmap:/root/.awsmap \
  awsmap -p myprofile -o /app/output/inventory.html

# Using environment variables
docker run --rm \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_DEFAULT_REGION=us-east-1 \
  -v $(pwd)/output:/app/output \
  -v ~/.awsmap:/root/.awsmap \
  awsmap -o /app/output/inventory.html

# Query stored inventory
docker run --rm \
  -v ~/.awsmap:/root/.awsmap \
  awsmap query "SELECT service, COUNT(*) as count FROM resources GROUP BY service ORDER BY count DESC"

# List available services
docker run --rm awsmap --list-services

Usage

# Full account inventory (all services, all regions, HTML output)
awsmap -p myprofile

# Specific services (comma-separated or multiple -s flags)
awsmap -p myprofile -s ec2,s3,rds,lambda,iam

# Specific regions
awsmap -p myprofile -r us-east-1,eu-west-1

# Filter by tags (OR logic for same key)
awsmap -p myprofile -t Owner=John -t Owner=Jane -t Environment=Production

# JSON output
awsmap -p myprofile -f json -o inventory.json

# List available collectors
awsmap --list-services

# Show timing per service (useful for debugging)
awsmap -p myprofile --timings

# Exclude default AWS resources (default VPCs, security groups, etc.)
awsmap -p myprofile --exclude-defaults

# Skip local database storage
awsmap -p myprofile --no-db

Multi-Account

Scan multiple AWS accounts. Each scan is stored in the same local database — query across all of them.

# Scan different accounts (different profiles)
awsmap -p production
awsmap -p staging
awsmap -p dev-account

# Query across all accounts
awsmap query -n resources-by-account
awsmap ask how many resources per account

# Scope to one account
awsmap query -n admin-users -a production
awsmap ask -a staging show me all Lambda functions

Query Your Inventory

Every scan is automatically stored in a local SQLite database (~/.awsmap/inventory.db). Query it offline with raw SQL or natural language.

SQL Queries

# Count resources per service
awsmap query "SELECT service, COUNT(*) as count FROM resources GROUP BY service ORDER BY count DESC"

# Find all EC2 instances in a specific region
awsmap query "SELECT id, name, region FROM resources WHERE service='ec2' AND type='instance'"

# View scan history
awsmap query "SELECT * FROM scans ORDER BY timestamp DESC"

# JSON or CSV output
awsmap query "SELECT * FROM resources WHERE service='s3'" -f json
awsmap query "SELECT service, id, name FROM resources" -f csv

# Query tags (filter to resources that have the tag)
awsmap query "SELECT id, name, json_extract(tags, '$.Owner') as owner FROM resources WHERE service='ec2' AND json_extract(tags, '$.Owner') IS NOT NULL"

More SQL examples: See examples/queries/*.sql for ready-to-use query templates you can customize.

Pre-Built Query Library

awsmap ships with 30 pre-built queries for common security, compliance, and operational tasks. No SQL knowledge required.

# List all available queries
awsmap query --list

# Run a named query
awsmap query -n admin-users
awsmap query -n users-without-mfa
awsmap query -n open-security-groups
awsmap query -n untagged-resources

# Pass parameters (find resources with Owner tag)
awsmap query -n resources-by-tag -P tag=Owner

# Multiple parameters (find EC2 missing Environment tag)
awsmap query -n missing-tag -P tag=Environment -P service=ec2

# Scope to a specific account
awsmap query -n admin-users -a production

# Show query SQL without running it
awsmap query --show admin-users

# Run SQL from a file
awsmap query -F my-query.sql

Parameter format: Use -P parameter=value where parameter is the query parameter name (e.g., tag, service) and value is what you're searching for. Example: -P tag=Owner means "filter by the Owner tag" (NOT -P Owner=SomeValue).

Available queries:

Query Description Example
IAM / Security
admin-users IAM users with admin permissions (direct + via group) awsmap query -n admin-users
admin-roles IAM roles with admin permissions awsmap query -n admin-roles
users-without-mfa IAM users without MFA enabled awsmap query -n users-without-mfa
iam-inactive-users IAM users with no login and no access keys awsmap query -n iam-inactive-users
old-access-keys IAM users with access keys awsmap query -n old-access-keys
cross-account-roles IAM roles with trust policies allowing external accounts awsmap query -n cross-account-roles
open-security-groups Security groups with 0.0.0.0/0 ingress rules awsmap query -n open-security-groups
secrets-no-rotation Secrets Manager secrets without auto-rotation awsmap query -n secrets-no-rotation
S3
public-s3-buckets S3 buckets with public access enabled awsmap query -n public-s3-buckets
encryption-status S3 buckets and their encryption configuration awsmap query -n encryption-status
s3-no-versioning S3 buckets without versioning awsmap query -n s3-no-versioning
s3-no-logging S3 buckets without access logging awsmap query -n s3-no-logging
EC2 / EBS
stopped-instances EC2 instances in stopped state awsmap query -n stopped-instances
unused-volumes EBS volumes not attached to any instance awsmap query -n unused-volumes
ebs-unencrypted EBS volumes without encryption awsmap query -n ebs-unencrypted
unused-eips Elastic IPs not associated with any instance awsmap query -n unused-eips
default-vpcs Default VPCs across all regions awsmap query -n default-vpcs
RDS
rds-public RDS instances with public access enabled awsmap query -n rds-public
rds-unencrypted RDS instances without encryption awsmap query -n rds-unencrypted
rds-no-multi-az RDS instances without Multi-AZ awsmap query -n rds-no-multi-az
rds-engines RDS instances grouped by engine awsmap query -n rds-engines
Lambda
lambda-runtimes Lambda functions grouped by runtime awsmap query -n lambda-runtimes
lambda-high-memory Lambda functions with memory > 512 MB awsmap query -n lambda-high-memory
Tags
untagged-resources Resources with no tags awsmap query -n untagged-resources
missing-tag Resources missing a specific tag awsmap query -n missing-tag -P tag=Owner
resources-by-tag Resources that have a specific tag awsmap query -n resources-by-tag -P tag=Owner
Inventory
resources-by-service Resource count per service awsmap query -n resources-by-service
resources-by-region Resource count per region awsmap query -n resources-by-region
resources-by-account Resource count per account awsmap query -n resources-by-account
resources-per-account-service Resource count per account per service awsmap query -n resources-per-account-service

You can also add your own queries by placing .sql files in ~/.awsmap/queries/. Use the same header format as the built-in queries (-- name:, -- description:, -- params:).

Natural Language Queries

Ask questions about your inventory in plain English using awsmap ask. No setup required — works out of the box with a built-in zero-dependency parser.

awsmap ask how many resources per region
awsmap ask show me all EC2 instances without Owner tag
awsmap ask which S3 buckets are in eu-west-1
awsmap ask what services have the most resources

awsmap translates your question to SQL using a built-in parser (zero dependencies), shows you the generated query, and displays the results.

Examples Library

Browse and run 1381 pre-built questions organized by AWS service using awsmap examples.

# List all services with question counts
awsmap examples

# Browse questions for a service
awsmap examples lambda

# Run a specific question by number
awsmap examples lambda 5

# Search across all questions
awsmap examples --search "public"
awsmap examples --search "encryption"

Multi-Account Queries

When multiple accounts have been scanned, awsmap ask queries all of them by default. Use -a to scope to a single account:

# Query across all accounts
awsmap ask show me all IAM users

# Scope to one account
awsmap ask -a production show me Lambda functions

CLI Options

Scan Options

Option Description
-p, --profile AWS profile name
-r, --region Region(s) to scan (comma-separated or multiple flags)
-s, --services Service(s) to scan (comma-separated or multiple flags)
-t, --tag Filter by tag Key=Value (multiple allowed)
-f, --format Output format: html (default), json, csv
-o, --output Output file path
-w, --workers Parallel workers (default: 40)
-q, --quiet Suppress progress output
--timings Show timing summary per service
--include-global Include global services when filtering by non-global regions
--exclude-defaults Exclude default AWS resources (default VPCs, security groups, etc.)
--no-db Skip local database storage
--list-services List available service collectors

Query Options (awsmap query)

Option Description
-n, --name Run a pre-built named query
-F, --file Run SQL from a file
-l, --list List available pre-built queries
-S, --show Show SQL of a named query without running it
-P, --param Parameter for named query (key=value, multiple allowed)
-a, --account Scope to an account (account ID, account alias, or AWS profile)
--db Database path (default: ~/.awsmap/inventory.db)
-f, --format Output format: table (default), json, csv

Ask Options (awsmap ask)

Option Description
-a, --account Scope to an account (account ID, account alias, or AWS profile)
--db Database path (default: ~/.awsmap/inventory.db)

Examples Options (awsmap examples)

Argument / Option Description
<service> Show questions for a specific service
<service> <number> Run question #N against the database
-s, --search Search all questions by keyword
--db Database path (default: ~/.awsmap/inventory.db)

Config Commands (awsmap config)

Set persistent defaults so you don't have to repeat CLI flags. CLI flags always override config values.

Only the keys listed below are accepted — unknown keys and invalid values are rejected. If the config file is manually edited and contains invalid entries, awsmap config list detects them, warns you, and auto-cleans the file.

Command Description
awsmap config set key value Set a configuration value (validated)
awsmap config get key Get a configuration value
awsmap config list List all values (detects and cleans invalid entries)
awsmap config delete key Delete a configuration value

Available config keys (only these are accepted):

Key Applies to Description Example
profile awsmap (scan) Default AWS profile awsmap config set profile production
regions awsmap (scan) Default regions (comma-separated) awsmap config set regions us-east-1,eu-west-1
services awsmap (scan) Default services (comma-separated) awsmap config set services ec2,s3,lambda
format awsmap (scan) Default output format (html, json, csv) awsmap config set format json
workers awsmap (scan) Default parallel workers awsmap config set workers 20
exclude_defaults awsmap (scan) Exclude default AWS resources (true/false) awsmap config set exclude_defaults true
db query, ask Default database path awsmap config set db /path/to/inventory.db
query_format query Default query output format (table, json, csv) awsmap config set query_format csv
# Set your usual profile and regions
awsmap config set profile production
awsmap config set regions us-east-1,eu-west-1

# Now just run:
awsmap
# Equivalent to: awsmap -p production -r us-east-1,eu-west-1

# CLI flags still override config:
awsmap -p staging    # Uses staging profile, but regions from config

Supported Services

Category Services
Compute ec2, lambda, ecs, eks, ecr, ecr-public, lightsail, autoscaling, application-autoscaling, elasticbeanstalk, batch, apprunner, imagebuilder
Storage s3, efs, fsx, backup, datasync, dlm, storagegateway
Database rds, dynamodb, elasticache, memorydb, docdb, neptune, redshift, redshift-serverless, keyspaces, opensearch, opensearch-serverless, dax, dsql, timestream-influxdb
Networking vpc, elbv2, elb, route53, route53resolver, route53domains, cloudfront, globalaccelerator, apigateway, apigatewayv2, appsync, directconnect, network-firewall, servicediscovery, vpc-lattice, networkmanager
Security iam, sso, kms, secretsmanager, acm, acm-pca, wafv2, guardduty, inspector2, securityhub, ds, cognito, accessanalyzer, macie2, detective, shield, fms, cloudhsmv2, auditmanager, securitylake
Management & Monitoring cloudwatch, logs, cloudtrail, ssm, config, sns, sqs, events, xray, grafana, amp, ce, budgets, compute-optimizer, service-quotas, resource-groups, health, synthetics, appconfig, organizations, servicecatalog, resiliencehub
Serverless stepfunctions, kinesis, firehose, kafka, serverlessrepo, eventbridge-scheduler, eventbridge-pipes, schemas
Developer Tools cloudformation, codeartifact, codebuild, codepipeline, codedeploy, devicefarm
Analytics athena, glue, mwaa, lakeformation, emr, emr-serverless, cleanrooms, quicksight, datazone
AI/ML sagemaker, bedrock, lexv2, rekognition, textract, transcribe, translate, comprehend, polly, personalize, kendra, frauddetector
Media mediaconvert, mediaconnect, mediapackage, medialive, mediastore, mediatailor, ivs
Migration & Transfer transfer, dms
End User Computing workspaces, amplify, connect
IoT iot, iotsitewise
Other ram, resource-explorer-2, mq, sesv2, appflow, gamelift, outposts, fis, location

For detailed resource types per service, see SERVICES.md.

Output Formats

HTML (Default)

Interactive report with:

  • Dashboard with resource counts and charts
  • Global search across all resources
  • Filter by service and region
  • Collapsible service sections
  • Click to copy ARN/ID
  • Clickable tag badges (shows all tags)
  • Dark/light mode toggle
  • Export filtered view to CSV
  • Print-friendly

JSON

{
  "metadata": {
    "account_id": "123456789012",
    "timestamp": "2024-12-24 15:30:00 UTC",
    "resource_count": 1590
  },
  "resources": [
    {
      "service": "ec2",
      "type": "instance",
      "id": "i-1234567890abcdef0",
      "arn": "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
      "name": "my-instance",
      "region": "us-east-1",
      "details": {...},
      "tags": {"Owner": "John", "Environment": "Production"}
    }
  ]
}

CSV

Flat format with columns: service, type, id, name, region, arn, is_default, tags

Tag Filtering

# Single tag
awsmap -t Environment=Production

# Multiple values for same key (OR logic)
awsmap -t Owner=John -t Owner=Jane
# Returns resources where Owner is "John" OR "Jane"

# Multiple keys (AND logic)
awsmap -t Owner=John -t Environment=Production
# Returns resources where Owner is "John" AND Environment is "Production"

# Combined
awsmap -t Owner=John -t Owner=Jane -t Environment=Production
# Returns resources where (Owner is "John" OR "Jane") AND Environment is "Production"

Global vs Regional Services

AWS has two types of services:

  • Regional services (EC2, RDS, Lambda, etc.) - Resources exist in specific regions
  • Global services (IAM, Route53, CloudFront, etc.) - Resources are account-wide, not region-specific

How awsmap handles global services

When you filter by region, awsmap intelligently includes global services based on their control plane location:

Command Behavior
awsmap (no region) All services (regional + global)
awsmap -r us-east-1 Regional in us-east-1 + global services with us-east-1 control plane
awsmap -r us-west-2 Regional in us-west-2 + global services with us-west-2 control plane
awsmap -r eu-west-1 Regional in eu-west-1 only (no global services)
awsmap -r eu-west-1 --include-global Regional in eu-west-1 + all global services

Global services by control plane

Based on AWS Global Services documentation:

Control Plane Global Services
us-east-1 IAM, Organizations, Route53, Route53 Domains, CloudFront, Shield, Budgets, Cost Explorer, Health
us-west-2 Network Manager, Global Accelerator

S3 buckets

S3 bucket names are globally unique, but each bucket has a specific region. awsmap treats S3 as a regional service:

# Only S3 buckets in eu-west-1
awsmap -r eu-west-1 -s s3

# All S3 buckets
awsmap -s s3

Performance

Scans 150+ services across all regions in parallel.

Account Size Resources Estimated Time
Small <500 ~1.5 minutes
Medium 500-5,000 ~2 minutes
Large 5,000-20,000 ~3-5 minutes
Enterprise 20,000+ ~5-10 minutes

Tuning Options:

# Increase parallelism for faster scans
awsmap -p myprofile -w 50

# Reduce parallelism for rate-limited accounts
awsmap -p myprofile -w 20

# Scan specific services only (much faster)
awsmap -p myprofile -s ec2,s3,lambda,iam

# Scan specific regions only
awsmap -p myprofile -r us-east-1,eu-west-1

Why is the scan fast?

  • Parallel execution with configurable workers (default: 40)
  • Region-aware collectors skip unsupported regions automatically
  • Global services (IAM, Route53, etc.) collected once, not per-region
  • Smart region filtering excludes global services when not relevant
  • Optimized API calls (batch operations where available)

IAM Permissions

awsmap requires read-only access to the AWS services you want to inventory.

Recommended: Attach the AWS managed ReadOnlyAccess policy to your IAM user or role. This policy is maintained by AWS and provides read access across all services.

# Attach to a role
aws iam attach-role-policy \
  --role-name YourRoleName \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

# Attach to a user
aws iam attach-user-policy \
  --user-name YourUserName \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

For more restrictive access, you can create a custom policy with explicit read actions for specific services (e.g., ec2:Describe*, s3:List*, s3:Get*). See the IAM Actions Reference for service-specific actions.

What's NOT Collected

This tool only collects user-owned resources, excluding:

  • AWS-managed policies (only customer-managed)
  • AWS-managed KMS keys (only customer-managed)
  • Default parameter groups and option groups
  • AWS service-linked roles
  • Reserved instance offerings (pricing catalog)
  • Foundation models (Bedrock catalog)
  • Automated backups (only manual snapshots)
  • AWS system keyspaces (Keyspaces: system_*)
  • AWS default queues/groups (MediaConvert, X-Ray)
  • AWS managed domain lists (Route53 Resolver: AWSManagedDomains*)
  • Default data lake settings (Lake Formation)

Default VPC resources (default VPCs, subnets, security groups, route tables, internet gateways, NACLs, DHCP options) are collected by default and marked with a "DEFAULT" badge in HTML reports. Use --exclude-defaults to filter them out.

See SERVICES.md for the complete list of filtered resources.

Why a Built-In NLQ Parser Instead of AI/LLM?

We evaluated three approaches for natural language queries:

Approach Accuracy Cost Latency Offline
Ollama (local LLMs) ~80% Free Slow (seconds) Yes
OpenAI / Anthropic APIs ~95% Pay per query Network dependent No
Built-in parser (awsmap) 100% Free Instant Yes
  • Ollama models are free and run locally, but when tested against real AWS inventory queries, accuracy was around 80% — one in five queries would generate wrong SQL or fail silently. Not acceptable for a CLI tool where users trust the output.
  • OpenAI / Anthropic APIs produce better results, but require API keys, cost money per query, and depend on network connectivity. Not ideal for an infrastructure tool that should just work.
  • Built-in parser is a zero-dependency, deterministic NL-to-SQL engine. It's tested against 1500 realistic test questions with a 100% pass rate (separate from the 1381 examples library). It covers listing, counting, aggregation, region filters, negation, tags, multi-service queries, synonyms, typo tolerance, relative time, numeric fields, keyword-value patterns, and 150+ AWS services. No API keys, no network, no cost, instant results.

The 1500 test questions (used during development to validate the parser) are designed to cover the vast majority of real-world use cases. The parser also includes typo tolerance, synonym support, and fuzzy matching to handle natural variations in how people phrase questions.

Found a bug or an inaccurate query? Please open an issue and report it! Every report helps improve the parser for everyone. If you have ideas for a better approach than the built-in NLQ, we're always open to suggestions.

Support

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A fast, comprehensive tool for mapping and inventorying AWS resources across 150+ services and all regions.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 99.9%
  • Dockerfile 0.1%