cartography 0.104.0rc2__py3-none-any.whl → 0.123.0__py3-none-any.whl
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.
- cartography/_version.py +16 -3
- cartography/cli.py +466 -5
- cartography/client/aws/__init__.py +19 -0
- cartography/client/aws/ecr.py +51 -0
- cartography/client/core/tx.py +357 -8
- cartography/config.py +153 -0
- cartography/data/azure_permission_relationships.yaml +20 -0
- cartography/data/gcp_permission_relationships.yaml +21 -0
- cartography/data/indexes.cypher +0 -186
- cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +2 -2
- cartography/data/jobs/analysis/keycloak_inheritance.json +30 -0
- cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
- cartography/data/jobs/cleanup/github_repos_cleanup.json +2 -0
- cartography/driftdetect/cli.py +3 -2
- cartography/graph/cleanupbuilder.py +198 -41
- cartography/graph/job.py +54 -6
- cartography/graph/querybuilder.py +528 -27
- cartography/graph/statement.py +5 -1
- cartography/intel/airbyte/__init__.py +105 -0
- cartography/intel/airbyte/connections.py +120 -0
- cartography/intel/airbyte/destinations.py +81 -0
- cartography/intel/airbyte/organizations.py +59 -0
- cartography/intel/airbyte/sources.py +78 -0
- cartography/intel/airbyte/tags.py +64 -0
- cartography/intel/airbyte/users.py +106 -0
- cartography/intel/airbyte/util.py +122 -0
- cartography/intel/airbyte/workspaces.py +63 -0
- cartography/intel/aws/__init__.py +24 -9
- cartography/intel/aws/acm.py +124 -0
- cartography/intel/aws/apigateway.py +253 -22
- cartography/intel/aws/apigatewayv2.py +116 -0
- cartography/intel/aws/cloudtrail.py +17 -39
- cartography/intel/aws/cloudtrail_management_events.py +962 -0
- cartography/intel/aws/cloudwatch.py +150 -4
- cartography/intel/aws/codebuild.py +132 -0
- cartography/intel/aws/cognito.py +201 -0
- cartography/intel/aws/config.py +7 -3
- cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
- cartography/intel/aws/ec2/instances.py +25 -1
- cartography/intel/aws/ec2/internet_gateways.py +4 -2
- cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
- cartography/intel/aws/ec2/network_interfaces.py +5 -1
- cartography/intel/aws/ec2/reserved_instances.py +3 -1
- cartography/intel/aws/ec2/security_groups.py +140 -122
- cartography/intel/aws/ec2/snapshots.py +47 -84
- cartography/intel/aws/ec2/subnets.py +37 -63
- cartography/intel/aws/ec2/tgw.py +11 -5
- cartography/intel/aws/ec2/volumes.py +1 -1
- cartography/intel/aws/ec2/vpc.py +140 -124
- cartography/intel/aws/ec2/vpc_peerings.py +262 -125
- cartography/intel/aws/ecr.py +269 -98
- cartography/intel/aws/ecr_image_layers.py +923 -0
- cartography/intel/aws/ecs.py +251 -380
- cartography/intel/aws/efs.py +179 -11
- cartography/intel/aws/elasticache.py +102 -79
- cartography/intel/aws/elasticsearch.py +13 -4
- cartography/intel/aws/eventbridge.py +164 -0
- cartography/intel/aws/glue.py +181 -0
- cartography/intel/aws/guardduty.py +443 -0
- cartography/intel/aws/iam.py +750 -493
- cartography/intel/aws/identitycenter.py +605 -83
- cartography/intel/aws/inspector.py +221 -105
- cartography/intel/aws/kms.py +173 -201
- cartography/intel/aws/lambda_function.py +272 -189
- cartography/intel/aws/organizations.py +10 -9
- cartography/intel/aws/permission_relationships.py +10 -20
- cartography/intel/aws/rds.py +337 -446
- cartography/intel/aws/redshift.py +9 -4
- cartography/intel/aws/resourcegroupstaggingapi.py +78 -19
- cartography/intel/aws/resources.py +18 -0
- cartography/intel/aws/route53.py +386 -332
- cartography/intel/aws/s3.py +322 -14
- cartography/intel/aws/secretsmanager.py +81 -49
- cartography/intel/aws/securityhub.py +3 -1
- cartography/intel/aws/sns.py +62 -2
- cartography/intel/aws/sqs.py +36 -90
- cartography/intel/aws/ssm.py +3 -5
- cartography/intel/azure/__init__.py +202 -48
- cartography/intel/azure/aks.py +175 -0
- cartography/intel/azure/app_service.py +105 -0
- cartography/intel/azure/compute.py +59 -112
- cartography/intel/azure/container_instances.py +95 -0
- cartography/intel/azure/cosmosdb.py +222 -361
- cartography/intel/azure/data_factory.py +85 -0
- cartography/intel/azure/data_factory_dataset.py +128 -0
- cartography/intel/azure/data_factory_linked_service.py +119 -0
- cartography/intel/azure/data_factory_pipeline.py +142 -0
- cartography/intel/azure/data_lake.py +124 -0
- cartography/intel/azure/event_grid.py +94 -0
- cartography/intel/azure/functions.py +124 -0
- cartography/intel/azure/load_balancers.py +263 -0
- cartography/intel/azure/logic_apps.py +101 -0
- cartography/intel/azure/monitor.py +105 -0
- cartography/intel/azure/network.py +467 -0
- cartography/intel/azure/permission_relationships.py +466 -0
- cartography/intel/azure/rbac.py +309 -0
- cartography/intel/azure/resource_groups.py +82 -0
- cartography/intel/azure/security_center.py +106 -0
- cartography/intel/azure/sql.py +145 -292
- cartography/intel/azure/storage.py +185 -262
- cartography/intel/azure/subscription.py +21 -43
- cartography/intel/azure/tenant.py +39 -30
- cartography/intel/azure/util/common.py +13 -0
- cartography/intel/azure/util/credentials.py +49 -174
- cartography/intel/azure/util/tag.py +41 -0
- cartography/intel/create_indexes.py +2 -1
- cartography/intel/crowdstrike/spotlight.py +5 -2
- cartography/intel/dns.py +5 -2
- cartography/intel/entra/__init__.py +100 -1
- cartography/intel/entra/app_role_assignments.py +284 -0
- cartography/intel/entra/applications.py +182 -0
- cartography/intel/entra/federation/__init__.py +0 -0
- cartography/intel/entra/federation/aws_identity_center.py +77 -0
- cartography/intel/entra/groups.py +198 -0
- cartography/intel/entra/ou.py +48 -24
- cartography/intel/entra/service_principals.py +217 -0
- cartography/intel/entra/users.py +105 -57
- cartography/intel/gcp/__init__.py +334 -396
- cartography/intel/gcp/bigtable_app_profile.py +101 -0
- cartography/intel/gcp/bigtable_backup.py +91 -0
- cartography/intel/gcp/bigtable_cluster.py +93 -0
- cartography/intel/gcp/bigtable_instance.py +86 -0
- cartography/intel/gcp/bigtable_table.py +87 -0
- cartography/intel/gcp/cai.py +292 -0
- cartography/intel/gcp/clients.py +112 -0
- cartography/intel/gcp/compute.py +128 -119
- cartography/intel/gcp/crm/__init__.py +0 -0
- cartography/intel/gcp/crm/folders.py +114 -0
- cartography/intel/gcp/crm/orgs.py +70 -0
- cartography/intel/gcp/crm/projects.py +120 -0
- cartography/intel/gcp/dns.py +83 -169
- cartography/intel/gcp/gke.py +72 -113
- cartography/intel/gcp/iam.py +111 -91
- cartography/intel/gcp/permission_relationships.py +394 -0
- cartography/intel/gcp/policy_bindings.py +225 -0
- cartography/intel/gcp/storage.py +75 -159
- cartography/intel/github/__init__.py +62 -25
- cartography/intel/github/commits.py +423 -0
- cartography/intel/github/repos.py +463 -85
- cartography/intel/github/teams.py +3 -3
- cartography/intel/github/users.py +5 -0
- cartography/intel/github/util.py +12 -0
- cartography/intel/googleworkspace/__init__.py +193 -0
- cartography/intel/googleworkspace/devices.py +254 -0
- cartography/intel/googleworkspace/groups.py +568 -0
- cartography/intel/googleworkspace/oauth_apps.py +259 -0
- cartography/intel/googleworkspace/tenant.py +85 -0
- cartography/intel/googleworkspace/users.py +138 -0
- cartography/intel/gsuite/__init__.py +17 -9
- cartography/intel/gsuite/groups.py +291 -0
- cartography/intel/gsuite/users.py +142 -0
- cartography/intel/jamf/computers.py +7 -1
- cartography/intel/keycloak/__init__.py +153 -0
- cartography/intel/keycloak/authenticationexecutions.py +322 -0
- cartography/intel/keycloak/authenticationflows.py +77 -0
- cartography/intel/keycloak/clients.py +187 -0
- cartography/intel/keycloak/groups.py +126 -0
- cartography/intel/keycloak/identityproviders.py +94 -0
- cartography/intel/keycloak/organizations.py +163 -0
- cartography/intel/keycloak/realms.py +61 -0
- cartography/intel/keycloak/roles.py +202 -0
- cartography/intel/keycloak/scopes.py +73 -0
- cartography/intel/keycloak/users.py +70 -0
- cartography/intel/keycloak/util.py +47 -0
- cartography/intel/kubernetes/__init__.py +60 -14
- cartography/intel/kubernetes/clusters.py +86 -0
- cartography/intel/kubernetes/eks.py +402 -0
- cartography/intel/kubernetes/namespaces.py +59 -57
- cartography/intel/kubernetes/pods.py +168 -75
- cartography/intel/kubernetes/rbac.py +597 -0
- cartography/intel/kubernetes/secrets.py +95 -45
- cartography/intel/kubernetes/services.py +131 -67
- cartography/intel/kubernetes/util.py +142 -14
- cartography/intel/oci/iam.py +23 -9
- cartography/intel/oci/organizations.py +3 -1
- cartography/intel/oci/utils.py +28 -5
- cartography/intel/okta/applications.py +15 -5
- cartography/intel/okta/awssaml.py +14 -10
- cartography/intel/okta/factors.py +3 -1
- cartography/intel/okta/groups.py +5 -2
- cartography/intel/okta/organization.py +3 -1
- cartography/intel/okta/origins.py +3 -1
- cartography/intel/okta/roles.py +5 -2
- cartography/intel/okta/users.py +10 -2
- cartography/intel/ontology/__init__.py +44 -0
- cartography/intel/ontology/devices.py +54 -0
- cartography/intel/ontology/users.py +54 -0
- cartography/intel/ontology/utils.py +176 -0
- cartography/intel/pagerduty/escalation_policies.py +13 -6
- cartography/intel/pagerduty/schedules.py +9 -4
- cartography/intel/pagerduty/services.py +7 -3
- cartography/intel/pagerduty/teams.py +5 -2
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/scaleway/__init__.py +127 -0
- cartography/intel/scaleway/iam/__init__.py +0 -0
- cartography/intel/scaleway/iam/apikeys.py +71 -0
- cartography/intel/scaleway/iam/applications.py +71 -0
- cartography/intel/scaleway/iam/groups.py +71 -0
- cartography/intel/scaleway/iam/users.py +71 -0
- cartography/intel/scaleway/instances/__init__.py +0 -0
- cartography/intel/scaleway/instances/flexibleips.py +86 -0
- cartography/intel/scaleway/instances/instances.py +92 -0
- cartography/intel/scaleway/projects.py +79 -0
- cartography/intel/scaleway/storage/__init__.py +0 -0
- cartography/intel/scaleway/storage/snapshots.py +86 -0
- cartography/intel/scaleway/storage/volumes.py +84 -0
- cartography/intel/scaleway/utils.py +37 -0
- cartography/intel/sentinelone/__init__.py +75 -0
- cartography/intel/sentinelone/account.py +140 -0
- cartography/intel/sentinelone/agent.py +139 -0
- cartography/intel/sentinelone/api.py +124 -0
- cartography/intel/sentinelone/application.py +248 -0
- cartography/intel/sentinelone/cve.py +119 -0
- cartography/intel/sentinelone/utils.py +28 -0
- cartography/intel/slack/__init__.py +78 -0
- cartography/intel/slack/channels.py +80 -0
- cartography/intel/slack/groups.py +90 -0
- cartography/intel/slack/teams.py +65 -0
- cartography/intel/slack/users.py +57 -0
- cartography/intel/slack/utils.py +29 -0
- cartography/intel/spacelift/__init__.py +161 -0
- cartography/intel/spacelift/account.py +73 -0
- cartography/intel/spacelift/ec2_ownership.py +280 -0
- cartography/intel/spacelift/runs.py +463 -0
- cartography/intel/spacelift/spaces.py +112 -0
- cartography/intel/spacelift/stacks.py +119 -0
- cartography/intel/spacelift/util.py +122 -0
- cartography/intel/spacelift/workerpools.py +131 -0
- cartography/intel/spacelift/workers.py +128 -0
- cartography/intel/trivy/__init__.py +272 -0
- cartography/intel/trivy/scanner.py +386 -0
- cartography/models/airbyte/__init__.py +0 -0
- cartography/models/airbyte/connection.py +138 -0
- cartography/models/airbyte/destination.py +75 -0
- cartography/models/airbyte/organization.py +19 -0
- cartography/models/airbyte/source.py +75 -0
- cartography/models/airbyte/stream.py +74 -0
- cartography/models/airbyte/tag.py +69 -0
- cartography/models/airbyte/user.py +115 -0
- cartography/models/airbyte/workspace.py +46 -0
- cartography/models/anthropic/apikey.py +4 -0
- cartography/models/anthropic/user.py +4 -0
- cartography/models/aws/acm/__init__.py +0 -0
- cartography/models/aws/acm/certificate.py +75 -0
- cartography/models/aws/apigateway/__init__.py +0 -0
- cartography/models/aws/apigateway/apigatewaydeployment.py +74 -0
- cartography/models/aws/apigateway/apigatewayintegration.py +79 -0
- cartography/models/aws/apigateway/apigatewaymethod.py +74 -0
- cartography/models/aws/apigatewayv2/__init__.py +0 -0
- cartography/models/aws/apigatewayv2/apigatewayv2.py +53 -0
- cartography/models/aws/cloudtrail/management_events.py +153 -0
- cartography/models/aws/cloudtrail/trail.py +45 -0
- cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
- cartography/models/aws/cloudwatch/metric_alarm.py +53 -0
- cartography/models/aws/codebuild/__init__.py +0 -0
- cartography/models/aws/codebuild/project.py +49 -0
- cartography/models/aws/cognito/__init__.py +0 -0
- cartography/models/aws/cognito/identity_pool.py +70 -0
- cartography/models/aws/cognito/user_pool.py +47 -0
- cartography/models/aws/dynamodb/tables.py +2 -0
- cartography/models/aws/ec2/instances.py +25 -1
- cartography/models/aws/ec2/networkinterfaces.py +4 -0
- cartography/models/aws/ec2/security_group_rules.py +109 -0
- cartography/models/aws/ec2/security_groups.py +90 -0
- cartography/models/aws/ec2/snapshots.py +58 -0
- cartography/models/aws/ec2/subnet_instance.py +2 -0
- cartography/models/aws/ec2/subnet_networkinterface.py +2 -0
- cartography/models/aws/ec2/subnets.py +65 -0
- cartography/models/aws/ec2/volumes.py +20 -0
- cartography/models/aws/ec2/vpc.py +46 -0
- cartography/models/aws/ec2/vpc_cidr.py +102 -0
- cartography/models/aws/ec2/vpc_peering.py +157 -0
- cartography/models/aws/ecr/__init__.py +0 -0
- cartography/models/aws/ecr/image.py +146 -0
- cartography/models/aws/ecr/image_layer.py +107 -0
- cartography/models/aws/ecr/repository.py +72 -0
- cartography/models/aws/ecr/repository_image.py +95 -0
- cartography/models/aws/ecs/__init__.py +0 -0
- cartography/models/aws/ecs/clusters.py +64 -0
- cartography/models/aws/ecs/container_definitions.py +93 -0
- cartography/models/aws/ecs/container_instances.py +84 -0
- cartography/models/aws/ecs/containers.py +101 -0
- cartography/models/aws/ecs/services.py +134 -0
- cartography/models/aws/ecs/task_definitions.py +135 -0
- cartography/models/aws/ecs/tasks.py +134 -0
- cartography/models/aws/efs/access_point.py +77 -0
- cartography/models/aws/efs/file_system.py +60 -0
- cartography/models/aws/efs/mount_target.py +29 -2
- cartography/models/aws/elasticache/__init__.py +0 -0
- cartography/models/aws/elasticache/cluster.py +65 -0
- cartography/models/aws/elasticache/topic.py +67 -0
- cartography/models/aws/eventbridge/__init__.py +0 -0
- cartography/models/aws/eventbridge/rule.py +77 -0
- cartography/models/aws/eventbridge/target.py +71 -0
- cartography/models/aws/glue/__init__.py +0 -0
- cartography/models/aws/glue/connection.py +51 -0
- cartography/models/aws/glue/job.py +69 -0
- cartography/models/aws/guardduty/__init__.py +1 -0
- cartography/models/aws/guardduty/detectors.py +50 -0
- cartography/models/aws/guardduty/findings.py +121 -0
- cartography/models/aws/iam/access_key.py +103 -0
- cartography/models/aws/iam/account_role.py +24 -0
- cartography/models/aws/iam/federated_principal.py +60 -0
- cartography/models/aws/iam/group.py +60 -0
- cartography/models/aws/iam/group_membership.py +27 -0
- cartography/models/aws/iam/inline_policy.py +78 -0
- cartography/models/aws/iam/managed_policy.py +51 -0
- cartography/models/aws/iam/policy_statement.py +57 -0
- cartography/models/aws/iam/role.py +83 -0
- cartography/models/aws/iam/root_principal.py +52 -0
- cartography/models/aws/iam/service_principal.py +30 -0
- cartography/models/aws/iam/sts_assumerole_allow.py +38 -0
- cartography/models/aws/iam/user.py +59 -0
- cartography/models/aws/identitycenter/awsidentitycenter.py +1 -0
- cartography/models/aws/identitycenter/awspermissionset.py +70 -0
- cartography/models/aws/identitycenter/awssogroup.py +70 -0
- cartography/models/aws/identitycenter/awsssouser.py +49 -9
- cartography/models/aws/inspector/findings.py +37 -0
- cartography/models/aws/inspector/packages.py +1 -31
- cartography/models/aws/kms/__init__.py +0 -0
- cartography/models/aws/kms/aliases.py +86 -0
- cartography/models/aws/kms/grants.py +65 -0
- cartography/models/aws/kms/keys.py +88 -0
- cartography/models/aws/lambda_function/__init__.py +0 -0
- cartography/models/aws/lambda_function/alias.py +74 -0
- cartography/models/aws/lambda_function/event_source_mapping.py +88 -0
- cartography/models/aws/lambda_function/lambda_function.py +91 -0
- cartography/models/aws/lambda_function/layer.py +72 -0
- cartography/models/aws/rds/__init__.py +0 -0
- cartography/models/aws/rds/cluster.py +91 -0
- cartography/models/aws/rds/event_subscription.py +146 -0
- cartography/models/aws/rds/instance.py +156 -0
- cartography/models/aws/rds/snapshot.py +108 -0
- cartography/models/aws/rds/subnet_group.py +101 -0
- cartography/models/aws/route53/__init__.py +0 -0
- cartography/models/aws/route53/dnsrecord.py +235 -0
- cartography/models/aws/route53/nameserver.py +63 -0
- cartography/models/aws/route53/subzone.py +40 -0
- cartography/models/aws/route53/zone.py +47 -0
- cartography/models/aws/s3/notification.py +24 -0
- cartography/models/aws/secretsmanager/secret.py +106 -0
- cartography/models/aws/secretsmanager/secret_version.py +0 -2
- cartography/models/aws/sns/topic_subscription.py +74 -0
- cartography/models/aws/sqs/__init__.py +0 -0
- cartography/models/aws/sqs/queue.py +89 -0
- cartography/models/azure/__init__.py +0 -0
- cartography/models/azure/aks_cluster.py +54 -0
- cartography/models/azure/aks_nodepool.py +54 -0
- cartography/models/azure/app_service.py +59 -0
- cartography/models/azure/container_instance.py +57 -0
- cartography/models/azure/cosmosdb/__init__.py +0 -0
- cartography/models/azure/cosmosdb/account.py +77 -0
- cartography/models/azure/cosmosdb/accountfailoverpolicy.py +77 -0
- cartography/models/azure/cosmosdb/cassandrakeyspace.py +82 -0
- cartography/models/azure/cosmosdb/cassandratable.py +81 -0
- cartography/models/azure/cosmosdb/corspolicy.py +74 -0
- cartography/models/azure/cosmosdb/dblocation.py +120 -0
- cartography/models/azure/cosmosdb/mongodbcollection.py +82 -0
- cartography/models/azure/cosmosdb/mongodbdatabase.py +78 -0
- cartography/models/azure/cosmosdb/privateendpointconnection.py +81 -0
- cartography/models/azure/cosmosdb/sqlcontainer.py +88 -0
- cartography/models/azure/cosmosdb/sqldatabase.py +78 -0
- cartography/models/azure/cosmosdb/tableresource.py +76 -0
- cartography/models/azure/cosmosdb/virtualnetworkrule.py +78 -0
- cartography/models/azure/data_factory/__init__.py +0 -0
- cartography/models/azure/data_factory/data_factory.py +51 -0
- cartography/models/azure/data_factory/data_factory_dataset.py +94 -0
- cartography/models/azure/data_factory/data_factory_linked_service.py +78 -0
- cartography/models/azure/data_factory/data_factory_pipeline.py +93 -0
- cartography/models/azure/data_lake_filesystem.py +51 -0
- cartography/models/azure/event_grid_topic.py +57 -0
- cartography/models/azure/function_app.py +59 -0
- cartography/models/azure/load_balancer/__init__.py +0 -0
- cartography/models/azure/load_balancer/load_balancer.py +49 -0
- cartography/models/azure/load_balancer/load_balancer_backend_pool.py +73 -0
- cartography/models/azure/load_balancer/load_balancer_frontend_ip.py +75 -0
- cartography/models/azure/load_balancer/load_balancer_inbound_nat_rule.py +78 -0
- cartography/models/azure/load_balancer/load_balancer_rule.py +108 -0
- cartography/models/azure/logic_apps.py +56 -0
- cartography/models/azure/monitor.py +54 -0
- cartography/models/azure/network_interface.py +112 -0
- cartography/models/azure/network_security_group.py +50 -0
- cartography/models/azure/permission_relationships.py +60 -0
- cartography/models/azure/principal.py +41 -0
- cartography/models/azure/public_ip_address.py +50 -0
- cartography/models/azure/rbac.py +268 -0
- cartography/models/azure/resource_groups.py +52 -0
- cartography/models/azure/security_center.py +50 -0
- cartography/models/azure/sql/__init__.py +0 -0
- cartography/models/azure/sql/databasethreatdetectionpolicy.py +85 -0
- cartography/models/azure/sql/elasticpool.py +77 -0
- cartography/models/azure/sql/failovergroup.py +73 -0
- cartography/models/azure/sql/recoverabledatabase.py +75 -0
- cartography/models/azure/sql/replicationlink.py +81 -0
- cartography/models/azure/sql/restorabledroppeddatabase.py +82 -0
- cartography/models/azure/sql/restorepoint.py +74 -0
- cartography/models/azure/sql/serveradadministrator.py +74 -0
- cartography/models/azure/sql/serverdnsalias.py +71 -0
- cartography/models/azure/sql/sqldatabase.py +85 -0
- cartography/models/azure/sql/sqlserver.py +50 -0
- cartography/models/azure/sql/transparentdataencryption.py +76 -0
- cartography/models/azure/storage/__init__.py +0 -0
- cartography/models/azure/storage/account.py +59 -0
- cartography/models/azure/storage/blobcontainer.py +85 -0
- cartography/models/azure/storage/blobservice.py +71 -0
- cartography/models/azure/storage/fileservice.py +71 -0
- cartography/models/azure/storage/fileshare.py +82 -0
- cartography/models/azure/storage/queue.py +71 -0
- cartography/models/azure/storage/queueservice.py +73 -0
- cartography/models/azure/storage/table.py +72 -0
- cartography/models/azure/storage/tableservice.py +73 -0
- cartography/models/azure/subnet.py +101 -0
- cartography/models/azure/subscription.py +47 -0
- cartography/models/azure/tags/__init__.py +0 -0
- cartography/models/azure/tags/storage_tag.py +40 -0
- cartography/models/azure/tags/tag.py +37 -0
- cartography/models/azure/tenant.py +17 -0
- cartography/models/azure/virtual_network.py +49 -0
- cartography/models/azure/vm/__init__.py +0 -0
- cartography/models/azure/vm/datadisk.py +80 -0
- cartography/models/azure/vm/disk.py +55 -0
- cartography/models/azure/vm/snapshot.py +56 -0
- cartography/models/azure/vm/virtualmachine.py +59 -0
- cartography/models/bigfix/bigfix_computer.py +1 -1
- cartography/models/cloudflare/member.py +4 -0
- cartography/models/core/common.py +1 -0
- cartography/models/core/nodes.py +15 -2
- cartography/models/core/relationships.py +44 -0
- cartography/models/crowdstrike/hosts.py +1 -1
- cartography/models/digitalocean/droplet.py +2 -0
- cartography/models/duo/endpoint.py +1 -1
- cartography/models/duo/phone.py +2 -2
- cartography/models/duo/user.py +4 -0
- cartography/models/entra/app_role_assignment.py +115 -0
- cartography/models/entra/application.py +49 -0
- cartography/models/entra/entra_user_to_aws_sso.py +41 -0
- cartography/models/entra/group.py +117 -0
- cartography/models/entra/service_principal.py +104 -0
- cartography/models/entra/user.py +42 -51
- cartography/models/gcp/__init__.py +0 -0
- cartography/models/gcp/bigtable/__init__.py +0 -0
- cartography/models/gcp/bigtable/app_profile.py +94 -0
- cartography/models/gcp/bigtable/backup.py +91 -0
- cartography/models/gcp/bigtable/cluster.py +73 -0
- cartography/models/gcp/bigtable/instance.py +52 -0
- cartography/models/gcp/bigtable/table.py +69 -0
- cartography/models/gcp/compute/__init__.py +0 -0
- cartography/models/gcp/compute/subnet.py +74 -0
- cartography/models/gcp/compute/vpc.py +50 -0
- cartography/models/gcp/crm/__init__.py +0 -0
- cartography/models/gcp/crm/folders.py +98 -0
- cartography/models/gcp/crm/organizations.py +21 -0
- cartography/models/gcp/crm/projects.py +100 -0
- cartography/models/gcp/dns.py +109 -0
- cartography/models/gcp/gke.py +69 -0
- cartography/models/gcp/iam.py +3 -0
- cartography/models/gcp/permission_relationships.py +61 -0
- cartography/models/gcp/policy_bindings.py +93 -0
- cartography/models/gcp/storage/__init__.py +0 -0
- cartography/models/gcp/storage/bucket.py +119 -0
- cartography/models/github/commits.py +63 -0
- cartography/models/github/dependencies.py +73 -0
- cartography/models/github/manifests.py +49 -0
- cartography/models/github/users.py +10 -0
- cartography/models/googleworkspace/__init__.py +0 -0
- cartography/models/googleworkspace/device.py +132 -0
- cartography/models/googleworkspace/group.py +382 -0
- cartography/models/googleworkspace/oauth_app.py +124 -0
- cartography/models/googleworkspace/tenant.py +30 -0
- cartography/models/googleworkspace/user.py +113 -0
- cartography/models/gsuite/__init__.py +0 -0
- cartography/models/gsuite/group.py +218 -0
- cartography/models/gsuite/tenant.py +29 -0
- cartography/models/gsuite/user.py +107 -0
- cartography/models/kandji/device.py +1 -2
- cartography/models/keycloak/__init__.py +0 -0
- cartography/models/keycloak/authenticationexecution.py +160 -0
- cartography/models/keycloak/authenticationflow.py +54 -0
- cartography/models/keycloak/client.py +179 -0
- cartography/models/keycloak/group.py +101 -0
- cartography/models/keycloak/identityprovider.py +89 -0
- cartography/models/keycloak/organization.py +116 -0
- cartography/models/keycloak/organizationdomain.py +73 -0
- cartography/models/keycloak/realm.py +173 -0
- cartography/models/keycloak/role.py +126 -0
- cartography/models/keycloak/scope.py +73 -0
- cartography/models/keycloak/user.py +55 -0
- cartography/models/kubernetes/__init__.py +0 -0
- cartography/models/kubernetes/clusterrolebindings.py +138 -0
- cartography/models/kubernetes/clusterroles.py +52 -0
- cartography/models/kubernetes/clusters.py +26 -0
- cartography/models/kubernetes/containers.py +133 -0
- cartography/models/kubernetes/groups.py +107 -0
- cartography/models/kubernetes/namespaces.py +51 -0
- cartography/models/kubernetes/oidc.py +51 -0
- cartography/models/kubernetes/pods.py +80 -0
- cartography/models/kubernetes/rolebindings.py +159 -0
- cartography/models/kubernetes/roles.py +76 -0
- cartography/models/kubernetes/secrets.py +79 -0
- cartography/models/kubernetes/serviceaccounts.py +77 -0
- cartography/models/kubernetes/services.py +108 -0
- cartography/models/kubernetes/users.py +105 -0
- cartography/models/lastpass/user.py +4 -0
- cartography/models/ontology/__init__.py +0 -0
- cartography/models/ontology/device.py +137 -0
- cartography/models/ontology/mapping/__init__.py +76 -0
- cartography/models/ontology/mapping/data/__init__.py +0 -0
- cartography/models/ontology/mapping/data/apikeys.py +93 -0
- cartography/models/ontology/mapping/data/computeinstance.py +95 -0
- cartography/models/ontology/mapping/data/containers.py +88 -0
- cartography/models/ontology/mapping/data/databases.py +182 -0
- cartography/models/ontology/mapping/data/devices.py +194 -0
- cartography/models/ontology/mapping/data/thirdpartyapps.py +140 -0
- cartography/models/ontology/mapping/data/useraccounts.py +416 -0
- cartography/models/ontology/mapping/data/users.py +63 -0
- cartography/models/ontology/mapping/specs.py +85 -0
- cartography/models/ontology/user.py +51 -0
- cartography/models/openai/adminapikey.py +4 -0
- cartography/models/openai/apikey.py +4 -0
- cartography/models/openai/user.py +4 -0
- cartography/models/scaleway/__init__.py +0 -0
- cartography/models/scaleway/iam/__init__.py +0 -0
- cartography/models/scaleway/iam/apikey.py +100 -0
- cartography/models/scaleway/iam/application.py +52 -0
- cartography/models/scaleway/iam/group.py +95 -0
- cartography/models/scaleway/iam/user.py +64 -0
- cartography/models/scaleway/instance/__init__.py +0 -0
- cartography/models/scaleway/instance/flexibleip.py +52 -0
- cartography/models/scaleway/instance/instance.py +120 -0
- cartography/models/scaleway/organization.py +19 -0
- cartography/models/scaleway/project.py +48 -0
- cartography/models/scaleway/storage/__init__.py +0 -0
- cartography/models/scaleway/storage/snapshot.py +78 -0
- cartography/models/scaleway/storage/volume.py +51 -0
- cartography/models/sentinelone/__init__.py +1 -0
- cartography/models/sentinelone/account.py +40 -0
- cartography/models/sentinelone/agent.py +50 -0
- cartography/models/sentinelone/application.py +44 -0
- cartography/models/sentinelone/application_version.py +96 -0
- cartography/models/sentinelone/cve.py +73 -0
- cartography/models/slack/__init__.py +0 -0
- cartography/models/slack/channels.py +92 -0
- cartography/models/slack/group.py +129 -0
- cartography/models/slack/team.py +22 -0
- cartography/models/slack/user.py +62 -0
- cartography/models/snipeit/asset.py +2 -0
- cartography/models/snipeit/user.py +4 -0
- cartography/models/spacelift/__init__.py +0 -0
- cartography/models/spacelift/cloudtrailevent.py +120 -0
- cartography/models/spacelift/run.py +162 -0
- cartography/models/spacelift/space.py +131 -0
- cartography/models/spacelift/spaceliftaccount.py +31 -0
- cartography/models/spacelift/spaceliftgitcommit.py +157 -0
- cartography/models/spacelift/stack.py +96 -0
- cartography/models/spacelift/user.py +63 -0
- cartography/models/spacelift/worker.py +97 -0
- cartography/models/spacelift/workerpool.py +90 -0
- cartography/models/tailscale/device.py +2 -1
- cartography/models/tailscale/user.py +6 -1
- cartography/models/trivy/__init__.py +0 -0
- cartography/models/trivy/findings.py +66 -0
- cartography/models/trivy/fix.py +66 -0
- cartography/models/trivy/package.py +71 -0
- cartography/rules/README.md +1 -0
- cartography/rules/__init__.py +0 -0
- cartography/rules/cli.py +261 -0
- cartography/rules/data/__init__.py +0 -0
- cartography/rules/data/rules/__init__.py +46 -0
- cartography/rules/data/rules/cloud_security_product_deactivated.py +49 -0
- cartography/rules/data/rules/compute_instance_exposed.py +51 -0
- cartography/rules/data/rules/database_instance_exposed.py +53 -0
- cartography/rules/data/rules/delegation_boundary_modifiable.py +90 -0
- cartography/rules/data/rules/identity_administration_privileges.py +100 -0
- cartography/rules/data/rules/inactive_user_active_accounts.py +48 -0
- cartography/rules/data/rules/malicious_npm_dependencies_shai_hulud.py +2222 -0
- cartography/rules/data/rules/mfa_missing.py +46 -0
- cartography/rules/data/rules/object_storage_public.py +100 -0
- cartography/rules/data/rules/policy_administration_privileges.py +104 -0
- cartography/rules/data/rules/unmanaged_accounts.py +43 -0
- cartography/rules/data/rules/workload_identity_admin_capabilities.py +193 -0
- cartography/rules/formatters.py +108 -0
- cartography/rules/runners.py +216 -0
- cartography/rules/spec/__init__.py +0 -0
- cartography/rules/spec/model.py +267 -0
- cartography/rules/spec/result.py +38 -0
- cartography/sync.py +25 -5
- cartography/util.py +101 -31
- {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/METADATA +61 -22
- cartography-0.123.0.dist-info/RECORD +856 -0
- {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/entry_points.txt +1 -0
- cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -65
- cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json +0 -17
- cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json +0 -24
- cartography/data/jobs/cleanup/aws_import_groups_cleanup.json +0 -13
- cartography/data/jobs/cleanup/aws_import_identity_center_cleanup.json +0 -16
- cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -50
- cartography/data/jobs/cleanup/aws_import_principals_cleanup.json +0 -30
- cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -47
- cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_roles_cleanup.json +0 -13
- cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
- cartography/data/jobs/cleanup/aws_import_snapshots_cleanup.json +0 -30
- cartography/data/jobs/cleanup/aws_import_users_cleanup.json +0 -8
- cartography/data/jobs/cleanup/aws_import_vpc_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -45
- cartography/data/jobs/cleanup/aws_kms_details.json +0 -10
- cartography/data/jobs/cleanup/azure_cosmosdb_cassandra_keyspace_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_cors_details.json +0 -15
- cartography/data/jobs/cleanup/azure_cosmosdb_mongodb_database_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_sql_database_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_table_resources_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_database_account_cleanup.json +0 -85
- cartography/data/jobs/cleanup/azure_import_disks_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_import_snapshots_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_import_virtual_machines_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_sql_server_cleanup.json +0 -125
- cartography/data/jobs/cleanup/azure_storage_account_cleanup.json +0 -95
- cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json +0 -14
- cartography/data/jobs/cleanup/azure_tenant_cleanup.json +0 -9
- cartography/data/jobs/cleanup/gcp_compute_vpc_subnet_cleanup.json +0 -35
- cartography/data/jobs/cleanup/gcp_crm_folder_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gcp_crm_organization_cleanup.json +0 -17
- cartography/data/jobs/cleanup/gcp_crm_project_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gcp_dns_cleanup.json +0 -29
- cartography/data/jobs/cleanup/gcp_gke_cluster_cleanup.json +0 -17
- cartography/data/jobs/cleanup/gcp_storage_bucket_cleanup.json +0 -29
- cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -11
- cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -70
- cartography/intel/gcp/crm.py +0 -355
- cartography/intel/gsuite/api.py +0 -342
- cartography-0.104.0rc2.dist-info/RECORD +0 -455
- /cartography/data/jobs/{analysis → scoped_analysis}/aws_s3acl_analysis.json +0 -0
- /cartography/models/aws/{apigateway.py → apigateway/apigateway.py} +0 -0
- /cartography/models/aws/{apigatewaycertificate.py → apigateway/apigatewaycertificate.py} +0 -0
- /cartography/models/aws/{apigatewayresource.py → apigateway/apigatewayresource.py} +0 -0
- /cartography/models/aws/{apigatewaystage.py → apigateway/apigatewaystage.py} +0 -0
- {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/WHEEL +0 -0
- {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/top_level.txt +0 -0
cartography/intel/gcp/compute.py
CHANGED
|
@@ -11,9 +11,14 @@ from typing import Optional
|
|
|
11
11
|
from typing import Set
|
|
12
12
|
|
|
13
13
|
import neo4j
|
|
14
|
-
from googleapiclient.discovery import HttpError
|
|
15
14
|
from googleapiclient.discovery import Resource
|
|
15
|
+
from googleapiclient.errors import HttpError
|
|
16
16
|
|
|
17
|
+
from cartography.client.core.tx import execute_write_with_retry
|
|
18
|
+
from cartography.client.core.tx import load
|
|
19
|
+
from cartography.client.core.tx import run_write_query
|
|
20
|
+
from cartography.graph.job import GraphJob
|
|
21
|
+
from cartography.models.gcp.compute.vpc import GCPVpcSchema
|
|
17
22
|
from cartography.util import run_cleanup_job
|
|
18
23
|
from cartography.util import timeit
|
|
19
24
|
|
|
@@ -21,6 +26,10 @@ logger = logging.getLogger(__name__)
|
|
|
21
26
|
InstanceUriPrefix = namedtuple("InstanceUriPrefix", "zone_name project_id")
|
|
22
27
|
|
|
23
28
|
|
|
29
|
+
# Maximum number of retries for Google API requests
|
|
30
|
+
GOOGLE_API_NUM_RETRIES = 5
|
|
31
|
+
|
|
32
|
+
|
|
24
33
|
def _get_error_reason(http_error: HttpError) -> str:
|
|
25
34
|
"""
|
|
26
35
|
Helper function to get an error reason out of the googleapiclient's HttpError object
|
|
@@ -63,7 +72,7 @@ def get_zones_in_project(
|
|
|
63
72
|
"""
|
|
64
73
|
try:
|
|
65
74
|
req = compute.zones().list(project=project_id, maxResults=max_results)
|
|
66
|
-
res = req.execute()
|
|
75
|
+
res = req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
67
76
|
return res["items"]
|
|
68
77
|
except HttpError as e:
|
|
69
78
|
reason = _get_error_reason(e)
|
|
@@ -117,22 +126,53 @@ def get_gcp_instance_responses(
|
|
|
117
126
|
response_objects: List[Resource] = []
|
|
118
127
|
for zone in zones:
|
|
119
128
|
req = compute.instances().list(project=project_id, zone=zone["name"])
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
try:
|
|
130
|
+
res = req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
131
|
+
response_objects.append(res)
|
|
132
|
+
except HttpError as e:
|
|
133
|
+
reason = _get_error_reason(e)
|
|
134
|
+
if reason in {"backendError", "rateLimitExceeded", "internalError"}:
|
|
135
|
+
logger.warning(
|
|
136
|
+
"Transient error listing instances for project %s zone %s: %s; skipping this zone.",
|
|
137
|
+
project_id,
|
|
138
|
+
zone.get("name"),
|
|
139
|
+
e,
|
|
140
|
+
)
|
|
141
|
+
continue
|
|
142
|
+
raise
|
|
122
143
|
return response_objects
|
|
123
144
|
|
|
124
145
|
|
|
125
146
|
@timeit
|
|
126
|
-
def get_gcp_subnets(projectid: str, region: str, compute: Resource) ->
|
|
147
|
+
def get_gcp_subnets(projectid: str, region: str, compute: Resource) -> Dict:
|
|
127
148
|
"""
|
|
128
|
-
Return list of all subnets in the given projectid and region
|
|
129
|
-
|
|
149
|
+
Return list of all subnets in the given projectid and region. If the API
|
|
150
|
+
call times out mid-pagination, return any subnets gathered so far rather than
|
|
151
|
+
bubbling the error up to the caller.
|
|
152
|
+
:param projectid: The project ID
|
|
130
153
|
:param region: The region to pull subnets from
|
|
131
154
|
:param compute: The compute resource object created by googleapiclient.discovery.build()
|
|
132
155
|
:return: Response object containing data on all GCP subnets for a given project
|
|
133
156
|
"""
|
|
134
157
|
req = compute.subnetworks().list(project=projectid, region=region)
|
|
135
|
-
|
|
158
|
+
items: List[Dict] = []
|
|
159
|
+
response_id = f"projects/{projectid}/regions/{region}/subnetworks"
|
|
160
|
+
while req is not None:
|
|
161
|
+
try:
|
|
162
|
+
res = req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
163
|
+
except TimeoutError:
|
|
164
|
+
logger.warning(
|
|
165
|
+
"GCP: subnetworks.list for project %s region %s timed out; continuing with partial data.",
|
|
166
|
+
projectid,
|
|
167
|
+
region,
|
|
168
|
+
)
|
|
169
|
+
break
|
|
170
|
+
items.extend(res.get("items", []))
|
|
171
|
+
response_id = res.get("id", response_id)
|
|
172
|
+
req = compute.subnetworks().list_next(
|
|
173
|
+
previous_request=req, previous_response=res
|
|
174
|
+
)
|
|
175
|
+
return {"id": response_id, "items": items}
|
|
136
176
|
|
|
137
177
|
|
|
138
178
|
@timeit
|
|
@@ -144,7 +184,7 @@ def get_gcp_vpcs(projectid: str, compute: Resource) -> Resource:
|
|
|
144
184
|
:return: VPC response object
|
|
145
185
|
"""
|
|
146
186
|
req = compute.networks().list(project=projectid)
|
|
147
|
-
return req.execute()
|
|
187
|
+
return req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
148
188
|
|
|
149
189
|
|
|
150
190
|
@timeit
|
|
@@ -161,7 +201,7 @@ def get_gcp_regional_forwarding_rules(
|
|
|
161
201
|
:return: Response object containing data on all GCP forwarding rules for a given project
|
|
162
202
|
"""
|
|
163
203
|
req = compute.forwardingRules().list(project=project_id, region=region)
|
|
164
|
-
return req.execute()
|
|
204
|
+
return req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
165
205
|
|
|
166
206
|
|
|
167
207
|
@timeit
|
|
@@ -173,7 +213,7 @@ def get_gcp_global_forwarding_rules(project_id: str, compute: Resource) -> Resou
|
|
|
173
213
|
:return: Response object containing data on all GCP forwarding rules for a given project
|
|
174
214
|
"""
|
|
175
215
|
req = compute.globalForwardingRules().list(project=project_id)
|
|
176
|
-
return req.execute()
|
|
216
|
+
return req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
177
217
|
|
|
178
218
|
|
|
179
219
|
@timeit
|
|
@@ -185,7 +225,7 @@ def get_gcp_firewall_ingress_rules(project_id: str, compute: Resource) -> Resour
|
|
|
185
225
|
:return: Firewall response object
|
|
186
226
|
"""
|
|
187
227
|
req = compute.firewalls().list(project=project_id, filter='(direction="INGRESS")')
|
|
188
|
-
return req.execute()
|
|
228
|
+
return req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
189
229
|
|
|
190
230
|
|
|
191
231
|
@timeit
|
|
@@ -581,7 +621,8 @@ def load_gcp_instances(
|
|
|
581
621
|
SET r.lastupdated = $gcp_update_tag
|
|
582
622
|
"""
|
|
583
623
|
for instance in data:
|
|
584
|
-
|
|
624
|
+
run_write_query(
|
|
625
|
+
neo4j_session,
|
|
585
626
|
query,
|
|
586
627
|
ProjectId=instance["project_id"],
|
|
587
628
|
PartialUri=instance["partial_uri"],
|
|
@@ -600,48 +641,17 @@ def load_gcp_instances(
|
|
|
600
641
|
@timeit
|
|
601
642
|
def load_gcp_vpcs(
|
|
602
643
|
neo4j_session: neo4j.Session,
|
|
603
|
-
vpcs:
|
|
644
|
+
vpcs: list[dict[str, Any]],
|
|
604
645
|
gcp_update_tag: int,
|
|
646
|
+
project_id: str,
|
|
605
647
|
) -> None:
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
query = """
|
|
614
|
-
MERGE(p:GCPProject{id:$ProjectId})
|
|
615
|
-
ON CREATE SET p.firstseen = timestamp()
|
|
616
|
-
SET p.lastupdated = $gcp_update_tag
|
|
617
|
-
|
|
618
|
-
MERGE(vpc:GCPVpc{id:$PartialUri})
|
|
619
|
-
ON CREATE SET vpc.firstseen = timestamp(),
|
|
620
|
-
vpc.partial_uri = $PartialUri
|
|
621
|
-
SET vpc.self_link = $SelfLink,
|
|
622
|
-
vpc.name = $VpcName,
|
|
623
|
-
vpc.project_id = $ProjectId,
|
|
624
|
-
vpc.auto_create_subnetworks = $AutoCreateSubnetworks,
|
|
625
|
-
vpc.routing_config_routing_mode = $RoutingMode,
|
|
626
|
-
vpc.description = $Description,
|
|
627
|
-
vpc.lastupdated = $gcp_update_tag
|
|
628
|
-
|
|
629
|
-
MERGE (p)-[r:RESOURCE]->(vpc)
|
|
630
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
631
|
-
SET r.lastupdated = $gcp_update_tag
|
|
632
|
-
"""
|
|
633
|
-
for vpc in vpcs:
|
|
634
|
-
neo4j_session.run(
|
|
635
|
-
query,
|
|
636
|
-
ProjectId=vpc["project_id"],
|
|
637
|
-
PartialUri=vpc["partial_uri"],
|
|
638
|
-
SelfLink=vpc["self_link"],
|
|
639
|
-
VpcName=vpc["name"],
|
|
640
|
-
AutoCreateSubnetworks=vpc["auto_create_subnetworks"],
|
|
641
|
-
RoutingMode=vpc["routing_config_routing_mode"],
|
|
642
|
-
Description=vpc["description"],
|
|
643
|
-
gcp_update_tag=gcp_update_tag,
|
|
644
|
-
)
|
|
648
|
+
load(
|
|
649
|
+
neo4j_session,
|
|
650
|
+
GCPVpcSchema(),
|
|
651
|
+
vpcs,
|
|
652
|
+
PROJECT_ID=project_id,
|
|
653
|
+
LASTUPDATED=gcp_update_tag,
|
|
654
|
+
)
|
|
645
655
|
|
|
646
656
|
|
|
647
657
|
@timeit
|
|
@@ -649,51 +659,25 @@ def load_gcp_subnets(
|
|
|
649
659
|
neo4j_session: neo4j.Session,
|
|
650
660
|
subnets: List[Dict],
|
|
651
661
|
gcp_update_tag: int,
|
|
662
|
+
project_id: str,
|
|
652
663
|
) -> None:
|
|
653
664
|
"""
|
|
654
|
-
Ingest GCP subnet data to Neo4j
|
|
665
|
+
Ingest GCP subnet data to Neo4j using the data model
|
|
655
666
|
:param neo4j_session: The Neo4j session
|
|
656
667
|
:param subnets: List of the subnets
|
|
657
668
|
:param gcp_update_tag: The timestamp to set these Neo4j nodes with
|
|
669
|
+
:param project_id: The project ID
|
|
658
670
|
:return: Nothing
|
|
659
671
|
"""
|
|
660
|
-
|
|
661
|
-
MERGE(vpc:GCPVpc{id:$VpcPartialUri})
|
|
662
|
-
ON CREATE SET vpc.firstseen = timestamp(),
|
|
663
|
-
vpc.partial_uri = $VpcPartialUri
|
|
672
|
+
from cartography.models.gcp.compute.subnet import GCPSubnetSchema
|
|
664
673
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
subnet.gateway_address = $GatewayAddress,
|
|
673
|
-
subnet.ip_cidr_range = $IpCidrRange,
|
|
674
|
-
subnet.private_ip_google_access = $PrivateIpGoogleAccess,
|
|
675
|
-
subnet.vpc_partial_uri = $VpcPartialUri,
|
|
676
|
-
subnet.lastupdated = $gcp_update_tag
|
|
677
|
-
|
|
678
|
-
MERGE (vpc)-[r:RESOURCE]->(subnet)
|
|
679
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
680
|
-
SET r.lastupdated = $gcp_update_tag
|
|
681
|
-
"""
|
|
682
|
-
for s in subnets:
|
|
683
|
-
neo4j_session.run(
|
|
684
|
-
query,
|
|
685
|
-
VpcPartialUri=s["vpc_partial_uri"],
|
|
686
|
-
VpcSelfLink=s["vpc_self_link"],
|
|
687
|
-
PartialUri=s["partial_uri"],
|
|
688
|
-
SubnetSelfLink=s["self_link"],
|
|
689
|
-
ProjectId=s["project_id"],
|
|
690
|
-
SubnetName=s["name"],
|
|
691
|
-
Region=s["region"],
|
|
692
|
-
GatewayAddress=s["gateway_address"],
|
|
693
|
-
IpCidrRange=s["ip_cidr_range"],
|
|
694
|
-
PrivateIpGoogleAccess=s["private_ip_google_access"],
|
|
695
|
-
gcp_update_tag=gcp_update_tag,
|
|
696
|
-
)
|
|
674
|
+
load(
|
|
675
|
+
neo4j_session,
|
|
676
|
+
GCPSubnetSchema(),
|
|
677
|
+
subnets,
|
|
678
|
+
lastupdated=gcp_update_tag,
|
|
679
|
+
PROJECT_ID=project_id,
|
|
680
|
+
)
|
|
697
681
|
|
|
698
682
|
|
|
699
683
|
@timeit
|
|
@@ -733,7 +717,8 @@ def load_gcp_forwarding_rules(
|
|
|
733
717
|
network = fwd.get("network", None)
|
|
734
718
|
subnetwork = fwd.get("subnetwork", None)
|
|
735
719
|
|
|
736
|
-
|
|
720
|
+
run_write_query(
|
|
721
|
+
neo4j_session,
|
|
737
722
|
query,
|
|
738
723
|
PartialUri=fwd["partial_uri"],
|
|
739
724
|
IPAddress=fwd["ip_address"],
|
|
@@ -779,7 +764,8 @@ def _attach_fwd_rule_to_subnet(
|
|
|
779
764
|
SET p.lastupdated = $gcp_update_tag
|
|
780
765
|
"""
|
|
781
766
|
|
|
782
|
-
|
|
767
|
+
run_write_query(
|
|
768
|
+
neo4j_session,
|
|
783
769
|
query,
|
|
784
770
|
PartialUri=fwd["partial_uri"],
|
|
785
771
|
SubNetworkPartialUri=fwd.get("subnetwork_partial_uri", None),
|
|
@@ -806,7 +792,8 @@ def _attach_fwd_rule_to_vpc(
|
|
|
806
792
|
SET r.lastupdated = $gcp_update_tag
|
|
807
793
|
"""
|
|
808
794
|
|
|
809
|
-
|
|
795
|
+
run_write_query(
|
|
796
|
+
neo4j_session,
|
|
810
797
|
query,
|
|
811
798
|
PartialUri=fwd["partial_uri"],
|
|
812
799
|
NetworkPartialUri=fwd.get("network_partial_uri", None),
|
|
@@ -850,7 +837,8 @@ def _attach_instance_tags(
|
|
|
850
837
|
for tag in instance.get("tags", {}).get("items", []):
|
|
851
838
|
for nic in instance.get("networkInterfaces", []):
|
|
852
839
|
tag_id = _create_gcp_network_tag_id(nic["vpc_partial_uri"], tag)
|
|
853
|
-
|
|
840
|
+
run_write_query(
|
|
841
|
+
neo4j_session,
|
|
854
842
|
query,
|
|
855
843
|
InstanceId=instance["partial_uri"],
|
|
856
844
|
TagId=tag_id,
|
|
@@ -899,7 +887,8 @@ def _attach_gcp_nics(
|
|
|
899
887
|
for nic in instance.get("networkInterfaces", []):
|
|
900
888
|
# Make an ID for GCPNetworkInterface nodes because GCP doesn't define one but we need to uniquely identify them
|
|
901
889
|
nic_id = f"{instance['partial_uri']}/networkinterfaces/{nic['name']}"
|
|
902
|
-
|
|
890
|
+
run_write_query(
|
|
891
|
+
neo4j_session,
|
|
903
892
|
query,
|
|
904
893
|
InstanceId=instance["partial_uri"],
|
|
905
894
|
NicId=nic_id,
|
|
@@ -945,7 +934,8 @@ def _attach_gcp_nic_access_configs(
|
|
|
945
934
|
for ac in nic.get("accessConfigs", []):
|
|
946
935
|
# Make an ID for GCPNicAccessConfig nodes because GCP doesn't define one but we need to uniquely identify them
|
|
947
936
|
access_config_id = f"{nic_id}/accessconfigs/{ac['type']}"
|
|
948
|
-
|
|
937
|
+
run_write_query(
|
|
938
|
+
neo4j_session,
|
|
949
939
|
query,
|
|
950
940
|
NicId=nic_id,
|
|
951
941
|
AccessConfigId=access_config_id,
|
|
@@ -974,12 +964,13 @@ def _attach_gcp_vpc(
|
|
|
974
964
|
"""
|
|
975
965
|
query = """
|
|
976
966
|
MATCH (i:GCPInstance{id:$InstanceId})-[:NETWORK_INTERFACE]->(nic:GCPNetworkInterface)
|
|
977
|
-
-[p:PART_OF_SUBNET]->(sn:GCPSubnet)<-[r:
|
|
967
|
+
-[p:PART_OF_SUBNET]->(sn:GCPSubnet)<-[r:HAS]-(vpc:GCPVpc)
|
|
978
968
|
MERGE (i)-[m:MEMBER_OF_GCP_VPC]->(vpc)
|
|
979
969
|
ON CREATE SET m.firstseen = timestamp()
|
|
980
970
|
SET m.lastupdated = $gcp_update_tag
|
|
981
971
|
"""
|
|
982
|
-
|
|
972
|
+
run_write_query(
|
|
973
|
+
neo4j_session,
|
|
983
974
|
query,
|
|
984
975
|
InstanceId=instance_id,
|
|
985
976
|
gcp_update_tag=gcp_update_tag,
|
|
@@ -993,10 +984,23 @@ def load_gcp_ingress_firewalls(
|
|
|
993
984
|
gcp_update_tag: int,
|
|
994
985
|
) -> None:
|
|
995
986
|
"""
|
|
996
|
-
Load the firewall list to Neo4j
|
|
987
|
+
Load the firewall list to Neo4j with retry logic for transient errors.
|
|
997
988
|
:param fw_list: The transformed list of firewalls
|
|
998
989
|
:return: Nothing
|
|
999
990
|
"""
|
|
991
|
+
execute_write_with_retry(
|
|
992
|
+
neo4j_session,
|
|
993
|
+
_load_gcp_ingress_firewalls_tx,
|
|
994
|
+
fw_list,
|
|
995
|
+
gcp_update_tag,
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
def _load_gcp_ingress_firewalls_tx(
|
|
1000
|
+
tx: neo4j.Transaction,
|
|
1001
|
+
fw_list: List[Resource],
|
|
1002
|
+
gcp_update_tag: int,
|
|
1003
|
+
) -> None:
|
|
1000
1004
|
query = """
|
|
1001
1005
|
MERGE (fw:GCPFirewall{id:$FwPartialUri})
|
|
1002
1006
|
ON CREATE SET fw.firstseen = timestamp(),
|
|
@@ -1019,7 +1023,7 @@ def load_gcp_ingress_firewalls(
|
|
|
1019
1023
|
SET r.lastupdated = $gcp_update_tag
|
|
1020
1024
|
"""
|
|
1021
1025
|
for fw in fw_list:
|
|
1022
|
-
|
|
1026
|
+
tx.run(
|
|
1023
1027
|
query,
|
|
1024
1028
|
FwPartialUri=fw["id"],
|
|
1025
1029
|
Direction=fw["direction"],
|
|
@@ -1030,20 +1034,20 @@ def load_gcp_ingress_firewalls(
|
|
|
1030
1034
|
VpcPartialUri=fw["vpc_partial_uri"],
|
|
1031
1035
|
HasTargetServiceAccounts=fw["has_target_service_accounts"],
|
|
1032
1036
|
gcp_update_tag=gcp_update_tag,
|
|
1033
|
-
)
|
|
1034
|
-
_attach_firewall_rules(
|
|
1035
|
-
_attach_target_tags(
|
|
1037
|
+
).consume()
|
|
1038
|
+
_attach_firewall_rules(tx, fw, gcp_update_tag)
|
|
1039
|
+
_attach_target_tags(tx, fw, gcp_update_tag)
|
|
1036
1040
|
|
|
1037
1041
|
|
|
1038
1042
|
@timeit
|
|
1039
1043
|
def _attach_firewall_rules(
|
|
1040
|
-
|
|
1044
|
+
tx: neo4j.Transaction,
|
|
1041
1045
|
fw: Resource,
|
|
1042
1046
|
gcp_update_tag: int,
|
|
1043
1047
|
) -> None:
|
|
1044
1048
|
"""
|
|
1045
1049
|
Attach the allow_rules to the Firewall object
|
|
1046
|
-
:param
|
|
1050
|
+
:param tx: The Neo4j transaction
|
|
1047
1051
|
:param fw: The Firewall object
|
|
1048
1052
|
:param gcp_update_tag: The timestamp
|
|
1049
1053
|
:return: Nothing
|
|
@@ -1084,7 +1088,7 @@ def _attach_firewall_rules(
|
|
|
1084
1088
|
# If sourceRanges is not specified then the rule must specify sourceTags.
|
|
1085
1089
|
# Since an IP range cannot have a tag applied to it, it is ok if we don't ingest this rule.
|
|
1086
1090
|
for ip_range in fw.get("sourceRanges", []):
|
|
1087
|
-
|
|
1091
|
+
tx.run(
|
|
1088
1092
|
template.safe_substitute(fw_rule_relationship_label=label),
|
|
1089
1093
|
FwPartialUri=fw["id"],
|
|
1090
1094
|
RuleId=rule["ruleid"],
|
|
@@ -1093,18 +1097,18 @@ def _attach_firewall_rules(
|
|
|
1093
1097
|
ToPort=rule.get("toport"),
|
|
1094
1098
|
Range=ip_range,
|
|
1095
1099
|
gcp_update_tag=gcp_update_tag,
|
|
1096
|
-
)
|
|
1100
|
+
).consume()
|
|
1097
1101
|
|
|
1098
1102
|
|
|
1099
1103
|
@timeit
|
|
1100
1104
|
def _attach_target_tags(
|
|
1101
|
-
|
|
1105
|
+
tx: neo4j.Transaction,
|
|
1102
1106
|
fw: Resource,
|
|
1103
1107
|
gcp_update_tag: int,
|
|
1104
1108
|
) -> None:
|
|
1105
1109
|
"""
|
|
1106
1110
|
Attach target tags to the firewall object
|
|
1107
|
-
:param
|
|
1111
|
+
:param tx: The neo4j transaction
|
|
1108
1112
|
:param fw: The firewall object
|
|
1109
1113
|
:param gcp_update_tag: The timestamp
|
|
1110
1114
|
:return: Nothing
|
|
@@ -1124,13 +1128,13 @@ def _attach_target_tags(
|
|
|
1124
1128
|
"""
|
|
1125
1129
|
for tag in fw.get("targetTags", []):
|
|
1126
1130
|
tag_id = _create_gcp_network_tag_id(fw["vpc_partial_uri"], tag)
|
|
1127
|
-
|
|
1131
|
+
tx.run(
|
|
1128
1132
|
query,
|
|
1129
1133
|
FwPartialUri=fw["id"],
|
|
1130
1134
|
TagId=tag_id,
|
|
1131
1135
|
TagValue=tag,
|
|
1132
1136
|
gcp_update_tag=gcp_update_tag,
|
|
1133
|
-
)
|
|
1137
|
+
).consume()
|
|
1134
1138
|
|
|
1135
1139
|
|
|
1136
1140
|
@timeit
|
|
@@ -1159,6 +1163,12 @@ def cleanup_gcp_vpcs(neo4j_session: neo4j.Session, common_job_parameters: Dict)
|
|
|
1159
1163
|
:param common_job_parameters: dict of other job parameters to pass to Neo4j
|
|
1160
1164
|
:return: Nothing
|
|
1161
1165
|
"""
|
|
1166
|
+
GraphJob.from_node_schema(
|
|
1167
|
+
GCPVpcSchema(),
|
|
1168
|
+
common_job_parameters,
|
|
1169
|
+
).run(neo4j_session)
|
|
1170
|
+
|
|
1171
|
+
# TODO: remove this once we refactor GCP instances and add the instance to vpc rel as an object
|
|
1162
1172
|
run_cleanup_job(
|
|
1163
1173
|
"gcp_compute_vpc_cleanup.json",
|
|
1164
1174
|
neo4j_session,
|
|
@@ -1172,15 +1182,15 @@ def cleanup_gcp_subnets(
|
|
|
1172
1182
|
common_job_parameters: Dict,
|
|
1173
1183
|
) -> None:
|
|
1174
1184
|
"""
|
|
1175
|
-
Delete out-of-date GCP VPC subnet nodes and relationships
|
|
1185
|
+
Delete out-of-date GCP VPC subnet nodes and relationships using data model
|
|
1176
1186
|
:param neo4j_session: The Neo4j session
|
|
1177
1187
|
:param common_job_parameters: dict of other job parameters to pass to Neo4j
|
|
1178
1188
|
:return: Nothing
|
|
1179
1189
|
"""
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1190
|
+
from cartography.models.gcp.compute.subnet import GCPSubnetSchema
|
|
1191
|
+
|
|
1192
|
+
GraphJob.from_node_schema(GCPSubnetSchema(), common_job_parameters).run(
|
|
1193
|
+
neo4j_session
|
|
1184
1194
|
)
|
|
1185
1195
|
|
|
1186
1196
|
|
|
@@ -1267,8 +1277,7 @@ def sync_gcp_vpcs(
|
|
|
1267
1277
|
"""
|
|
1268
1278
|
vpc_res = get_gcp_vpcs(project_id, compute)
|
|
1269
1279
|
vpcs = transform_gcp_vpcs(vpc_res)
|
|
1270
|
-
load_gcp_vpcs(neo4j_session, vpcs, gcp_update_tag)
|
|
1271
|
-
# TODO scope the cleanup to the current project - https://github.com/cartography-cncf/cartography/issues/381
|
|
1280
|
+
load_gcp_vpcs(neo4j_session, vpcs, gcp_update_tag, project_id)
|
|
1272
1281
|
cleanup_gcp_vpcs(neo4j_session, common_job_parameters)
|
|
1273
1282
|
|
|
1274
1283
|
|
|
@@ -1284,7 +1293,7 @@ def sync_gcp_subnets(
|
|
|
1284
1293
|
for r in regions:
|
|
1285
1294
|
subnet_res = get_gcp_subnets(project_id, r, compute)
|
|
1286
1295
|
subnets = transform_gcp_subnets(subnet_res)
|
|
1287
|
-
load_gcp_subnets(neo4j_session, subnets, gcp_update_tag)
|
|
1296
|
+
load_gcp_subnets(neo4j_session, subnets, gcp_update_tag, project_id)
|
|
1288
1297
|
# TODO scope the cleanup to the current project - https://github.com/cartography-cncf/cartography/issues/381
|
|
1289
1298
|
cleanup_gcp_subnets(neo4j_session, common_job_parameters)
|
|
1290
1299
|
|
|
File without changes
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from typing import List
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import neo4j
|
|
7
|
+
from google.auth.credentials import Credentials as GoogleCredentials
|
|
8
|
+
from google.cloud import resourcemanager_v3
|
|
9
|
+
|
|
10
|
+
from cartography.client.core.tx import load
|
|
11
|
+
from cartography.models.gcp.crm.folders import GCPFolderSchema
|
|
12
|
+
from cartography.util import timeit
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@timeit
|
|
18
|
+
def get_gcp_folders(
|
|
19
|
+
org_resource_name: str,
|
|
20
|
+
credentials: Optional[GoogleCredentials] = None,
|
|
21
|
+
) -> List[Dict]:
|
|
22
|
+
"""
|
|
23
|
+
Return a list of all descendant GCP folders under the specified organization by traversing the folder tree.
|
|
24
|
+
|
|
25
|
+
:param org_resource_name: Full organization resource name (e.g., "organizations/123456789012")
|
|
26
|
+
:return: List of folder dicts with 'name' field containing full resource names (e.g., "folders/123456")
|
|
27
|
+
"""
|
|
28
|
+
results: List[Dict] = []
|
|
29
|
+
client = resourcemanager_v3.FoldersClient(credentials=credentials)
|
|
30
|
+
# BFS over folders starting at the org root
|
|
31
|
+
queue: List[str] = [org_resource_name]
|
|
32
|
+
seen: set[str] = set()
|
|
33
|
+
while queue:
|
|
34
|
+
parent = queue.pop(0)
|
|
35
|
+
if parent in seen:
|
|
36
|
+
continue
|
|
37
|
+
seen.add(parent)
|
|
38
|
+
|
|
39
|
+
for folder in client.list_folders(parent=parent):
|
|
40
|
+
results.append(
|
|
41
|
+
{
|
|
42
|
+
"name": folder.name,
|
|
43
|
+
"parent": parent,
|
|
44
|
+
"displayName": folder.display_name,
|
|
45
|
+
"lifecycleState": folder.state.name,
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
if folder.name:
|
|
49
|
+
queue.append(folder.name)
|
|
50
|
+
return results
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@timeit
|
|
54
|
+
def transform_gcp_folders(data: List[Dict]) -> List[Dict]:
|
|
55
|
+
"""
|
|
56
|
+
Transform GCP folder data to add parent_org or parent_folder fields based on parent type.
|
|
57
|
+
|
|
58
|
+
:param data: List of folder dicts
|
|
59
|
+
:return: List of transformed folder dicts with parent_org and parent_folder fields
|
|
60
|
+
"""
|
|
61
|
+
for folder in data:
|
|
62
|
+
folder["parent_org"] = None
|
|
63
|
+
folder["parent_folder"] = None
|
|
64
|
+
|
|
65
|
+
if folder["parent"].startswith("organizations"):
|
|
66
|
+
folder["parent_org"] = folder["parent"]
|
|
67
|
+
elif folder["parent"].startswith("folders"):
|
|
68
|
+
folder["parent_folder"] = folder["parent"]
|
|
69
|
+
else:
|
|
70
|
+
logger.warning(
|
|
71
|
+
f"Folder {folder['name']} has unexpected parent type: {folder['parent']}"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return data
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@timeit
|
|
78
|
+
def load_gcp_folders(
|
|
79
|
+
neo4j_session: neo4j.Session,
|
|
80
|
+
data: List[Dict],
|
|
81
|
+
gcp_update_tag: int,
|
|
82
|
+
org_resource_name: str,
|
|
83
|
+
) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Load GCP folders into the graph.
|
|
86
|
+
:param org_resource_name: Full organization resource name (e.g., "organizations/123456789012")
|
|
87
|
+
"""
|
|
88
|
+
transformed_data = transform_gcp_folders(data)
|
|
89
|
+
load(
|
|
90
|
+
neo4j_session,
|
|
91
|
+
GCPFolderSchema(),
|
|
92
|
+
transformed_data,
|
|
93
|
+
lastupdated=gcp_update_tag,
|
|
94
|
+
ORG_RESOURCE_NAME=org_resource_name,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@timeit
|
|
99
|
+
def sync_gcp_folders(
|
|
100
|
+
neo4j_session: neo4j.Session,
|
|
101
|
+
gcp_update_tag: int,
|
|
102
|
+
common_job_parameters: Dict,
|
|
103
|
+
org_resource_name: str,
|
|
104
|
+
credentials: Optional[GoogleCredentials] = None,
|
|
105
|
+
) -> List[Dict]:
|
|
106
|
+
"""
|
|
107
|
+
Get GCP folder data using the CRM v2 resource object and load the data to Neo4j.
|
|
108
|
+
:param org_resource_name: Full organization resource name (e.g., "organizations/123456789012")
|
|
109
|
+
:return: List of folders synced
|
|
110
|
+
"""
|
|
111
|
+
logger.debug("Syncing GCP folders")
|
|
112
|
+
folders = get_gcp_folders(org_resource_name, credentials=credentials)
|
|
113
|
+
load_gcp_folders(neo4j_session, folders, gcp_update_tag, org_resource_name)
|
|
114
|
+
return folders
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from typing import List
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import neo4j
|
|
7
|
+
from google.auth.credentials import Credentials as GoogleCredentials
|
|
8
|
+
from google.cloud import resourcemanager_v3
|
|
9
|
+
|
|
10
|
+
from cartography.client.core.tx import load
|
|
11
|
+
from cartography.models.gcp.crm.organizations import GCPOrganizationSchema
|
|
12
|
+
from cartography.util import timeit
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@timeit
|
|
18
|
+
def get_gcp_organizations(
|
|
19
|
+
credentials: Optional[GoogleCredentials] = None,
|
|
20
|
+
) -> List[Dict]:
|
|
21
|
+
"""
|
|
22
|
+
Return list of GCP organizations that the authenticated principal can access using the high-level client.
|
|
23
|
+
Returns empty list on error.
|
|
24
|
+
:return: List of org dicts with keys: name, displayName, lifecycleState.
|
|
25
|
+
"""
|
|
26
|
+
client = resourcemanager_v3.OrganizationsClient(credentials=credentials)
|
|
27
|
+
orgs = []
|
|
28
|
+
for org in client.search_organizations():
|
|
29
|
+
orgs.append(
|
|
30
|
+
{
|
|
31
|
+
"name": org.name,
|
|
32
|
+
"displayName": org.display_name,
|
|
33
|
+
"lifecycleState": org.state.name,
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
return orgs
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@timeit
|
|
40
|
+
def load_gcp_organizations(
|
|
41
|
+
neo4j_session: neo4j.Session,
|
|
42
|
+
data: List[Dict],
|
|
43
|
+
gcp_update_tag: int,
|
|
44
|
+
) -> None:
|
|
45
|
+
for org in data:
|
|
46
|
+
org["id"] = org["name"]
|
|
47
|
+
|
|
48
|
+
load(
|
|
49
|
+
neo4j_session,
|
|
50
|
+
GCPOrganizationSchema(),
|
|
51
|
+
data,
|
|
52
|
+
lastupdated=gcp_update_tag,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@timeit
|
|
57
|
+
def sync_gcp_organizations(
|
|
58
|
+
neo4j_session: neo4j.Session,
|
|
59
|
+
gcp_update_tag: int,
|
|
60
|
+
common_job_parameters: Dict,
|
|
61
|
+
credentials: Optional[GoogleCredentials] = None,
|
|
62
|
+
) -> List[Dict]:
|
|
63
|
+
"""
|
|
64
|
+
Get GCP organization data using the CRM v1 resource object and load the data to Neo4j.
|
|
65
|
+
Returns the list of organizations synced.
|
|
66
|
+
"""
|
|
67
|
+
logger.debug("Syncing GCP organizations")
|
|
68
|
+
data = get_gcp_organizations(credentials=credentials)
|
|
69
|
+
load_gcp_organizations(neo4j_session, data, gcp_update_tag)
|
|
70
|
+
return data
|