CloudMapper "wot" - Command to identify a Web Of Trust of trusted AWS accounts


RSS feed

This CloudMapper post introduces the wot command, short for Web Of Trust. This identifies the AWS accounts trusted by a set of AWS accounts. It looks at the IAM policies, S3 policies, VPC peerings, and Direct Connect information to identify external accounts or Direct Connect locations that are in some way trusted.

AWS accounts that are owned vendors, including AWS themselves, are given the logos of the company. These are identified based on the account ID. Unknown accounts are shown as black triangles and their account ID is listed. Accounts that you collected data from are shown as yellow boxes, and accounts that are listed in your config.json file, but that you did not collect data on, are shown as grayish boxes.

Accounts can also be grouped. This will be discussed later.

Edges are colored based on the type of trust relationship that exists. These are:

  • Red: Full admin privileges.
  • Gray: Non-admin IAM privileges.
  • Yellow: S3. Dotted lines are read ability only, solid yellow are anything else.
  • Blue: Solid lines for VPC peerings and dashed lines for Direct Connect.

This command works much like the original use case of CloudMapper in that you first generate a web/data.json file, and then run the webserver command and use your web browser to view the diagram.

Here is some example output:

$ python wot --account all
Unknown account: 999999999999
- 6 connections built

This can then be viewed in the browser with the webserver command.

CloudMapper wot example

In this example, I've tagged my accounts in my config.json file so that they are grouped. This looks like:

{  "accounts":
        {"id": "000000000000", "name": "prod", "tags": ["Summit Route"]},
        {"id": "111111111111", "name": "dev", "tags": ["Summit Route"]},
        {"id": "333333333333", "name": "security", "tags": ["Summit Route"]},
        {"id": "222222222222", "name": "flAWS", "tags": ["flaws"]}
    "cidrs": {}

Currently, CloudMapper only supports a single element in the tags array. In the image you can see that the accounts prod, dev, and security have been grouped under the Summit Route grouping and the flAWS account is alone in its own grouping named flaws.

An external vendor account, Okta, has admin access to dev and prod (red lines), but only limited IAM access to the security account (gray line). The security account can read S3 files from the dev and prod account (yellow lines). There is then an unknown account with account ID 999999999999 that is VPC peered to the prod account (blue line). The purpose of that should be investigated and recorded in our inventory.

Vendor accounts

The account IDs for known vendor accounts are stored in a vendor_accounts.yaml file. Here is an example.

- name: 'Datadog'
  source: ''
  accounts: ['464622532012']

The web/style.css then contains:

    "selector": "[type = \"Datadog\"]",
    "css": {
        "background-image": "./icons/logos/datadog.png",

The logo for this vendor is then stored in web/icons/logos/datadog.png


This command is much less mature than other commands, but is useful enough that I decided to release it. Some of its biggest limitations are:

  • Only supports a handful of the ways in which trust can be established between accounts. Many resources (ex. Glacier) can have resource policies that grant trust to other accounts.
  • The number of vendors I know about is limited.


This command is useful for getting a high-level overview of the interconnected nature of companies with large numbers of AWS accounts. It can help identify vendors that are connected in, finding unknown accounts, and finding ways an attacker might leverage access to esclate themselves to more important accounts.

Next steps

Try it out by cloning CloudMapper from