Skip to content

AWS Organizations and Control Tower

Section 6 · From docs/INVENTORY_INTERNALS.md on GitHub

discover_organization(session, control_tower=True, home_region=None) (blocking, read-only):

  1. sts:GetCallerIdentity (caller account), organizations:DescribeOrganization (ID, ARN, management account, feature set). Failure raises RuntimeError: the caller is not in an organization or lacks access.
  2. ListRoots; for each root, a recursive walk with ListAccountsForParent and ListOrganizationalUnitsForParent, recording every account's parent and OU path.
  3. Policies of each policy type enabled on the root (ListPolicies, ListTargetsForPolicy).
  4. Trusted service access (ListAWSServiceAccessForOrganization) and delegated administrators for the security services (ListDelegatedAdministrators); an access denial stops that loop.
  5. With control_tower, discover_control_tower() probes regions in order (the hint, the session region, then the usual home regions) with controltower:ListLandingZones. On the first landing zone: GetLandingZone (the manifest is parsed for governed regions and shared accounts, both the 3.x and 4.x layouts, and then dropped), ListEnabledControls (falling back to per-OU queries on older API revisions) and ListEnabledBaselines.

Account selection happens in OrganizationTopology.target_accounts(); the mapper wires it to aws.organization (step 2). The map nodes come from organization_assets.topology_assets() (reference).

Permissions: run from the management account or a delegated administrator for Organizations (organizations:Describe*, List*; controltower:List*, Get*). Member accounts need a role cloudg can assume; the default AWSControlTowerExecution has administrator access, so the recommended setup is a dedicated read-only role (SecurityAudit + ViewOnlyAccess) deployed to every account with a service-managed StackSet and passed with --org-role.