cloudg 0.5.0__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloudg-0.5.0 → cloudg-0.5.2}/PKG-INFO +206 -17
- {cloudg-0.5.0 → cloudg-0.5.2}/README.md +14 -7
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/__init__.py +1 -1
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli.py +4 -152
- cloudg-0.5.2/cloudg/cli_inventory.py +487 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws.py +25 -17
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws_services.py +14 -6
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws_services_extended.py +13 -7
- cloudg-0.5.2/cloudg/collectors/azure.py +400 -0
- cloudg-0.5.2/cloudg/collectors/gcp.py +554 -0
- cloudg-0.5.2/cloudg/collectors/gcp_assets.py +466 -0
- cloudg-0.5.2/cloudg/collectors/multi.py +507 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/config.py +124 -1
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/builder.py +5 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/ontology.py +68 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/ontology_rules.py +38 -3
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/inventory/__init__.py +9 -2
- cloudg-0.5.2/cloudg/inventory/_util.py +29 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/inventory/aws_deep.py +222 -102
- cloudg-0.5.2/cloudg/inventory/aws_deep_tasks.py +180 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/__init__.py +31 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/_base.py +379 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/_policy_grants.py +46 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/__init__.py +103 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/_common.py +255 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/alarms.py +199 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/backup.py +237 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/batch.py +244 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/build_deploy.py +367 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/cicd.py +306 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/compute.py +356 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/containers_ext.py +252 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/firehose.py +246 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/integration.py +285 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/logs.py +287 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/operations.py +389 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/application/serverless_ext.py +105 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/cloudcontrol.py +295 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/containers/__init__.py +38 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/containers/ecr.py +134 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/containers/ecs.py +280 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/containers/eks.py +434 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/__init__.py +122 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/_common.py +235 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/analytics.py +217 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/bedrock.py +408 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/databases.py +241 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/glue.py +205 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/glue_etl.py +326 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/lakeformation.py +144 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/messaging.py +204 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/registry.py +34 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/sagemaker.py +282 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/serverless_data.py +315 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/transfer.py +427 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/__init__.py +150 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/_common.py +202 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/cognito.py +220 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/data_protection.py +408 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/iam_extras.py +187 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/identity_center.py +531 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/ram.py +154 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/s3_access_points.py +192 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/service_catalog.py +267 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/sharing.py +302 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/governance/stack_sets.py +175 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/identity.py +384 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/__init__.py +135 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/_common.py +182 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/apigateway.py +408 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/cloudfront.py +325 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/direct_connect.py +308 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/elb_rules.py +224 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/global_accelerator.py +126 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/lattice.py +218 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/network_manager.py +144 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/privatelink.py +226 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/resolver.py +268 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/tgw.py +228 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/vpn.py +184 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/__init__.py +57 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/compute_fabric.py +209 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/data.py +294 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/dns_iac_ops.py +285 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/load_balancing.py +181 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/platform/storage.py +252 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/security/__init__.py +60 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/security/_common.py +71 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/security/detection.py +266 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/security/network_protection.py +185 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/security/posture.py +200 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/serverless/__init__.py +45 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/serverless/apigateway.py +165 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/serverless/functions.py +207 -0
- cloudg-0.5.2/cloudg/inventory/aws_services/serverless/messaging.py +293 -0
- cloudg-0.5.2/cloudg/inventory/azure_deep.py +229 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/__init__.py +163 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/arm_types.py +31 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/builder.py +483 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/compute.py +283 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/data_security.py +357 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/edge.py +254 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/helpers.py +316 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/network.py +396 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/query.py +161 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/registry.py +229 -0
- cloudg-0.5.2/cloudg/inventory/azure_graph/web_containers.py +253 -0
- cloudg-0.5.2/cloudg/inventory/azure_hierarchy.py +410 -0
- cloudg-0.5.2/cloudg/inventory/catalogs/__init__.py +79 -0
- cloudg-0.5.2/cloudg/inventory/catalogs/aws_arn_types.yaml +159 -0
- cloudg-0.5.2/cloudg/inventory/catalogs/aws_cloudcontrol.yaml +334 -0
- cloudg-0.5.2/cloudg/inventory/catalogs/azure_arm_types.yaml +133 -0
- cloudg-0.5.2/cloudg/inventory/catalogs/gcp_asset_types.yaml +157 -0
- cloudg-0.5.2/cloudg/inventory/dependencies.py +319 -0
- cloudg-0.5.2/cloudg/inventory/gcp_deep.py +81 -0
- cloudg-0.5.2/cloudg/inventory/gcp_hierarchy.py +272 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/__init__.py +118 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/compute.py +191 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/context.py +152 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/data_logging.py +258 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/gke.py +211 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/iam.py +473 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/load_balancing.py +247 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/messaging.py +99 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/names.py +367 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/network.py +415 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/pipelines.py +166 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/resource_manager.py +178 -0
- cloudg-0.5.2/cloudg/inventory/gcp_relations/serverless.py +434 -0
- cloudg-0.5.2/cloudg/inventory/kubernetes.py +434 -0
- cloudg-0.5.2/cloudg/inventory/linker.py +518 -0
- cloudg-0.5.2/cloudg/inventory/linker_index.py +265 -0
- cloudg-0.5.2/cloudg/inventory/mapper.py +592 -0
- cloudg-0.5.2/cloudg/inventory/mapper_result.py +282 -0
- cloudg-0.5.2/cloudg/inventory/organization.py +464 -0
- cloudg-0.5.2/cloudg/inventory/organization_assets.py +239 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/schema/models.py +155 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/ui.py +48 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/docs/DOCUMENTATION.md +203 -16
- {cloudg-0.5.0 → cloudg-0.5.2}/pyproject.toml +2 -1
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/conftest.py +36 -0
- cloudg-0.5.2/tests/test_aws_application.py +1450 -0
- cloudg-0.5.2/tests/test_aws_data_ml.py +1027 -0
- cloudg-0.5.2/tests/test_aws_governance.py +1131 -0
- cloudg-0.5.2/tests/test_aws_network_ext.py +1161 -0
- cloudg-0.5.2/tests/test_azure_inventory.py +1401 -0
- cloudg-0.5.2/tests/test_catalogs_cloudcontrol.py +280 -0
- cloudg-0.5.2/tests/test_gcp_inventory.py +1220 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_inventory.py +10 -2
- cloudg-0.5.2/tests/test_inventory_deep.py +1251 -0
- cloudg-0.5.0/cloudg/collectors/azure.py +0 -363
- cloudg-0.5.0/cloudg/collectors/gcp.py +0 -170
- cloudg-0.5.0/cloudg/collectors/multi.py +0 -340
- cloudg-0.5.0/cloudg/inventory/azure_deep.py +0 -336
- cloudg-0.5.0/cloudg/inventory/gcp_deep.py +0 -97
- cloudg-0.5.0/cloudg/inventory/linker.py +0 -345
- cloudg-0.5.0/cloudg/inventory/mapper.py +0 -334
- {cloudg-0.5.0 → cloudg-0.5.2}/.gitignore +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/LICENSE +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/api.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_commands.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_helpers.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_run_helpers.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/base.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/coverage.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/credentials.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/rag_export.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/reachability.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/ingest.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/normaliser.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-aws-security.yml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-azure.yml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-gcp.yml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian.yml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/region_discovery.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/registry.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/html_report.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/json_export.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/svg.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/svg_layout.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/terraform_export.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/retry.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/check_equivalence.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_aws_v3.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_azure_v2.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_gcp_v3.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/aws_foundational_security_best_practices_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/gdpr_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/nist_800_53_revision_5_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/nist_csf_2.0_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_aws.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_azure.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_gcp.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/gdpr.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/hipaa_security_rule.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/iso_27001_2022.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/nist_800_53.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/pci_dss_v4.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/soc2_tsc.yaml +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/checkov.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/iam_linter.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/prowler.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/scoutsuite.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/trivy.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/schema/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/templates/report.html.j2 +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/__init__.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_api.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_collectors.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_ingest.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_normaliser.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_ontology.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_rag_export.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_region_discovery.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_scanner_orchestration.py +0 -0
- {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_terraform_export.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cloudg
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: cloudg (cloud graphing) - multi-cloud infrastructure mapping, knowledge graphs and security intelligence for AWS, Azure and GCP
|
|
5
5
|
Project-URL: Homepage, https://github.com/morpheuslord/cloudg
|
|
6
6
|
Project-URL: Repository, https://github.com/morpheuslord/cloudg
|
|
@@ -38,6 +38,7 @@ Requires-Dist: azure-mgmt-compute>=30.0; extra == 'all'
|
|
|
38
38
|
Requires-Dist: azure-mgmt-keyvault>=10.0; extra == 'all'
|
|
39
39
|
Requires-Dist: azure-mgmt-network>=25.0; extra == 'all'
|
|
40
40
|
Requires-Dist: azure-mgmt-resource>=23.0; extra == 'all'
|
|
41
|
+
Requires-Dist: azure-mgmt-resourcegraph>=8.0.0; extra == 'all'
|
|
41
42
|
Requires-Dist: azure-mgmt-sql>=3.0; extra == 'all'
|
|
42
43
|
Requires-Dist: azure-mgmt-storage>=21.0; extra == 'all'
|
|
43
44
|
Requires-Dist: boto3>=1.28; extra == 'all'
|
|
@@ -52,6 +53,7 @@ Requires-Dist: azure-mgmt-compute>=30.0; extra == 'azure'
|
|
|
52
53
|
Requires-Dist: azure-mgmt-keyvault>=10.0; extra == 'azure'
|
|
53
54
|
Requires-Dist: azure-mgmt-network>=25.0; extra == 'azure'
|
|
54
55
|
Requires-Dist: azure-mgmt-resource>=23.0; extra == 'azure'
|
|
56
|
+
Requires-Dist: azure-mgmt-resourcegraph>=8.0.0; extra == 'azure'
|
|
55
57
|
Requires-Dist: azure-mgmt-sql>=3.0; extra == 'azure'
|
|
56
58
|
Requires-Dist: azure-mgmt-storage>=21.0; extra == 'azure'
|
|
57
59
|
Provides-Extra: dev
|
|
@@ -80,6 +82,12 @@ cloudg (cloud graphing) maps AWS, Azure and GCP infrastructure into a graph, run
|
|
|
80
82
|
|
|
81
83
|
This is the complete reference: every CLI command, the exact input and output formats, the data models, the full Python API with integration examples, configuration, plugins and authentication. Release history lives in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md).
|
|
82
84
|
|
|
85
|
+
The inventory mapper (`cloudg map`, `cloudg deps`, `cloudg.inventory`) has three deeper companion documents:
|
|
86
|
+
|
|
87
|
+
- [Inventory reference](INVENTORY_REFERENCE.md): the structure of every return value and exported file, field by field, with annotated examples (`CloudAsset`, `NetworkEdge`, relation objects, `InventoryResult`, `summary`, coverage records, dependency trees, blast radius, security coverage, `inventory-map.json`, `inventory-graph.json`, GraphML, `inventory-organization.json`, `asset-map.json`, `compliance-map.json`, `cloudg deps --json`).
|
|
88
|
+
- [Inventory catalog](INVENTORY_CATALOG.md): all 156 asset types with the native resource types mapped to each, the metadata keys and relations each one carries, and the full relationship matrix.
|
|
89
|
+
- [Inventory internals](INVENTORY_INTERNALS.md): how a mapping run works, every module, the 133 AWS collector tasks, the linker's resolution rules, the Azure and GCP extractor frameworks, dependency semantics, catalogs, and recipes for adding collectors, extractors and asset types.
|
|
90
|
+
|
|
83
91
|
Contents:
|
|
84
92
|
|
|
85
93
|
- [Installation](#installation)
|
|
@@ -177,12 +185,15 @@ cloudg collect -p gcp --project-id <id>
|
|
|
177
185
|
|
|
178
186
|
### cloudg map
|
|
179
187
|
|
|
180
|
-
Scanner-independent inventory mapping: everything deployed or default, linked into one map. No scanner runs and none needs to be installed.
|
|
188
|
+
Scanner-independent inventory mapping: everything deployed or default, linked into one map of typed interdependencies. No scanner runs and none needs to be installed.
|
|
181
189
|
|
|
182
190
|
```bash
|
|
183
191
|
cloudg map -p aws --regions all
|
|
184
192
|
cloudg map -p all --regions all
|
|
185
|
-
cloudg map -p aws --
|
|
193
|
+
cloudg map -p aws --org --regions all # every account in the Organization / Control Tower
|
|
194
|
+
cloudg map -p aws --org --ou Workloads --exclude-account 111122223333
|
|
195
|
+
cloudg map -p aws --services containers,serverless,security # narrow the run
|
|
196
|
+
cloudg map -p aws --findings ./reports/raw-findings.json # merge scanner output
|
|
186
197
|
```
|
|
187
198
|
|
|
188
199
|
| Flag | Meaning |
|
|
@@ -190,18 +201,93 @@ cloudg map -p aws --findings ./reports/raw-findings.json # merge scanner outpu
|
|
|
190
201
|
| `-p, --provider` | `aws`, `azure`, `gcp` or `all`; repeatable |
|
|
191
202
|
| `--regions` | `all` for auto-discovery, or a comma-separated list |
|
|
192
203
|
| `--profile` | AWS CLI profile |
|
|
204
|
+
| `--accounts`, `--role-name` | AWS: explicit account list and the role to assume in each |
|
|
205
|
+
| `--org / --no-org` | AWS: discover and map every account of the Organization (run from the management account or a delegated administrator) |
|
|
206
|
+
| `--org-role` | AWS: role assumed in member accounts; defaults to `AWSControlTowerExecution` |
|
|
207
|
+
| `--ou` | AWS: only accounts under this OU (ID, ARN or name, nested OUs included); repeatable |
|
|
208
|
+
| `--exclude-account` | AWS: skip an account; repeatable |
|
|
209
|
+
| `--ct-home-region` | AWS: Control Tower home region, auto-detected when omitted |
|
|
210
|
+
| `--services`, `--exclude-services` | service families or collector names, comma-separated (see below) |
|
|
211
|
+
| `--kubernetes / --no-kubernetes` | map workloads inside EKS clusters through the Kubernetes API |
|
|
212
|
+
| `--cloud-control / --no-cloud-control` | AWS Cloud Control breadth sweep, on by default |
|
|
193
213
|
| `--subscription-id`, `--project-id` | Azure / GCP identity |
|
|
194
214
|
| `--findings` | existing cloudg findings JSON (`raw-findings.json` or a report); repeatable |
|
|
195
215
|
| `--sweep / --no-sweep` | catch-all sweep, on by default |
|
|
196
216
|
| `-o, --output` | output directory |
|
|
197
217
|
|
|
198
|
-
Coverage comes in
|
|
218
|
+
Coverage comes in four layers.
|
|
219
|
+
|
|
220
|
+
1. Dedicated deep collectors. On AWS, 133 collectors grouped into service families you can select with `--services` / `--exclude-services` (family or collector names):
|
|
221
|
+
|
|
222
|
+
| Family | Collected |
|
|
223
|
+
|---|---|
|
|
224
|
+
| `network` | VPCs, subnets, security groups, route tables, internet / NAT / egress-only gateways, ENIs, Elastic IPs, NACLs, VPC peering, transit gateways, attachments, route tables and peering, VPC endpoints and endpoint services (PrivateLink, allowed principals, consumers), managed prefix lists, ALB/NLB listeners, rules, certificates and target groups, classic ELB, CloudFront (origins, aliases, certificates, Lambda@Edge, functions, OAC, logging), Global Accelerator, VPC Lattice |
|
|
225
|
+
| `hybrid` | site-to-site VPN, customer and virtual private gateways, Direct Connect connections, VIFs and gateways, Cloud WAN / Network Manager |
|
|
226
|
+
| `compute` | EC2, Auto Scaling groups, launch templates, AMIs (with sharing), Batch, App Runner, Elastic Beanstalk |
|
|
227
|
+
| `containers` | ECR (+ public), ECS clusters, services, task definitions, capacity providers, container instances, Cloud Map, EKS clusters, nodegroups, Fargate profiles, addons, access entries, pod identity |
|
|
228
|
+
| `kubernetes` | inside EKS clusters: namespaces, Deployments, StatefulSets, DaemonSets, CronJobs, Services, Ingresses, ServiceAccounts |
|
|
229
|
+
| `serverless` | Lambda (triggers, URLs, images, layers, DLQs, aliases), API Gateway REST / HTTP APIs, authorizers, VPC links and custom domains, Step Functions |
|
|
230
|
+
| `integration` | SQS, SNS, EventBridge buses, rules, archives, API destinations, Scheduler, Pipes, Kinesis, Firehose, MSK, Amazon MQ |
|
|
231
|
+
| `storage` | S3 (notifications, replication, logging, account and bucket Block Public Access), access points and multi-region access points, EBS volumes and snapshots, EFS, FSx, Transfer Family, DataSync |
|
|
232
|
+
| `data` | RDS, Aurora, proxies, global clusters, manual snapshot sharing, DynamoDB (KMS, streams, replicas, PITR, policies), ElastiCache, MemoryDB, DAX, OpenSearch (+ Serverless), Redshift (+ Serverless) |
|
|
233
|
+
| `analytics`, `ml` | Glue, Lake Formation permissions, EMR (+ Serverless), Athena; SageMaker, Bedrock agents, knowledge bases, guardrails and invocation logging |
|
|
234
|
+
| `identity` | the IAM graph (users, groups, roles, trust, grants, instance profiles, OIDC and SAML providers, access key metadata), IAM Identity Center (instances, permission sets, assignments, users, groups), Roles Anywhere, Cognito user and identity pools, KMS (aliases, rotation, key policy and grant principals), Secrets Manager, ACM |
|
|
235
|
+
| `governance` | RAM resource shares, Service Catalog portfolios and provisioned products (Account Factory), CloudFormation StackSets |
|
|
236
|
+
| `security` | GuardDuty, Security Hub, Inspector (per-resource coverage), Macie, AWS Config, IAM Access Analyzer, Detective, WAF, Network Firewall, Shield Advanced |
|
|
237
|
+
| `logging`, `operations`, `backup` | CloudTrail, flow logs, log groups, subscription filters and destinations, cross-account observability (OAM); CloudWatch alarms, SSM parameters (metadata only), managed instances, documents, associations, maintenance windows; AWS Backup plans, selections and vaults |
|
|
238
|
+
| `dns`, `iac`, `cicd` | Route 53 zones and records, Resolver endpoints, rules and DNS Firewall; CloudFormation stacks and the resources they manage; CodePipeline, CodeBuild, CodeDeploy, CodeConnections |
|
|
239
|
+
|
|
240
|
+
Account-wide services are collected once per account, in the primary region, so `--regions all` does not repeat them. Security services that are not enabled appear as placeholder nodes with `enabled: false`, so detection gaps show on the map. Values that could be secret (parameter values, environment variables, passwords, VPN pre-shared keys, Direct Connect auth keys) are never collected.
|
|
199
241
|
|
|
200
|
-
|
|
201
|
-
2. Catch-all sweeps. The AWS Resource Groups Tagging API, Azure Resource Manager's full `resources.list()`, and GCP Cloud Asset Inventory each enumerate every resource in scope, so services without a dedicated collector still appear on the map (classified by ARN/ARM/asset type, or `OTHER`). A sweep hit that duplicates a dedicated collector's asset is dropped; the richer asset wins.
|
|
202
|
-
3. The relationship linker. A post-collection pass that derives edges purely from asset metadata: instance → security group (`ATTACHED_TO`), subnet ⊃ resource (`CONTAINS`), route table → gateway (`ROUTE`), Lambda → execution role, secret → KMS key, CloudFront → origin (`REFERENCES`), VPC peering (`PEERING`), Azure VM → NIC → NSG/subnet/public IP chains, GCP parent containment and IAM policy bindings, and finally a generic pass that resolves any ARN, Azure resource ID or GCP resource name found in one asset's metadata to another collected asset.
|
|
242
|
+
Azure is collected through Azure Resource Graph (`azure-mgmt-resourcegraph`, in the `azure` extra) with every resource's full properties, so PaaS services get real relationships: managed identities and role assignments (principal → scope, with role names), private endpoints, AKS node pools, kubelet identity and ACR pulls, App Service plans, VNet integration and container images, Container Apps, subnets, peering, NICs, disks and disk encryption sets, firewalls and route-table next hops, Application Gateway and Front Door backends and WAF policies, Key Vault access policies, storage and SQL network rules, Defender for Cloud plans per subscription. Every Enabled subscription is collected when none are configured (`azure.all_subscriptions`), and the management group → subscription → resource group hierarchy, Azure Landing Zone archetypes and Azure Policy assignments and exemptions are mapped (`azure.map_management_groups`). Without the Resource Graph SDK, cloudg falls back to the per-service SDK collectors plus the ARM sweep. Permissions: Reader at the tenant root management group (Resource Graph scopes to what the credential can read).
|
|
203
243
|
|
|
204
|
-
|
|
244
|
+
GCP is collected through Cloud Asset Inventory `list_assets` with the full resource JSON, once at `organizations/<organization_id>` when that is set (`gcp.collection_scope`), otherwise per project. Relations cover instances (service accounts, subnets, disks, external IPs), firewall semantics (target tags and service accounts, source ranges, priorities), the load-balancing chain down to NEGs and Cloud Armor, managed instance groups and templates, GKE clusters and node pools with Workload Identity, Cloud Run and Functions v2 (service accounts, images in Artifact Registry, secrets, VPC connectors, triggers), Pub/Sub (subscriptions, push endpoints, dead-letter and export targets), Eventarc, logging sinks, CMEK keys, Shared VPC, Cloud SQL / Redis / Filestore networks and DNS zones. IAM bindings resolve to service accounts or to principal nodes (users, groups, workload identity pools); only `allUsers` / `allAuthenticatedUsers` mark a resource internet-exposed. With an organization ID, the organization → folder → project tree, organization policies and VPC Service Controls perimeters are mapped too (`gcp.map_hierarchy`, `org_policies`, `vpc_service_controls`). Permissions: `roles/cloudasset.viewer` on the organization (or each project) and the Cloud Asset API enabled on the quota project.
|
|
245
|
+
2. Breadth sweeps, so services without a dedicated collector still appear on the map.
|
|
246
|
+
- AWS Cloud Control API: every CloudFormation resource type with a list handler (800+ types) is listed, tagged or not. Types already mapped by a deep collector are skipped, account-wide types run once per account, types that need a parent identifier or fail are skipped and counted in coverage (`cloud_control_skipped_types`). The listable-type catalogue is discovered once and cached for a week (`$CLOUDG_CACHE_DIR`, default `~/.cache/cloudg`). Secret-bearing properties (passwords, tokens, SSM parameter values, environment variables, user data) are never copied. Turn it off with `--no-cloud-control`, or narrow it with `inventory.cloud_control_types` / `cloud_control_exclude` (type names or prefixes such as `AWS::Glue::`).
|
|
247
|
+
- AWS Resource Groups Tagging API: tagged resources only (AWS never returns resources that were never tagged), kept for tag enrichment.
|
|
248
|
+
- Azure Resource Manager's full `resources.list()` and GCP Cloud Asset Inventory enumerate their scopes.
|
|
249
|
+
|
|
250
|
+
Precedence when the same resource is found twice: dedicated collector, then Cloud Control, then the tagging API.
|
|
251
|
+
3. The relationship linker. Collectors declare what each asset talks to; the linker resolves those identifiers across services, regions and accounts into typed edges, then applies provider rules and a generic reference pass. See [Relationships](#relationships) below.
|
|
252
|
+
4. Account hierarchy. Every account gets a `CLOUD_ACCOUNT` node that contains its top-level resources. With `--org`, accounts hang under the OU tree, next to SCPs, the Control Tower landing zone and its enabled controls.
|
|
253
|
+
|
|
254
|
+
Outputs: `inventory-map.json` (assets, edges, unresolved references, and a summary covering services, types, regions, accounts, relationship counts, cross-account edges, external accounts, security service gaps, internet exposure and unlinked assets), `inventory-map.graphml`, `inventory-graph.json` (D3, with account and relationship attributes), `inventory-dependencies.json` (most shared dependencies, largest blast radius, cross-account edges, security coverage including workloads no vulnerability scanner covers and internet-facing endpoints without a WAF), and with `--org` `inventory-organization.json`. With `--findings`, additionally `asset-map.json` (per-asset finding counts and severity breakdowns, riskiest first) and `compliance-map.json` (framework → findings and affected assets). The map does not depend on the scanners; findings from any earlier run merge in whenever they exist.
|
|
255
|
+
|
|
256
|
+
#### Relationships
|
|
257
|
+
|
|
258
|
+
Every edge has a coarse `edge_type` and, when known, a fine-grained `relationship` (an ontology relation name) plus `properties`. Direction always reads "source verb target".
|
|
259
|
+
|
|
260
|
+
| Edge type | Example |
|
|
261
|
+
|---|---|
|
|
262
|
+
| `INVOKES` | S3 bucket → Lambda (notification), SQS → Lambda (`TRIGGERED_BY`, event source mapping), SNS → SQS (`STREAMS_TO`), EventBridge rule → target, API Gateway → Lambda, Step Functions → anything its definition calls |
|
|
263
|
+
| `USES_IMAGE` | task definition / Kubernetes workload / Lambda → ECR repository |
|
|
264
|
+
| `ASSUMES_ROLE` | Lambda, task definition, nodegroup, Kubernetes service account (IRSA or Pod Identity), instance profile → IAM role |
|
|
265
|
+
| `IAM_TRUST` | principal / external account / OIDC provider → role it may assume (`CROSS_ACCOUNT_TRUST` across accounts) |
|
|
266
|
+
| `GRANTS_ACCESS` | principal → resource its policy names; principal → EKS cluster (access entry, with access policies); bucket / queue / repository policy grants |
|
|
267
|
+
| `IAM_POLICY_ATTACHMENT` | user, group or role → managed policy |
|
|
268
|
+
| `PROTECTS` | WAF → ALB / API Gateway / CloudFront, Network Firewall → VPC, Shield → resource |
|
|
269
|
+
| `MONITORS` | Inspector → each scanned EC2 / ECR / Lambda, GuardDuty / Config / CloudTrail / Macie → account, Security Hub → the services it ingests from, flow log → VPC/subnet/ENI |
|
|
270
|
+
| `MANAGES` | CloudFormation stack → resource, ASG → instance, nodegroup → ASG, landing zone → OUs and shared accounts |
|
|
271
|
+
| `GOVERNS` | SCP / RCP / tag policy and Control Tower control or baseline → OU or account |
|
|
272
|
+
| `LOGS_TO` | trail, flow log, load balancer, API stage, task definition, function → log destination |
|
|
273
|
+
| `LOAD_BALANCER_TARGET` | load balancer → target group → instance / IP / Lambda, Kubernetes Service → workload |
|
|
274
|
+
| `ROUTE` | route table → gateway, DNS record → load balancer / distribution, transit gateway → attached VPC, Ingress → Service |
|
|
275
|
+
| `CONTAINS`, `ATTACHED_TO`, `PEERING`, `REFERENCES` | containment, security-group attachment, VPC peering, everything else (KMS keys, secrets, DLQs, layers, ...) |
|
|
276
|
+
|
|
277
|
+
Identifier resolution is scoped: an ambiguous name such as `default` resolves within the referencing asset's account and region, and is left unresolved rather than guessed when it could belong to several accounts. References into accounts that were not mapped become `CLOUD_ACCOUNT` nodes with `external: true`, so a role trusted by a vendor account or a bucket replicating to another account stays visible. References that resolve to nothing (a deleted queue still configured as a DLQ) are listed under `unresolved_references`.
|
|
278
|
+
|
|
279
|
+
### cloudg deps
|
|
280
|
+
|
|
281
|
+
Interdependency queries over a saved map; no cloud access needed.
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
cloudg deps arn:aws:iam::123456789012:role/app-role # both directions
|
|
285
|
+
cloudg deps jobs-queue --direction down --depth 5 # blast radius
|
|
286
|
+
cloudg deps --map ./reports # overview
|
|
287
|
+
cloudg deps my-function --direction up --json # machine-readable
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Each edge is read as "dependent needs dependency": a function needs its role, image, key and the queue that triggers it; an ALB needs the WAF protecting it; a resource needs the stack managing it. `--direction up` shows what an asset needs, `down` what needs it (what breaks or changes with it), `both` the two trees. Without an asset, `deps` prints the most shared dependencies (one KMS key behind forty resources), the largest blast radius, and every cross-account edge. Assets are matched by ARN or resource ID, internal ID, or a unique name.
|
|
205
291
|
|
|
206
292
|
### cloudg scan
|
|
207
293
|
|
|
@@ -318,8 +404,12 @@ All commands write into the output directory (`./reports` by default).
|
|
|
318
404
|
| `rag_chunks.jsonl`, `rag_metadata_index.json` | retrieval-ready chunks, one JSON object per line |
|
|
319
405
|
| `terraform/*.tf.json`, `terraform/import.sh` | Terraform recreation of live infrastructure, 25+ asset types |
|
|
320
406
|
| `inventory-map.json`, `inventory-map.graphml`, `inventory-graph.json` | scanner-independent inventory map: assets, interconnections, summary (`cloudg map`) |
|
|
407
|
+
| `inventory-dependencies.json` | shared dependencies, blast radius, cross-account edges, security service coverage (`cloudg map`) |
|
|
408
|
+
| `inventory-organization.json` | AWS Organization / Control Tower topology (`cloudg map --org`) |
|
|
321
409
|
| `asset-map.json`, `compliance-map.json` | inventory overlaid with scanner findings (`cloudg map --findings`) |
|
|
322
410
|
|
|
411
|
+
The inventory files are specified field by field in the [inventory reference](INVENTORY_REFERENCE.md).
|
|
412
|
+
|
|
323
413
|
`findings.json` has this shape:
|
|
324
414
|
|
|
325
415
|
```json
|
|
@@ -381,17 +471,44 @@ The unit every scanner and parser produces.
|
|
|
381
471
|
| `id` | `str` | auto UUID |
|
|
382
472
|
| `arn` | `str \| None` | native identifier |
|
|
383
473
|
| `name` | `str` | |
|
|
384
|
-
| `asset_type` | `AssetType` |
|
|
474
|
+
| `asset_type` | `AssetType` | 156-value taxonomy covering compute, networking, storage, databases, IAM and identity federation, keys and secrets, logging, containers and Kubernetes, integration, data and ML platforms, DNS and deployment, security services and scanners, organization and governance, hybrid networking, `OTHER`; the full list with what maps to each is in the [inventory catalog](INVENTORY_CATALOG.md#asset-types-by-category) |
|
|
385
475
|
| `provider` | `CloudProvider` | `AWS`, `AZURE`, `GCP` |
|
|
386
476
|
| `region` | `str` | `"global"` for regionless resources |
|
|
387
477
|
| `account_id` | `str \| None` | |
|
|
388
478
|
| `tags` | `dict[str, str]` | |
|
|
389
|
-
| `metadata` | `dict[str, Any]` | normalised extra attributes |
|
|
390
|
-
| `
|
|
479
|
+
| `metadata` | `dict[str, Any]` | normalised extra attributes; inventory assets also carry declared `relations` and identifier `aliases` |
|
|
480
|
+
| `collected_at` | `datetime` | when the asset was built |
|
|
481
|
+
| `is_internet_exposed` | `bool` | set by the collector or the graph analysis |
|
|
482
|
+
| `raw_data` | `dict[str, Any]` | raw API payload, never serialised |
|
|
483
|
+
| `display_id` | computed `str` | `arn` or `id` |
|
|
484
|
+
|
|
485
|
+
`id` is regenerated on every run; correlate assets across runs by `arn`.
|
|
391
486
|
|
|
392
487
|
### NetworkEdge
|
|
393
488
|
|
|
394
|
-
Directed edge between two asset IDs
|
|
489
|
+
Directed edge between two asset IDs (`source_id`, `target_id`); direction always reads "source verb target".
|
|
490
|
+
|
|
491
|
+
| Field | Type | Notes |
|
|
492
|
+
|---|---|---|
|
|
493
|
+
| `id` | `str` | auto UUID |
|
|
494
|
+
| `source_id`, `target_id` | `str` | asset IDs; network rule edges can use a CIDR or native security group ID as an endpoint |
|
|
495
|
+
| `edge_type` | `EdgeType` | coarse class, below |
|
|
496
|
+
| `relationship` | `str \| None` | fine-grained ontology relation (`TRIGGERED_BY`, `RUNS_ON`, `CROSS_ACCOUNT_TRUST`, `ENCRYPTED_BY_KMS`, ...) |
|
|
497
|
+
| `properties` | `dict[str, Any]` | relation detail: trust conditions, granted actions, EKS access policies, notification events, `cross_account`, `external_reference`, `hierarchy` |
|
|
498
|
+
| `description` | `str \| None` | human-readable explanation |
|
|
499
|
+
| `ports`, `port_range`, `protocol`, `cidr`, `direction` | | network rule edges |
|
|
500
|
+
|
|
501
|
+
`edge_type` values:
|
|
502
|
+
|
|
503
|
+
| Group | Values |
|
|
504
|
+
|---|---|
|
|
505
|
+
| Network | `SECURITY_GROUP_RULE`, `NACL_RULE`, `ROUTE`, `PEERING`, `LOAD_BALANCER_TARGET`, `INTERNET_EXPOSED` |
|
|
506
|
+
| Structure | `CONTAINS`, `ATTACHED_TO`, `REFERENCES` |
|
|
507
|
+
| Identity | `IAM_TRUST`, `IAM_POLICY_ATTACHMENT`, `ASSUMES_ROLE`, `GRANTS_ACCESS` |
|
|
508
|
+
| Workload | `INVOKES`, `USES_IMAGE`, `LOGS_TO` |
|
|
509
|
+
| Security and governance | `PROTECTS`, `MONITORS`, `MANAGES`, `GOVERNS` |
|
|
510
|
+
|
|
511
|
+
What each one means, its typical endpoints and how it counts for dependency analysis is in the [inventory reference](INVENTORY_REFERENCE.md#6-edge-types-and-direction); every observed source type → relationship → target type combination is in the [relationship matrix](INVENTORY_CATALOG.md#relationship-matrix).
|
|
395
512
|
|
|
396
513
|
### ComplianceResult
|
|
397
514
|
|
|
@@ -418,6 +535,17 @@ aws:
|
|
|
418
535
|
profile: null
|
|
419
536
|
max_retries: 10
|
|
420
537
|
retry_mode: adaptive
|
|
538
|
+
organization: # AWS Organizations / Control Tower (cloudg map)
|
|
539
|
+
enabled: false
|
|
540
|
+
role_name: null # default AWSControlTowerExecution
|
|
541
|
+
include_ous: [] # IDs, ARNs or names; nested OUs included
|
|
542
|
+
exclude_accounts: []
|
|
543
|
+
include_management_account: true
|
|
544
|
+
include_suspended: false
|
|
545
|
+
use_governed_regions: true # regions [all] -> Control Tower governed regions
|
|
546
|
+
control_tower: true
|
|
547
|
+
home_region: null # auto-detected
|
|
548
|
+
map_structure: true # org, OU, account, SCP, control nodes
|
|
421
549
|
|
|
422
550
|
azure:
|
|
423
551
|
subscription_ids: []
|
|
@@ -427,10 +555,19 @@ azure:
|
|
|
427
555
|
certificate_path: null
|
|
428
556
|
federated_token_file: null
|
|
429
557
|
use_managed_identity: false
|
|
558
|
+
all_subscriptions: true # every Enabled subscription when subscription_ids is empty
|
|
559
|
+
map_management_groups: true # management groups, subscriptions, Azure Policy
|
|
430
560
|
regions: [ALL]
|
|
431
561
|
|
|
432
562
|
gcp:
|
|
433
563
|
project_ids: []
|
|
564
|
+
organization_id: null # set to collect org-wide and map folders / org policy
|
|
565
|
+
collection_scope: auto # auto | organization | project
|
|
566
|
+
skip_asset_types: [...] # high-churn types (Pods, ReplicaSets, Events, ...) by default
|
|
567
|
+
iam_policies: true
|
|
568
|
+
map_hierarchy: true
|
|
569
|
+
org_policies: true
|
|
570
|
+
vpc_service_controls: true
|
|
434
571
|
credentials_file: null
|
|
435
572
|
impersonate_service_account: null
|
|
436
573
|
regions: [ALL]
|
|
@@ -446,6 +583,18 @@ scanners:
|
|
|
446
583
|
inventory:
|
|
447
584
|
tagging_sweep: true # AWS catch-all sweep (Resource Groups Tagging API)
|
|
448
585
|
link_references: true # generic cross-service REFERENCES edges
|
|
586
|
+
services: [all] # families or collector names (see cloudg map)
|
|
587
|
+
exclude_services: []
|
|
588
|
+
kubernetes: true # workloads inside EKS clusters
|
|
589
|
+
kubernetes_timeout: 10
|
|
590
|
+
iam_resource_edges: true # principal -> granted resource edges
|
|
591
|
+
max_images_per_repository: 20
|
|
592
|
+
stack_resources: true # CloudFormation stack -> resource edges
|
|
593
|
+
account_hierarchy: true # account nodes containing top-level resources
|
|
594
|
+
cloud_control: true # AWS breadth sweep over every listable resource type
|
|
595
|
+
cloud_control_types: [] # only these CloudFormation types / prefixes
|
|
596
|
+
cloud_control_exclude: []
|
|
597
|
+
cloud_control_concurrency: 6
|
|
449
598
|
|
|
450
599
|
graph:
|
|
451
600
|
persist_graphml: true
|
|
@@ -550,7 +699,32 @@ print(inventory.summary) # services, types, regions, exposur
|
|
|
550
699
|
inventory.export("./reports") # inventory-map.json / .graphml / graph
|
|
551
700
|
```
|
|
552
701
|
|
|
553
|
-
`InventoryResult` carries `assets`, `edges`, `coverage`, `providers`, `regions` and a computed `summary` (totals, per-service/type/region/account breakdowns, edge types, internet-exposed and unlinked counts). `export(dir)` writes `inventory-map.json`, `inventory-map.graphml` and `inventory-
|
|
702
|
+
`InventoryResult` carries `assets`, `edges`, `coverage`, `providers`, `regions`, `organization` (the discovered topology, when mapped) and `unresolved_references`, plus a computed `summary` (totals, per-service/type/region/account breakdowns, edge types and relationships, cross-account edges, external accounts, security service gaps, internet-exposed and unlinked counts). `export(dir)` writes `inventory-map.json`, `inventory-map.graphml`, `inventory-graph.json`, `inventory-dependencies.json` and, for an organization, `inventory-organization.json`; `InventoryResult.load(dir_or_file)` reads a map back.
|
|
703
|
+
|
|
704
|
+
Interdependency questions go through `DependencyGraph`:
|
|
705
|
+
|
|
706
|
+
```python
|
|
707
|
+
graph = inventory.dependency_graph()
|
|
708
|
+
role = graph.find("arn:aws:iam::123456789012:role/app-role")
|
|
709
|
+
needs = graph.depends_on(role.id) # upstream, breadth-first
|
|
710
|
+
needed_by = graph.dependents(role.id) # downstream: blast radius
|
|
711
|
+
view = graph.tree(role.id, direction="both", max_depth=3)
|
|
712
|
+
graph.shared_dependencies(top=25)
|
|
713
|
+
graph.blast_radius(top=25)
|
|
714
|
+
inventory.analysis() # everything above + coverage
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
Organizations and Control Tower discovery is usable on its own:
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
import boto3
|
|
721
|
+
from cloudg.inventory import discover_organization
|
|
722
|
+
|
|
723
|
+
topology = discover_organization(boto3.Session())
|
|
724
|
+
topology.governed_regions, topology.shared_accounts # Control Tower
|
|
725
|
+
topology.target_accounts(include_ous=["Workloads"]) # nested OUs included
|
|
726
|
+
assets = topology.to_assets() # org, OUs, accounts, SCPs, controls
|
|
727
|
+
```
|
|
554
728
|
|
|
555
729
|
Merging scanner findings (from `scan()`, `ingest_reports()`, or a saved `raw-findings.json`) happens after the fact, so the mapper never touches the scanners:
|
|
556
730
|
|
|
@@ -565,10 +739,18 @@ mapper.export_merged(inventory, findings, "./reports") # asset-map.json
|
|
|
565
739
|
```python
|
|
566
740
|
linker = RelationshipLinker(assets)
|
|
567
741
|
linker.seed_existing(existing_edges) # don't duplicate edges you already have
|
|
568
|
-
edges = linker.link() #
|
|
742
|
+
edges = linker.link() # typed edges, see Relationships
|
|
743
|
+
linker.external_assets # placeholder nodes for unmapped accounts
|
|
744
|
+
linker.unresolved # declared references that resolved to nothing
|
|
569
745
|
```
|
|
570
746
|
|
|
571
|
-
|
|
747
|
+
Reference data lives in YAML catalogs under `cloudg/inventory/catalogs/` rather than in code: `aws_cloudcontrol.yaml` (types the deep collectors already cover, account-wide types, CloudFormation type → asset type, per-type secret fields), `aws_arn_types.yaml` (ARN → asset type for sweep hits), `azure_arm_types.yaml` (ARM resource type → asset type) and `gcp_asset_types.yaml` (Cloud Asset Inventory type → asset type). Point `$CLOUDG_CATALOG_DIR` at a directory holding files of the same names to extend or override them without touching cloudg: mappings merge key by key, lists are extended. Unknown asset type names are rejected at load time.
|
|
748
|
+
|
|
749
|
+
Your own collectors can declare relationships the same way the built-in ones do, by listing them in `metadata["relations"]`: `{"target": <any identifier>, "edge": "INVOKES", "relationship": "TRIGGERED_BY", "reverse": false}`.
|
|
750
|
+
|
|
751
|
+
The deep collectors are public too, when you want single-region, single-account control: `AWSDeepInventoryCollector(session, region="us-east-1", account_id=None, tagging_sweep=True, **options)` (keyword options `is_primary_region`, `services`, `exclude_services`, `kubernetes`, `kubernetes_timeout`, `iam_resource_edges`, `max_images_per_repository`, `stack_resources`, `cloud_control`, `cloud_control_types`, `cloud_control_exclude`, `cloud_control_concurrency`; an unknown option raises `TypeError`), `AzureDeepInventoryCollector(credential, subscription_id, graph_client_factory=None, use_resource_graph=True)` and `GCPDeepInventoryCollector(project_id, credentials=None, **options)` (keyword options `organization_id`, `scope`, `project_filter`, `skip_asset_types`, `page_size`, `include_iam`, `client`, `coverage`, `timeout`, `link_locally`) all implement the standard `collect()` / `collect_edges()` / `run()` collector interface. Their assets carry declared relations; pass them through `RelationshipLinker` for the typed edges.
|
|
752
|
+
|
|
753
|
+
Every structure above, from `summary` to the dependency tree, is specified field by field in the [inventory reference](INVENTORY_REFERENCE.md).
|
|
572
754
|
|
|
573
755
|
### The deeper toolkit
|
|
574
756
|
|
|
@@ -584,6 +766,11 @@ Modules the pipeline uses internally that are equally useful standalone:
|
|
|
584
766
|
| `cloudg.normaliser` | `FindingsNormaliser` | the full dedupe / cross-scanner merge / CVSS rescore / compliance mapping pass, on any `list[Finding]` |
|
|
585
767
|
| `cloudg.ingest` | `parse_report`, `ingest_reports` | every scanner's parser, standalone; no engine, no credentials |
|
|
586
768
|
| `cloudg.coverage` | `CollectionCoverage` | per-service success/failure/asset-count records every collector produces |
|
|
769
|
+
| `cloudg.inventory.dependencies` | `DependencyGraph`, `cross_account_edges`, `security_coverage` | dependency walks, shared dependencies, blast radius, cross-account edges and security service coverage over any assets and edges |
|
|
770
|
+
| `cloudg.inventory.linker` | `RelationshipLinker` | resolve declared relations and identifiers across services, regions and accounts into typed edges |
|
|
771
|
+
| `cloudg.inventory.organization` | `discover_organization`, `OrganizationTopology` | AWS Organizations and Control Tower discovery, account selection, map nodes |
|
|
772
|
+
| `cloudg.inventory.kubernetes` | `collect_eks_workloads`, `KubernetesReader` | read-only Kubernetes object mapping for EKS clusters |
|
|
773
|
+
| `cloudg.inventory.catalogs` | `load_catalog`, `asset_type_map` | the YAML reference catalogs with `$CLOUDG_CATALOG_DIR` overlays |
|
|
587
774
|
| `cloudg.registry` | `PluginRegistry` | entry-point discovery of collector and scanner plugins |
|
|
588
775
|
|
|
589
776
|
### PipelineResult
|
|
@@ -795,13 +982,15 @@ myscanner = "my_package.scanner:MyScanner"
|
|
|
795
982
|
mycloud = "my_package.collector:MyCollector"
|
|
796
983
|
```
|
|
797
984
|
|
|
798
|
-
After `pip install`, the name is available in `scanners.enabled` and `--scanners`. Collectors follow the base interface in `cloudg/collectors/base.py`. If your scanner emits a stable check ID in `source_finding_id`, you can add it to `rules/check_equivalence.yaml` so its findings merge with equivalent checks from other tools.
|
|
985
|
+
After `pip install`, the name is available in `scanners.enabled` and `--scanners`. Collectors follow the base interface in `cloudg/collectors/base.py`. A collector plugin's assets join the inventory map like the built-in ones: declare what each asset talks to in `metadata["relations"]` and extra identifiers in `metadata["aliases"]`, and the relationship linker resolves them (see [Inventory internals](INVENTORY_INTERNALS.md#156-declare-relations-from-your-own-collector-or-plugin)). If your scanner emits a stable check ID in `source_finding_id`, you can add it to `rules/check_equivalence.yaml` so its findings merge with equivalent checks from other tools.
|
|
799
986
|
|
|
800
987
|
## Authentication
|
|
801
988
|
|
|
802
989
|
Every provider supports several methods, resolved in a fixed priority order, so the same config works on a laptop, in CI and on cloud compute.
|
|
803
990
|
|
|
804
|
-
AWS, in priority order: direct keys (`--aws-key`, `--aws-secret`, `--aws-session-token` or the standard env vars); OIDC web identity federation (`--aws-role-arn` with `--aws-web-identity-token-file`, the GitHub Actions, GitLab CI and EKS pattern with no long-lived keys); a named CLI profile via `--profile`, SSO included; or nothing, letting the default chain pick up env vars, cached SSO or the instance role. On top of any of these, STS role assumption with `--aws-role-arn` and, for the third-party auditor pattern, `--aws-external-id`. Multi-account fan-out uses `accounts` plus `role_name` in the config, assuming that role in each account before collecting.
|
|
991
|
+
AWS, in priority order: direct keys (`--aws-key`, `--aws-secret`, `--aws-session-token` or the standard env vars); OIDC web identity federation (`--aws-role-arn` with `--aws-web-identity-token-file`, the GitHub Actions, GitLab CI and EKS pattern with no long-lived keys); a named CLI profile via `--profile`, SSO included; or nothing, letting the default chain pick up env vars, cached SSO or the instance role. On top of any of these, STS role assumption with `--aws-role-arn` and, for the third-party auditor pattern, `--aws-external-id`. Multi-account fan-out uses `accounts` plus `role_name` in the config, assuming that role in each account before collecting; the caller's own account is collected with the base credentials.
|
|
992
|
+
|
|
993
|
+
AWS Organizations and Control Tower: run `cloudg map --org` with credentials for the management account (Organizations APIs also work from a delegated administrator; the Control Tower APIs need the management account). cloudg lists the org read-only (`organizations:Describe*`/`List*`, `controltower:List*`/`Get*`) and then assumes the member role in each selected account. `AWSControlTowerExecution` exists in every account Control Tower enrolled, but it carries administrator permissions; the `aws-controltower-ReadOnlyExecutionRole` cannot be used directly because it only trusts a Lambda-only role in the audit account. For production, deploy a dedicated read-only role (for example `cloudg-readonly` with the `SecurityAudit` and `ViewOnlyAccess` managed policies, trusting the management account) to all accounts with a service-managed CloudFormation StackSet targeting your OUs, and pass it with `--org-role cloudg-readonly`. Mapping Kubernetes workloads additionally needs an EKS access entry for that role with `AmazonEKSViewPolicy`.
|
|
805
994
|
|
|
806
995
|
Azure, in priority order: workload identity federation (`--azure-tenant-id`, `--azure-client-id`, `--azure-federated-token-file`); a service principal with a client secret (`--azure-client-secret`) or a certificate (`--azure-cert-path`); managed identity (`--azure-managed-identity`, with `managed_identity_client_id` in config for user-assigned identities); or the `DefaultAzureCredential` chain, which covers `az login`.
|
|
807
996
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT"></a>
|
|
7
7
|
<img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+">
|
|
8
|
-
<img src="https://img.shields.io/badge/version-0.5.
|
|
8
|
+
<img src="https://img.shields.io/badge/version-0.5.2-4c1.svg" alt="Version 0.5.2">
|
|
9
9
|
<a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ One command collects assets from every configured provider in parallel, feeds th
|
|
|
20
20
|
|
|
21
21
|
Need the map without the security tooling? `cloudg map` is a scanner-independent inventory mapper: it deep-collects everything deployed (or default) in an account, down to the network fabric, sweeps every service for the rest, and links it all into one asset map you can overlay with scanner findings later. See [Inventory mapping](#inventory-mapping).
|
|
22
22
|
|
|
23
|
-
**Full documentation:** the rendered handbook lives at [morpheuslord.github.io/cloudg](https://morpheuslord.github.io/cloudg/), with the same content as markdown in the [feature reference](https://github.com/morpheuslord/cloudg/blob/main/docs/DOCUMENTATION.md) and release notes in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md).
|
|
23
|
+
**Full documentation:** the rendered handbook lives at [morpheuslord.github.io/cloudg](https://morpheuslord.github.io/cloudg/), with the same content as markdown in the [feature reference](https://github.com/morpheuslord/cloudg/blob/main/docs/DOCUMENTATION.md) and release notes in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md). The inventory mapper has its own deep-dive documents: the [inventory reference](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_REFERENCE.md) (every return structure and output file, field by field), the [inventory catalog](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_CATALOG.md) (all 156 asset types, their metadata and relationships) and the [inventory internals](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_INTERNALS.md) (how it works and how to extend it).
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -77,24 +77,31 @@ docker compose run --rm cloudg run -p aws --regions us-east-1
|
|
|
77
77
|
|
|
78
78
|
## Inventory mapping
|
|
79
79
|
|
|
80
|
-
`cloudg map` answers a different question than `cloudg run`: what exists, and how is it wired together. Finding out what is wrong stays the scanners' job, and none of them runs here or even needs to be installed.
|
|
80
|
+
`cloudg map` answers a different question than `cloudg run`: what exists, and how is it wired together. Finding out what is wrong stays the scanners' job, and none of them runs here or even needs to be installed. What makes the map complete:
|
|
81
81
|
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
82
|
+
- Deep service collectors. Containers (ECR repositories, ECS services and task definitions, EKS clusters, nodegroups, Fargate profiles, addons, access entries) and the Kubernetes workloads running inside EKS; Lambda with its triggers, function URLs, images and layers; API Gateway, SQS, SNS, EventBridge, Step Functions, Kinesis; data stores; Route 53; CloudFormation stacks and the resources they manage; the whole IAM graph; and the security services and scanners watching the account (GuardDuty, Security Hub, Inspector, Macie, Config, Access Analyzer, WAF, Network Firewall, Shield, CloudTrail), including where they are not enabled.
|
|
83
|
+
- Breadth across every service. On AWS, a Cloud Control API sweep lists every resource type that supports listing (800+), tagged or not, next to 133 dedicated collectors. Azure is read through Azure Resource Graph across every subscription and management group, GCP through Cloud Asset Inventory across the whole organization, both with full resource properties.
|
|
84
|
+
- Every account at once. `--org` discovers the AWS Organization from the management account (OU tree, accounts, SCPs, and the Control Tower landing zone with its governed regions and enabled controls) and maps every member account.
|
|
85
|
+
- Typed interdependencies. Edges say what they mean: S3 `INVOKES` Lambda, task definition `USES_IMAGE` ECR repository, function `ASSUMES_ROLE` role, WAF `PROTECTS` ALB, Inspector `MONITORS` instance, stack `MANAGES` resource, SCP `GOVERNS` OU, plus cross-account trust to accounts you did not map. `cloudg deps` then answers "what does this need" and "what breaks if it goes".
|
|
85
86
|
|
|
86
87
|
```bash
|
|
87
88
|
# map one provider
|
|
88
89
|
cloudg map -p aws --regions all
|
|
89
90
|
|
|
91
|
+
# every account in the AWS Organization / Control Tower landing zone
|
|
92
|
+
cloudg map -p aws --org --regions all
|
|
93
|
+
|
|
90
94
|
# map everything, everywhere
|
|
91
95
|
cloudg map -p all --regions all
|
|
92
96
|
|
|
97
|
+
# what depends on this role, and what does it depend on?
|
|
98
|
+
cloudg deps arn:aws:iam::123456789012:role/app-role
|
|
99
|
+
|
|
93
100
|
# overlay scanner findings you generated earlier -> asset map + compliance map
|
|
94
101
|
cloudg map -p aws --regions all --findings ./reports/raw-findings.json
|
|
95
102
|
```
|
|
96
103
|
|
|
97
|
-
Outputs: `inventory-map.json` (assets, interconnections, summary), `inventory-map.graphml`,
|
|
104
|
+
Outputs: `inventory-map.json` (assets, interconnections, summary), `inventory-map.graphml`, `inventory-graph.json` for viewers, `inventory-dependencies.json` (shared dependencies, blast radius, cross-account edges, security coverage gaps) and, with `--org`, `inventory-organization.json`. With `--findings`, additionally `asset-map.json` (each asset with its findings and severity breakdown) and `compliance-map.json` (framework → affected assets). The map never depends on the scanners; you can map today and merge in findings from a scan you run next week. Every file is specified field by field, with annotated examples, in the [inventory reference](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_REFERENCE.md).
|
|
98
105
|
|
|
99
106
|
All of this is also a library API, see [Using it as a library](#using-it-as-a-library):
|
|
100
107
|
|
|
@@ -21,10 +21,10 @@ from cloudg.cli_helpers import (
|
|
|
21
21
|
_build_scan_jobs,
|
|
22
22
|
_gather_ingest_reports,
|
|
23
23
|
_parse_ingest_reports,
|
|
24
|
-
_parse_region_flag,
|
|
25
24
|
_render_ingest_reports,
|
|
26
25
|
_run_scan_jobs,
|
|
27
26
|
)
|
|
27
|
+
from cloudg.cli_inventory import deps, map_inventory
|
|
28
28
|
from cloudg.ui import console
|
|
29
29
|
|
|
30
30
|
# Global config reference (set by CLI group)
|
|
@@ -169,157 +169,6 @@ def collect(
|
|
|
169
169
|
ui.artifact("Inventory", inventory_path)
|
|
170
170
|
|
|
171
171
|
|
|
172
|
-
# ─────────────────────────────────────────────────────────────────────
|
|
173
|
-
# MAP command (scanner-independent inventory mapping)
|
|
174
|
-
# ─────────────────────────────────────────────────────────────────────
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
@cli.command(name="map")
|
|
178
|
-
@click.option(
|
|
179
|
-
"-p",
|
|
180
|
-
"--provider",
|
|
181
|
-
type=click.Choice(["aws", "azure", "gcp", "all"], case_sensitive=False),
|
|
182
|
-
multiple=True,
|
|
183
|
-
default=("aws",),
|
|
184
|
-
show_default=True,
|
|
185
|
-
help="Provider(s) to map. Use multiple times or 'all'.",
|
|
186
|
-
)
|
|
187
|
-
@click.option("--profile", default=None, help="AWS profile name")
|
|
188
|
-
@click.option(
|
|
189
|
-
"--regions",
|
|
190
|
-
"scan_regions",
|
|
191
|
-
default=None,
|
|
192
|
-
help="Regions: 'all' for auto-discovery, or comma-separated list",
|
|
193
|
-
)
|
|
194
|
-
@click.option("--subscription-id", default=None, help="Azure subscription ID")
|
|
195
|
-
@click.option("--project-id", default=None, help="GCP project ID")
|
|
196
|
-
@click.option(
|
|
197
|
-
"--findings",
|
|
198
|
-
"findings_paths",
|
|
199
|
-
multiple=True,
|
|
200
|
-
help="Existing cloudg findings JSON (raw-findings.json or a cloudg report) "
|
|
201
|
-
"to merge into asset/compliance maps. Repeatable.",
|
|
202
|
-
)
|
|
203
|
-
@click.option(
|
|
204
|
-
"--sweep/--no-sweep",
|
|
205
|
-
default=True,
|
|
206
|
-
show_default=True,
|
|
207
|
-
help="Catch-all sweep (AWS Resource Groups Tagging API) for resources "
|
|
208
|
-
"without a dedicated collector",
|
|
209
|
-
)
|
|
210
|
-
@click.option("-o", "--output", default="./reports", help="Output directory")
|
|
211
|
-
def map_inventory(
|
|
212
|
-
provider: tuple[str, ...],
|
|
213
|
-
profile: str | None,
|
|
214
|
-
scan_regions: str | None,
|
|
215
|
-
subscription_id: str | None,
|
|
216
|
-
project_id: str | None,
|
|
217
|
-
findings_paths: tuple[str, ...],
|
|
218
|
-
sweep: bool,
|
|
219
|
-
output: str,
|
|
220
|
-
) -> None:
|
|
221
|
-
"""Map the complete infrastructure inventory — no scanners involved.
|
|
222
|
-
|
|
223
|
-
Deep-collects everything deployed (or default) across the configured
|
|
224
|
-
providers, including the network fabric (route tables, gateways, ENIs,
|
|
225
|
-
volumes, peering) and a catch-all sweep so services without a dedicated
|
|
226
|
-
collector still appear. Every asset is then linked into an
|
|
227
|
-
interconnected map: attachment, containment, routing, and
|
|
228
|
-
cross-service references.
|
|
229
|
-
|
|
230
|
-
Optionally merge previously generated scanner findings to produce an
|
|
231
|
-
asset map and a compliance map:
|
|
232
|
-
|
|
233
|
-
cloudg map -p aws --regions all --findings ./reports/raw-findings.json
|
|
234
|
-
"""
|
|
235
|
-
ui.section("Inventory Mapping")
|
|
236
|
-
|
|
237
|
-
from cloudg.config import CloudGConfig
|
|
238
|
-
from cloudg.inventory import InventoryMapper
|
|
239
|
-
|
|
240
|
-
cfg: CloudGConfig = _config or CloudGConfig()
|
|
241
|
-
|
|
242
|
-
providers_list = list(provider)
|
|
243
|
-
if "all" in providers_list:
|
|
244
|
-
providers_list = ["aws", "azure", "gcp"]
|
|
245
|
-
cfg.providers = providers_list
|
|
246
|
-
|
|
247
|
-
if scan_regions:
|
|
248
|
-
region_list = _parse_region_flag(scan_regions)
|
|
249
|
-
cfg.aws.regions = region_list
|
|
250
|
-
cfg.azure.regions = region_list
|
|
251
|
-
cfg.gcp.regions = region_list
|
|
252
|
-
if profile:
|
|
253
|
-
cfg.aws.profile = profile
|
|
254
|
-
if subscription_id:
|
|
255
|
-
cfg.azure.subscription_ids = [subscription_id]
|
|
256
|
-
if project_id:
|
|
257
|
-
cfg.gcp.project_ids = [project_id]
|
|
258
|
-
|
|
259
|
-
ui.config_panel(
|
|
260
|
-
"Map Configuration",
|
|
261
|
-
{
|
|
262
|
-
"Providers": ", ".join(cfg.providers),
|
|
263
|
-
"AWS regions": ", ".join(cfg.aws.regions),
|
|
264
|
-
"Catch-all sweep": "enabled" if sweep else "disabled",
|
|
265
|
-
"Scanners": "none (inventory mapping is scanner-independent)",
|
|
266
|
-
},
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
mapper = InventoryMapper(cfg, tagging_sweep=sweep)
|
|
270
|
-
|
|
271
|
-
try:
|
|
272
|
-
with console.status("[accent]Mapping infrastructure inventory…[/]", spinner="dots"):
|
|
273
|
-
result = mapper.map_inventory_sync()
|
|
274
|
-
except Exception as exc:
|
|
275
|
-
ui.error_panel("Inventory mapping failed", exc)
|
|
276
|
-
sys.exit(1)
|
|
277
|
-
|
|
278
|
-
output_dir = Path(output)
|
|
279
|
-
paths = result.export(output_dir)
|
|
280
|
-
|
|
281
|
-
summary = result.summary
|
|
282
|
-
ui.stats_table(
|
|
283
|
-
"Inventory Summary",
|
|
284
|
-
{
|
|
285
|
-
"Assets": summary["total_assets"],
|
|
286
|
-
"Interconnections": summary["total_edges"],
|
|
287
|
-
"Services": len(summary["assets_by_service"]),
|
|
288
|
-
"Internet-exposed": summary["internet_exposed"],
|
|
289
|
-
"Unlinked assets": summary["unlinked_assets"],
|
|
290
|
-
},
|
|
291
|
-
)
|
|
292
|
-
for svc, count in list(summary["assets_by_service"].items())[:15]:
|
|
293
|
-
ui.detail(f"{svc}: {count} assets")
|
|
294
|
-
|
|
295
|
-
ui.artifact("Inventory map", paths["map"])
|
|
296
|
-
ui.artifact("GraphML", paths["graphml"])
|
|
297
|
-
ui.artifact("Graph JSON", paths["graph"])
|
|
298
|
-
|
|
299
|
-
# Optional merge with existing scanner findings
|
|
300
|
-
if findings_paths:
|
|
301
|
-
from cloudg.schema.models import Finding
|
|
302
|
-
|
|
303
|
-
findings: list[Any] = []
|
|
304
|
-
for fpath in findings_paths:
|
|
305
|
-
try:
|
|
306
|
-
with open(fpath) as f:
|
|
307
|
-
data = json.load(f)
|
|
308
|
-
raw = data if isinstance(data, list) else data.get("findings", [])
|
|
309
|
-
findings.extend(Finding.model_validate(item) for item in raw)
|
|
310
|
-
except (OSError, ValueError) as exc:
|
|
311
|
-
ui.warn(f"Skipping findings file {fpath}: {exc}")
|
|
312
|
-
|
|
313
|
-
if findings:
|
|
314
|
-
merged_paths = mapper.export_merged(result, findings, output_dir)
|
|
315
|
-
ui.success(f"Merged [metric]{len(findings)}[/] findings into the inventory")
|
|
316
|
-
ui.artifact("Asset map", merged_paths["asset_map"])
|
|
317
|
-
ui.artifact("Compliance map", merged_paths["compliance_map"])
|
|
318
|
-
|
|
319
|
-
console.print()
|
|
320
|
-
ui.success(f"Inventory map saved to [path]{output_dir}[/]")
|
|
321
|
-
|
|
322
|
-
|
|
323
172
|
# ─────────────────────────────────────────────────────────────────────
|
|
324
173
|
# SCAN command
|
|
325
174
|
# ─────────────────────────────────────────────────────────────────────
|
|
@@ -565,9 +414,12 @@ def ingest(
|
|
|
565
414
|
|
|
566
415
|
# ─────────────────────────────────────────────────────────────────────
|
|
567
416
|
# RUN command (full pipeline) — defined in cloudg.cli_commands
|
|
417
|
+
# MAP / DEPS commands (inventory mapping) — defined in cloudg.cli_inventory
|
|
568
418
|
# ─────────────────────────────────────────────────────────────────────
|
|
569
419
|
|
|
570
420
|
cli.add_command(run)
|
|
421
|
+
cli.add_command(map_inventory)
|
|
422
|
+
cli.add_command(deps)
|
|
571
423
|
|
|
572
424
|
|
|
573
425
|
if __name__ == "__main__":
|