Skip to content

cloudg map

Builds the scanner-independent inventory map. Everything deployed or default is collected, linked into typed relationships and written to disk for cloudg deps, the MCP server or your own code.

cloudg map needs read access to the cloud APIs and nothing else. No scanner runs and none has to be installed. The Inventory mapping guide explains what the map contains; this page covers the command itself.

Usage

cloudg map [OPTIONS]

Options

Flag Value Default Description
-p, --provider aws azure gcp all aws Provider(s) to map. Use multiple times or 'all'. Repeatable.
--profile TEXT none AWS profile name
--regions TEXT none Regions: 'all' for auto-discovery, or comma-separated list
--subscription-id TEXT none Azure subscription ID
--project-id TEXT none GCP project ID
--accounts TEXT none AWS: comma-separated account IDs to map; needs --role-name (or aws.role_name)
--role-name TEXT none AWS: role to assume in each account of --accounts (aws.role_name)
--org
--no-org
flag config AWS: discover every account in the Organization / Control Tower landing zone and map them all (run from the management account)
--org-role TEXT none AWS: role assumed in member accounts (default AWSControlTowerExecution)
--ou TEXT none AWS: only accounts under this OU (ID, ARN or name). Repeatable. An OU that matches nothing is an error. Repeatable.
--exclude-account TEXT none AWS: skip this account. Repeatable. Repeatable.
--ct-home-region TEXT none AWS: Control Tower home region (auto-detected)
--services TEXT none Service families or task names to map, comma-separated, for AWS and Azure (e.g. containers,serverless,security)
--exclude-services TEXT none Service families/collectors to skip, comma-separated
--kubernetes
--no-kubernetes
flag config Map workloads inside EKS and AKS clusters through the Kubernetes API
--cloud-control
--no-cloud-control
flag config AWS: list every resource type with a Cloud Control list handler, tagged or not (breadth for services without a dedicated collector)
--findings TEXT none Existing cloudg findings JSON (raw-findings.json or a cloudg report) to merge into asset/compliance maps. Repeatable. Repeatable.
--sweep
--no-sweep
flag config Catch-all sweep (AWS Resource Groups Tagging API) for resources without a dedicated collector. Default: inventory.tagging_sweep (on).
-o, --output TEXT ./reports Output directory

Generated from the click definition in /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/cloudg/cli_inventory.py, so it matches cloudg map --help. Credentials can come from flags, config.yaml or the environment: see Auth flags.

How it works

Like cloudg run, the command starts from the config loaded by the root command (cloudg -c config.yaml map ...), or from built-in defaults when there is no -c. It then applies three groups of flags. A flag you leave out never clears a value the config set.

Scope flags come first. -p/--provider replaces providers (default aws; all means all three). --regions replaces the region list of every provider, and all turns into the ALL sentinel that triggers discovery. --profile, --subscription-id and --project-id work as they do on run. --accounts sets aws.accounts and --role-name sets aws.role_name. An account list needs a role name, from the flag or the config: --accounts without one stops with exit status 2 before any API call, unless --org is on (the member role then defaults to AWSControlTowerExecution).

Organization flags fill aws.organization. --org/--no-org sets enabled, --org-role sets role_name, --ou and --exclude-account set include_ous and exclude_accounts, and --ct-home-region sets home_region.

Inventory flags fill inventory. --services and --exclude-services take comma-separated family or collector names. --kubernetes/--no-kubernetes and --cloud-control/--no-cloud-control only change the config when you pass them, so the config file decides otherwise (both default to on).

--sweep/--no-sweep works the same way: without the flag, inventory.tagging_sweep from the config decides (on by default).

The command prints the result as a "Map Configuration" panel before it calls any API. For cloudg map -p aws --org --org-role cloudg-readonly --ou Workloads --regions all --services containers,serverless,security it shows:

$ cloudg map -p aws --org --org-role cloudg-readonly --ou Workloads --regions all --services containers,serverless,security
╭─────────────────────────── Map Configuration ───────────────────────────╮
│             Providers  aws                                              │
│           AWS regions  ALL                                              │
│              Services  containers, serverless, security                 │
│  Kubernetes workloads  enabled                                          │
│       Catch-all sweep  enabled                                          │
│   Cloud Control sweep  enabled                                          │
│              Scanners  none (inventory mapping is scanner-independent)  │
│          Organization  discover all accounts under Workloads            │
│           Member role  cloudg-readonly                                  │
╰─────────────────────────────────────────────────────────────────────────╯

The mapping run itself goes through these steps:

flowchart TD
  A["Config + flags"] --> B{"--org?"}
  B -->|yes| C["Discover org, OUs, accounts, Control Tower"]
  B -->|no| D["Deep collectors per account and region"]
  C --> D
  D --> E["Breadth sweeps"]
  E --> F["Deduplicate"]
  F --> G["Link relationships"]
  G --> H["Account hierarchy"]
  H --> I["Dependency analysis"]
  I --> J["Write inventory files"]
  J --> K{"--findings?"}
  K -->|yes| L["asset-map.json, compliance-map.json"]
What cloudg map does

With --org, cloudg first lists the Organization from the account your credentials belong to (the management account, or a delegated administrator for the Organizations APIs). It picks the member accounts under --ou, drops --exclude-account entries, and, if you also passed --accounts, keeps only the accounts in both lists. The role assumed in each member account is --org-role, else --role-name, else AWSControlTowerExecution. If Control Tower is present and you asked for --regions all, only its governed regions are mapped (aws.organization.use_governed_regions, on by default).

