Inventory¶
The inventory is the account written as a document: every resource the scan found, placed in a tree, plus the accounts it refers to and everything that went wrong while reading. It comes in three renderings of one document:
| Format | File | Written by |
|---|---|---|
| JSON | vpcatlas-inventory.json |
vpcatlas discover, vpcatlas inventory (--format json) |
| Markdown | vpcatlas-inventory.md |
the same (--format md) |
| HTML | vpcatlas-inventory.html |
the same (--format html) |
vpcatlas inventory --profile prod --format json --output-dir out
The files are written next to vpcatlas-graph.json in the output directory (default vpcatlas-out). The dashboard offers the same three at /export/inventory.json, /export/inventory.md and /export/inventory.html, and serves the HTML page at /inventory.
The inventory is built from the graph (see the graph file), so --cache vpcatlas-graph.json rebuilds it without calling AWS. The same graph always gives the same document.
JSON document¶
The schema id is vpcatlas-inventory/1. The model is strict: it rejects keys it does not know. A key that is added in a way older documents still satisfy keeps the id; the services list of an account was added like that.
Every key described below is written in every document. A value that does not apply is null (a string or number that is unknown), [] (a list with nothing in it), {} (a mapping with nothing in it) or false or 0. The one exception is services in an account, which a document written before the service layer existed does not have; such a document still validates.
Root¶
| Key | Type | Meaning |
|---|---|---|
schema |
string | Always vpcatlas-inventory/1. |
generated_at |
string | Time of the scan, UTC, YYYY-MM-DDTHH:MM:SSZ. It is the generated_at of the graph, not the time the document was rendered. |
tool |
object | name (vpcatlas) and version of the tool that built the document. |
summary |
object | The counts below. |
accounts |
list of account sections | One entry per audited account. |
external_accounts |
list | Accounts the scan saw but has no credentials for. |
links |
list | Every link that crosses an account boundary. |
issues |
list | Calls that failed while discovering. |
summary¶
| Key | Type | Meaning |
|---|---|---|
audited_accounts |
integer | Accounts with a section in accounts. |
external_accounts |
integer | Length of external_accounts. |
regions |
integer | Distinct regions with a section, not counting global. |
resources |
integer | Resources counted, leaving out the account and region containers and the stubs of resources that were referenced but never described. |
cross_account_links |
integer | Length of links. |
issues |
integer | Length of issues. |
by_type |
object | Resource type id to count, for example {"subnet": 12, "vpc": 3}. Keys are sorted. |
Account section (accounts[])¶
| Key | Type | Meaning |
|---|---|---|
account_id |
string | The 12-digit account id. |
name |
string or null | A label for the account. The --account-names file wins, then the account alias, then the name from AWS Organizations (only visible from the management account). null when none is known. |
regions |
list of region sections | Sorted by region name. |
services |
list of service families | The service layer of the account, apart from the network tree. Empty when the account has none. |
Region section (accounts[].regions[])¶
| Key | Type | Meaning |
|---|---|---|
region |
string | A region code, or global for resources that belong to the account and not to a region (Direct Connect gateways, for example). |
resources |
list of resource rows | Resources of the region that sit in no VPC: Transit Gateways, peering connections, VPN gateways, resolver rules, RAM shares, managed prefix lists and the like. |
vpcs |
list of VPC sections | Sorted by name, then id. |
VPC section (...vpcs[])¶
| Key | Type | Meaning |
|---|---|---|
vpc |
resource row | The VPC. When a subnet names a VPC that the scan did not describe (a VPC shared from another account, for instance), a placeholder row is written with details.note set to the VPC itself was not described in this scan. |
cidrs |
list of strings | The CIDR blocks of the VPC. Empty for a placeholder. |
resources |
list of resource rows | Resources of the VPC that sit in no subnet: route tables, internet gateways, security groups, network ACLs, VPC endpoints and so on. |
subnets |
list of subnet sections | Sorted by Availability Zone, then CIDR. |
Subnet section (...subnets[])¶
| Key | Type | Meaning |
|---|---|---|
subnet |
resource row | The subnet. |
availability_zone |
string or null | The zone name, for example eu-west-1a. |
availability_zone_id |
string or null | The zone id, for example euw1-az1. Names map to different physical zones in different accounts; ids do not. |
cidr |
string or null | The IPv4 CIDR of the subnet. |
tier |
string | public (the default route goes to an internet gateway), private, isolated or unknown. |
resources |
list of resource rows | Resources placed in the subnet: NAT gateways, interface endpoints, load balancers, firewall endpoints and so on. |
workloads |
integer | The number of network interfaces in the subnet that no listed resource claims. They are counted, not listed. |
Resource row (resource rows, and the subnet and vpc keys above)¶
| Key | Type | Meaning |
|---|---|---|
key |
string | The graph key, <account>/<region>/<type>/<id>. Stable across scans. |
type |
string | The type id, for example vpc, subnet, tgw, lb. |
label |
string | A readable name for the type, for example Transit gateway. |
id |
string | The AWS id (or the name or ARN tail for resources that have no id). |
name |
string or null | The Name tag, or the native name. |
account_id |
string | The account that owns the resource. |
region |
string or null | The region, or global. |
arn |
string or null | The ARN when the API returns one. |
state |
string or null | The state the API reports (available, active, ...). |
details |
object of strings | The attributes of the resource worth showing: the fields of its model apart from the common ones, as short text. Lists are cut after six items with (+N), values at 110 characters, booleans are yes (false and empty values are left out). A finding of the scan appears as findings. |
tags |
object of strings | The tags, sorted by key. |
owned_elsewhere |
boolean | true when the owner is not an audited account: a shared subnet, a Transit Gateway shared through RAM. |
seen_by |
list of strings | The audited accounts whose credentials saw the resource. |
Network resources are placed by what contains them: a resource goes in its subnet when it has one, else in its VPC, else in its region.
Service family (accounts[].services[])¶
The service layer is grouped in families. A family is written only when the account has something in it.
| Key | Type | Meaning |
|---|---|---|
key |
string | edge, api, compute, data or account. |
title |
string | DNS and edge, API and load balancing, Compute and containers, Data and storage or Account services. |
counts |
object | Resource type id to count in this family. |
resources |
list of resource rows | The members. region is global for account-wide services such as Route 53, CloudFront, S3, Shield and CloudTrail. details holds the key attributes of each type. |
| Family | Types |
|---|---|
edge |
hosted_zone, cloudfront, web_acl, certificate, shield |
api |
api_gateway, api_vpc_link, target_group |
compute |
ecs_cluster, ecs_service, eks_cluster, instance_group, lambda |
data |
rds, elasticache, efs, s3_bucket, s3, dynamodb |
account |
cloudtrail, guardduty, config_recorder, cloudwatch, kms, ecr |
For the summary types (s3, dynamodb, cloudtrail, guardduty, config_recorder, cloudwatch, kms, ecr) a value the scan could not read is written as not read. That is different from zero or no: a denied call never reads as an empty account.
External accounts (external_accounts[])¶
An external account is an account id that appears in the network but is not audited: the owner of a shared Transit Gateway, the other end of a peering, the producer of an endpoint service. See External accounts below.
| Key | Type | Meaning |
|---|---|---|
account_id |
string | The account id. |
name |
string or null | A label, from --account-names or an alias, when known. |
seen_via |
list of strings | How the account was revealed, each as service.operation -> member, for example ec2.DescribeSecurityGroups -> IpPermissions.UserIdGroupPairs.UserId. |
links |
integer | How many entries of links point at this account. |
resources |
list of resource references | The resources of that account the audited ones refer to. |
A resource reference has key, type, label, id, name, account_id and region, with the meaning given for a resource row.
Cross-account links (links[])¶
| Key | Type | Meaning |
|---|---|---|
link_type |
string | What kind of link it is. Fixed names: vpc_peering, tgw_attachment_to_shared_tgw, tgw_attachment_from_other_account, tgw_peering. Otherwise shared_<type> for a resource of another account that an audited account can see (shared_subnet, shared_tgw), or <local type>_<relation>_<remote type> for a graph relation between accounts. |
local |
resource reference | The resource on the audited side. |
remote |
resource reference or null | The resource on the other side, when it is known. null for a shared_<type> link. |
remote_account |
string | The other account id. |
detected_by |
string | The API call and member that revealed the link, for example ec2.describe_transit_gateway_attachments -> ResourceOwnerId / TransitGatewayOwnerId. |
Issues (issues[])¶
An issue is a call that failed. The scan goes on after it, so the inventory may be incomplete where an issue is listed.
| Key | Type | Meaning |
|---|---|---|
kind |
string | denied, throttled, unsupported or error. It is read from the error code: access denied and unauthorized become denied, throttling becomes throttled, an unsupported operation or a region that is not opted in becomes unsupported, anything else error. |
account_id |
string or null | The account the call ran in. |
region |
string or null | The region. |
service |
string or null | The boto3 client name, for example ec2. |
operation |
string or null | The operation, for example describe_vpcs. |
code |
string or null | The AWS error code. |
message |
string | The error message. |
vpcatlas ... --strict exits with code 4 when this list is not empty.
Markdown¶
vpcatlas-inventory.md is the same document for reading in a repository or a pull request. Its sections:
# AWS network inventory, with the time, tool version and schema id.## Summary: the counts as a table, then a table of resources by type.## Accounts: for each account,### Account <id> (<name>), then each region (#### Region), each VPC (##### VPC <id> (<name>) - <cidrs>) and each subnet (###### Subnet <id> - <cidr>, <zone>, <tier>), each followed by a table with the columns Type, ID, Name, State and Details. A shared resource shows(owner <account>)after its id. Then#### Serviceswith one table per family.## External accounts and cross-account links: a table of external accounts and a table of links.## Issues and coverage gaps: written only when there are issues, as a table.
Details are cut at 240 characters in a table cell.
HTML¶
vpcatlas-inventory.html is one self-contained page: the styles and the script are inline, nothing is loaded from the network, and it follows the light or dark setting of the browser. It has the same sections as the Markdown, summary cards, a collapsible table of resources by type, and a search box at the top that filters rows by id, name, type or account. The dashboard serves it with a content security policy that allows the inline script and nothing else.
External accounts section¶
The external accounts section answers a question the network diagram can only hint at: whose account is on the other end?
external_accountslists each account once, with a label if you gave one, how it was found (seen_via), how many links point to it and which of its resources are referenced.linkslists each crossing: the resource on your side, the resource on the other side, the other account and the API call that showed it.
A link from a shared resource has no remote resource. For example, a Transit Gateway owned by account 222222222222 and shared with you through RAM appears as a shared_tgw link with remote_account 222222222222 and remote null, and again as a tgw_attachment_to_shared_tgw link for each of your attachments to it. Give accounts readable labels with --account-names, a JSON file that maps account ids to labels:
{ "222222222222": "network-hub", "333333333333": "partner-analytics" }
A scan can only name what its credentials can see. When it audits several accounts at once (--profile repeated, or --role-arn repeated), the accounts you audit stop being external, and stubs created while scanning a spoke are replaced by the real resources found in the hub.