Without --org, --accounts plus --role-name gives you the same fan-out over an explicit list. In both cases, if your own account is in the list, cloudg collects it with the base credentials instead of assuming the role, since member roles usually do not exist in the management account.

Deep collection runs per account and region. Account-wide services (IAM, S3, CloudFront, Route 53, Shield and others) run once per account, in the primary region, so --regions all does not repeat them. After the deep collectors, the breadth sweeps fill gaps: Cloud Control lists every resource type with a list handler, and the Resource Groups Tagging API finds tagged resources. When the same resource turns up twice, the dedicated collector wins, then Cloud Control, then the tagging API.

The linker then resolves every identifier the collectors recorded into typed edges (INVOKES, USES_IMAGE, ASSUMES_ROLE, PROTECTS, GOVERNS and so on), adds an account node above each account's top-level resources, and computes the dependency analysis. The Inventory mapping guide lists the edge types.

The command prints an organization table (with --org), an inventory summary, the 15 services with the most assets, the 10 most shared dependencies, the 10 largest blast radii and up to 15 security service gaps. Here is the summary part for the synthetic estate in the test suite (tests/mcp/fixtures/sample_estate.py), so the numbers are small:

           Inventory Summary
╭──────────────────────────────┬───────╮
│ Metric                       │ Value │
├──────────────────────────────┼───────┤
│ Assets                       │    44 │
│ Interconnections             │    56 │
│ Accounts                     │     5 │
│ Services                     │    23 │
│ Internet-exposed             │     6 │
│ Cross-account edges          │     3 │
│ External accounts referenced │     1 │
│ Security service gaps        │     1 │
│ Unlinked assets              │     2 │
│ Unresolved references        │     1 │
╰──────────────────────────────┴───────╯

If some collectors failed (an API you lack permission for, a region that is not enabled), the map is still written. cloudg prints one warning with the count and the first eight failures, as account region service. Run with cloudg -v map ... to see why each one failed, or look at the coverage records.

Merging findings

--findings takes a cloudg findings file: a raw-findings.json from cloudg scan or cloudg ingest, or a findings.json report. Both shapes work, a bare list or an object with a findings key. The option is repeatable. Files that cannot be read or validated are skipped with a warning. Findings attach to assets by ARN, resource ID or name.

The merge happens after a fresh mapping run, because --findings belongs to map. To overlay findings on a map you already saved without calling the cloud again, use InventoryMapper.export_merged() from Python (see InventoryMapper) or load both files into the MCP server.

Credentials

map has no --aws-key, --azure-* or --gcp-* flags. It takes credentials from the config file, the standard environment variables, --profile, or the provider's default chain, in the order described under Auth flags. Put role ARNs, service principals and credential files in config.yaml when you map with something other than your default identity.

Examples

Map one AWS account in every enabled region, using your default credentials:

cloudg map -p aws --regions all

Map the regions you care about with a named profile, into a dated folder:

cloudg map -p aws --profile audit --regions us-east-1,eu-west-1 -o ./maps/2026-10-09

Map every account in the Organization, from the management account, with a dedicated read-only role:

cloudg map -p aws --org --org-role cloudg-readonly --regions all

Limit an Organization run to one OU and skip a sandbox account:

cloudg map -p aws --org --ou Workloads --exclude-account 111122223333 --regions all

Map a fixed set of accounts without Organizations access:

cloudg map -p aws --accounts 111111111111,222222222222 --role-name cloudg-readonly --regions all

Narrow a run to containers and serverless, without reaching into the EKS clusters:

cloudg map -p aws --services containers,serverless --no-kubernetes --regions eu-west-1

Map Azure and GCP alongside AWS. Azure covers every enabled subscription unless you pass one:

cloudg map -p all --regions all --subscription-id 00000000-0000-0000-0000-000000000000 --project-id my-project

Map and overlay the findings of an earlier scan in one go:

cloudg map -p aws --regions all --findings ./reports/raw-findings.json -o ./reports

The same mapping from Python:

cloudg map -p aws --profile audit --regions all -o ./reports
map_inventory.py
from cloudg import CloudGConfig, CloudGEngine

config = CloudGConfig(providers=["aws"])
config.aws.profile = "audit"
config.aws.regions = ["ALL"]

engine = CloudGEngine(config)
result = engine.map_inventory_sync("./reports")
print(result.summary["total_assets"], "assets")

Output files

Written to -o/--output (default ./reports). The output files reference describes each one in more detail.

File Written when Contents
inventory-map.json always Summary, providers, resolved regions, assets, edges, unresolved references, and a throttling block when the run was throttled
inventory-map.graphml always The interconnection graph
inventory-graph.json always D3 graph with account and relationship attributes
inventory-dependencies.json always Most shared dependencies, largest blast radius, cross-account edges, security service coverage
inventory-organization.json the Organization was mapped OU tree, accounts, SCPs, Control Tower landing zone and controls
asset-map.json --findings loaded at least one finding Per-asset finding counts and severity breakdown, riskiest first
compliance-map.json same Framework to findings and affected assets

cloudg deps and the MCP server's load_dataset read inventory-map.json and pick up inventory-organization.json from the same folder.

Exit codes

Code When
0 The map was written, even if some collectors failed
1 Mapping failed as a whole, for example no usable credentials, or an --ou that matches no OU in the organization. cloudg prints an "Inventory mapping failed" panel.
2 Click rejected an option, such as -p aws2, or --accounts (or aws.accounts) was given without a role name