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
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
from googleapiclient.discovery import Resource
|
|
6
|
+
from googleapiclient.errors import HttpError
|
|
7
|
+
|
|
8
|
+
from cartography.client.core.tx import load
|
|
9
|
+
from cartography.client.core.tx import load_matchlinks
|
|
10
|
+
from cartography.graph.job import GraphJob
|
|
11
|
+
from cartography.models.googleworkspace.oauth_app import GoogleWorkspaceOAuthAppSchema
|
|
12
|
+
from cartography.models.googleworkspace.oauth_app import (
|
|
13
|
+
GoogleWorkspaceUserToOAuthAppRel,
|
|
14
|
+
)
|
|
15
|
+
from cartography.util import timeit
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
GOOGLE_API_NUM_RETRIES = 5
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@timeit
|
|
23
|
+
def get_oauth_tokens_for_user(admin: Resource, user_id: str) -> list[dict]:
|
|
24
|
+
"""
|
|
25
|
+
Get OAuth tokens for a specific user
|
|
26
|
+
https://developers.google.com/workspace/admin/directory/reference/rest/v1/tokens/list
|
|
27
|
+
|
|
28
|
+
:param admin: apiclient discovery resource object
|
|
29
|
+
:param user_id: User's ID
|
|
30
|
+
:return: list of OAuth tokens for the user
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
request = admin.tokens().list(userKey=user_id)
|
|
34
|
+
resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
35
|
+
tokens = resp.get("items", [])
|
|
36
|
+
|
|
37
|
+
# Add user_id to each token for relationship mapping
|
|
38
|
+
for token in tokens:
|
|
39
|
+
token["user_id"] = user_id
|
|
40
|
+
|
|
41
|
+
return tokens
|
|
42
|
+
except HttpError as e:
|
|
43
|
+
if (
|
|
44
|
+
e.resp.status == 403
|
|
45
|
+
and "Request had insufficient authentication scopes" in str(e)
|
|
46
|
+
):
|
|
47
|
+
logger.error(
|
|
48
|
+
"Missing required Google Workspace scopes. If using the gcloud CLI, "
|
|
49
|
+
"run: gcloud auth application-default login --scopes="
|
|
50
|
+
"https://www.googleapis.com/auth/admin.directory.customer.readonly,"
|
|
51
|
+
"https://www.googleapis.com/auth/admin.directory.user.readonly,"
|
|
52
|
+
"https://www.googleapis.com/auth/admin.directory.user.security,"
|
|
53
|
+
"https://www.googleapis.com/auth/cloud-identity.devices.readonly,"
|
|
54
|
+
"https://www.googleapis.com/auth/cloud-identity.groups.readonly,"
|
|
55
|
+
"https://www.googleapis.com/auth/cloud-platform"
|
|
56
|
+
)
|
|
57
|
+
elif e.resp.status == 404:
|
|
58
|
+
# User has no OAuth tokens, this is normal
|
|
59
|
+
return []
|
|
60
|
+
else:
|
|
61
|
+
logger.warning(f"Error fetching OAuth tokens for user: {e}")
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@timeit
|
|
66
|
+
def get_all_oauth_tokens(admin: Resource, user_ids: list[str]) -> list[dict]:
|
|
67
|
+
"""
|
|
68
|
+
Get OAuth tokens for all users in the organization
|
|
69
|
+
|
|
70
|
+
:param admin: apiclient discovery resource object
|
|
71
|
+
:param user_ids: List of user IDs
|
|
72
|
+
:return: list of all OAuth tokens across all users
|
|
73
|
+
"""
|
|
74
|
+
all_tokens = []
|
|
75
|
+
|
|
76
|
+
for user_id in user_ids:
|
|
77
|
+
tokens = get_oauth_tokens_for_user(admin, user_id)
|
|
78
|
+
all_tokens.extend(tokens)
|
|
79
|
+
|
|
80
|
+
logger.debug(f"Retrieved {len(all_tokens)} OAuth tokens for {len(user_ids)} users")
|
|
81
|
+
return all_tokens
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@timeit
|
|
85
|
+
def transform_oauth_apps_and_authorizations(
|
|
86
|
+
tokens: list[dict],
|
|
87
|
+
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
|
88
|
+
"""
|
|
89
|
+
Transform OAuth token objects to create app nodes and user authorization relationships
|
|
90
|
+
|
|
91
|
+
:param tokens: Raw API response token objects
|
|
92
|
+
:return: tuple of (apps, authorizations)
|
|
93
|
+
- apps: list of unique OAuth app dictionaries
|
|
94
|
+
- authorizations: list of user->app authorization relationships with scopes
|
|
95
|
+
"""
|
|
96
|
+
# Group tokens by client_id to create unique apps
|
|
97
|
+
apps_map: dict[str, dict[str, Any]] = {}
|
|
98
|
+
authorizations: list[dict[str, Any]] = []
|
|
99
|
+
|
|
100
|
+
for token in tokens:
|
|
101
|
+
client_id = token.get("clientId")
|
|
102
|
+
user_id = token.get("user_id")
|
|
103
|
+
scopes = token.get("scopes", [])
|
|
104
|
+
|
|
105
|
+
if not client_id or not user_id:
|
|
106
|
+
logger.warning("Skipping token due to missing client_id or user_id")
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
# Create or update app entry
|
|
110
|
+
if client_id not in apps_map:
|
|
111
|
+
apps_map[client_id] = {
|
|
112
|
+
"client_id": client_id,
|
|
113
|
+
"display_text": token.get("displayText"),
|
|
114
|
+
"anonymous": token.get("anonymous", False),
|
|
115
|
+
"native_app": token.get("nativeApp", False),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Create authorization relationship
|
|
119
|
+
authorizations.append(
|
|
120
|
+
{
|
|
121
|
+
"user_id": user_id,
|
|
122
|
+
"client_id": client_id,
|
|
123
|
+
"scopes": scopes,
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
apps = list(apps_map.values())
|
|
128
|
+
logger.info(
|
|
129
|
+
f"Transformed {len(apps)} unique OAuth apps with {len(authorizations)} authorizations"
|
|
130
|
+
)
|
|
131
|
+
return apps, authorizations
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@timeit
|
|
135
|
+
def load_googleworkspace_oauth_apps(
|
|
136
|
+
neo4j_session: neo4j.Session,
|
|
137
|
+
data: list[dict[str, Any]],
|
|
138
|
+
googleworkspace_update_tag: int,
|
|
139
|
+
customer_id: str,
|
|
140
|
+
) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Load Google Workspace OAuth apps
|
|
143
|
+
"""
|
|
144
|
+
logger.info(
|
|
145
|
+
"Ingesting %s Google Workspace OAuth apps for customer %s",
|
|
146
|
+
len(data),
|
|
147
|
+
customer_id,
|
|
148
|
+
)
|
|
149
|
+
load(
|
|
150
|
+
neo4j_session,
|
|
151
|
+
GoogleWorkspaceOAuthAppSchema(),
|
|
152
|
+
data,
|
|
153
|
+
lastupdated=googleworkspace_update_tag,
|
|
154
|
+
CUSTOMER_ID=customer_id,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@timeit
|
|
159
|
+
def load_user_to_app_authorizations(
|
|
160
|
+
neo4j_session: neo4j.Session,
|
|
161
|
+
authorizations: list[dict[str, Any]],
|
|
162
|
+
googleworkspace_update_tag: int,
|
|
163
|
+
customer_id: str,
|
|
164
|
+
) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Load user to OAuth app authorization relationships using MatchLinks
|
|
167
|
+
"""
|
|
168
|
+
logger.info(
|
|
169
|
+
"Creating %s user to OAuth app authorization relationships",
|
|
170
|
+
len(authorizations),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
load_matchlinks(
|
|
174
|
+
neo4j_session,
|
|
175
|
+
GoogleWorkspaceUserToOAuthAppRel(),
|
|
176
|
+
authorizations,
|
|
177
|
+
lastupdated=googleworkspace_update_tag,
|
|
178
|
+
_sub_resource_label="GoogleWorkspaceTenant",
|
|
179
|
+
_sub_resource_id=customer_id,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@timeit
|
|
184
|
+
def cleanup_googleworkspace_oauth_apps(
|
|
185
|
+
neo4j_session: neo4j.Session,
|
|
186
|
+
common_job_parameters: dict[str, Any],
|
|
187
|
+
) -> None:
|
|
188
|
+
"""
|
|
189
|
+
Clean up Google Workspace OAuth apps
|
|
190
|
+
"""
|
|
191
|
+
logger.debug("Running Google Workspace OAuth apps cleanup job")
|
|
192
|
+
GraphJob.from_node_schema(
|
|
193
|
+
GoogleWorkspaceOAuthAppSchema(), common_job_parameters
|
|
194
|
+
).run(neo4j_session)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@timeit
|
|
198
|
+
def cleanup_user_to_app_authorizations(
|
|
199
|
+
neo4j_session: neo4j.Session,
|
|
200
|
+
common_job_parameters: dict[str, Any],
|
|
201
|
+
) -> None:
|
|
202
|
+
"""
|
|
203
|
+
Clean up stale user to OAuth app authorization relationships using MatchLink cleanup
|
|
204
|
+
"""
|
|
205
|
+
logger.debug("Running user to OAuth app authorization relationships cleanup")
|
|
206
|
+
|
|
207
|
+
GraphJob.from_matchlink(
|
|
208
|
+
GoogleWorkspaceUserToOAuthAppRel(),
|
|
209
|
+
"GoogleWorkspaceTenant",
|
|
210
|
+
common_job_parameters["CUSTOMER_ID"],
|
|
211
|
+
common_job_parameters["UPDATE_TAG"],
|
|
212
|
+
).run(neo4j_session)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@timeit
|
|
216
|
+
def sync_googleworkspace_oauth_apps(
|
|
217
|
+
neo4j_session: neo4j.Session,
|
|
218
|
+
admin: Resource,
|
|
219
|
+
user_ids: list[str],
|
|
220
|
+
googleworkspace_update_tag: int,
|
|
221
|
+
common_job_parameters: dict[str, Any],
|
|
222
|
+
) -> None:
|
|
223
|
+
"""
|
|
224
|
+
GET Google Workspace OAuth app objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
|
|
225
|
+
|
|
226
|
+
:param neo4j_session: The Neo4j session
|
|
227
|
+
:param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
|
|
228
|
+
:param user_ids: List of user IDs to fetch tokens for
|
|
229
|
+
:param googleworkspace_update_tag: The timestamp value to set our new Neo4j nodes with
|
|
230
|
+
:param common_job_parameters: Parameters to carry to the Neo4j jobs
|
|
231
|
+
:return: Nothing
|
|
232
|
+
"""
|
|
233
|
+
logger.debug("Syncing Google Workspace OAuth Apps")
|
|
234
|
+
|
|
235
|
+
# 1. GET - Fetch data from API
|
|
236
|
+
tokens = get_all_oauth_tokens(admin, user_ids)
|
|
237
|
+
|
|
238
|
+
# 2. TRANSFORM - Shape data for ingestion
|
|
239
|
+
apps, authorizations = transform_oauth_apps_and_authorizations(tokens)
|
|
240
|
+
|
|
241
|
+
# 3. LOAD - Ingest apps to Neo4j using data model
|
|
242
|
+
load_googleworkspace_oauth_apps(
|
|
243
|
+
neo4j_session,
|
|
244
|
+
apps,
|
|
245
|
+
googleworkspace_update_tag,
|
|
246
|
+
common_job_parameters["CUSTOMER_ID"],
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# 4. LOAD - Create user to app authorization relationships
|
|
250
|
+
load_user_to_app_authorizations(
|
|
251
|
+
neo4j_session,
|
|
252
|
+
authorizations,
|
|
253
|
+
googleworkspace_update_tag,
|
|
254
|
+
common_job_parameters["CUSTOMER_ID"],
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# 5. CLEANUP - Remove stale data
|
|
258
|
+
cleanup_googleworkspace_oauth_apps(neo4j_session, common_job_parameters)
|
|
259
|
+
cleanup_user_to_app_authorizations(neo4j_session, common_job_parameters)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
from googleapiclient.discovery import Resource
|
|
6
|
+
from googleapiclient.errors import HttpError
|
|
7
|
+
|
|
8
|
+
from cartography.client.core.tx import load
|
|
9
|
+
from cartography.models.googleworkspace.tenant import GoogleWorkspaceTenantSchema
|
|
10
|
+
from cartography.util import timeit
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
GOOGLE_API_NUM_RETRIES = 5
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@timeit
|
|
18
|
+
def get_tenant(admin: Resource) -> dict[str, Any]:
|
|
19
|
+
"""
|
|
20
|
+
Return the Google Workspace tenant information
|
|
21
|
+
https://developers.google.com/workspace/admin/directory/reference/rest/v1/customers/get
|
|
22
|
+
|
|
23
|
+
:param admin: apiclient discovery resource object
|
|
24
|
+
:return: Google Workspace tenant information
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
req = admin.customers().get(
|
|
28
|
+
customerKey="my_customer",
|
|
29
|
+
)
|
|
30
|
+
resp = req.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
31
|
+
return resp
|
|
32
|
+
except HttpError as e:
|
|
33
|
+
if (
|
|
34
|
+
e.resp.status == 403
|
|
35
|
+
and "Request had insufficient authentication scopes" in str(e)
|
|
36
|
+
):
|
|
37
|
+
logger.error(
|
|
38
|
+
"Missing required Google Workspace scopes. If using the gcloud CLI, "
|
|
39
|
+
"run: gcloud auth application-default login --scopes="
|
|
40
|
+
"https://www.googleapis.com/auth/admin.directory.customer.readonly,"
|
|
41
|
+
"https://www.googleapis.com/auth/admin.directory.user.readonly,"
|
|
42
|
+
"https://www.googleapis.com/auth/admin.directory.user.security,"
|
|
43
|
+
"https://www.googleapis.com/auth/cloud-identity.devices.readonly,"
|
|
44
|
+
"https://www.googleapis.com/auth/cloud-identity.groups.readonly,"
|
|
45
|
+
"https://www.googleapis.com/auth/cloud-platform"
|
|
46
|
+
)
|
|
47
|
+
raise
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@timeit
|
|
51
|
+
def load_googleworkspace_tenant(
|
|
52
|
+
neo4j_session: neo4j.Session,
|
|
53
|
+
tenant_data: dict[str, Any],
|
|
54
|
+
googleworkspace_update_tag: int,
|
|
55
|
+
) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Load Google Workspace tenant
|
|
58
|
+
"""
|
|
59
|
+
logger.info("Ingesting %s Google Workspace tenant", tenant_data["id"])
|
|
60
|
+
load(
|
|
61
|
+
neo4j_session,
|
|
62
|
+
GoogleWorkspaceTenantSchema(),
|
|
63
|
+
[tenant_data],
|
|
64
|
+
lastupdated=googleworkspace_update_tag,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@timeit
|
|
69
|
+
def sync_googleworkspace_tenant(
|
|
70
|
+
neo4j_session: neo4j.Session,
|
|
71
|
+
admin: Resource,
|
|
72
|
+
googleworkspace_update_tag: int,
|
|
73
|
+
common_job_parameters: dict[str, Any],
|
|
74
|
+
) -> list[str]:
|
|
75
|
+
"""Sync Google Workspace tenant data."""
|
|
76
|
+
logger.debug("Syncing Google Workspace Tenant data")
|
|
77
|
+
|
|
78
|
+
# GET - Fetch data from API
|
|
79
|
+
resp_obj = get_tenant(admin)
|
|
80
|
+
|
|
81
|
+
# LOAD - Ingest to Neo4j using data model
|
|
82
|
+
load_googleworkspace_tenant(neo4j_session, resp_obj, googleworkspace_update_tag)
|
|
83
|
+
|
|
84
|
+
# Return the customer ID
|
|
85
|
+
return resp_obj["id"]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
from googleapiclient.discovery import Resource
|
|
6
|
+
|
|
7
|
+
from cartography.client.core.tx import load
|
|
8
|
+
from cartography.graph.job import GraphJob
|
|
9
|
+
from cartography.models.googleworkspace.user import GoogleWorkspaceUserSchema
|
|
10
|
+
from cartography.util import timeit
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
GOOGLE_API_NUM_RETRIES = 5
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@timeit
|
|
18
|
+
def get_all_users(admin: Resource) -> list[dict]:
|
|
19
|
+
"""
|
|
20
|
+
Return list of Google Users in your organization
|
|
21
|
+
Returns empty list if we are unable to enumerate the users for any reasons
|
|
22
|
+
https://developers.google.com/admin-sdk/directory/v1/guides/manage-users
|
|
23
|
+
|
|
24
|
+
:param admin: apiclient discovery resource object
|
|
25
|
+
:return: list of Google users in domain
|
|
26
|
+
see https://developers.google.com/admin-sdk/directory/v1/guides/manage-users#get_all_domain_users
|
|
27
|
+
"""
|
|
28
|
+
request = admin.users().list(
|
|
29
|
+
customer="my_customer",
|
|
30
|
+
maxResults=500,
|
|
31
|
+
orderBy="email",
|
|
32
|
+
)
|
|
33
|
+
response_objects = []
|
|
34
|
+
while request is not None:
|
|
35
|
+
resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
36
|
+
response_objects.append(resp)
|
|
37
|
+
request = admin.users().list_next(request, resp)
|
|
38
|
+
return response_objects
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@timeit
|
|
42
|
+
def transform_users(response_objects: list[dict]) -> list[dict[str, Any]]:
|
|
43
|
+
"""Transform list of API response objects to return list of user objects with flattened structure grouped by customerId
|
|
44
|
+
:param response_objects: Raw API response objects
|
|
45
|
+
:return: list of dictionary objects for data model consumption
|
|
46
|
+
"""
|
|
47
|
+
results = []
|
|
48
|
+
for response_object in response_objects:
|
|
49
|
+
for user in response_object["users"]:
|
|
50
|
+
# Flatten the nested name structure
|
|
51
|
+
transformed_user = user.copy()
|
|
52
|
+
if "name" in user and isinstance(user["name"], dict):
|
|
53
|
+
transformed_user["name"] = user["name"].get("fullName")
|
|
54
|
+
transformed_user["family_name"] = user["name"].get("familyName")
|
|
55
|
+
transformed_user["given_name"] = user["name"].get("givenName")
|
|
56
|
+
for org in user.get("organizations", []):
|
|
57
|
+
if org.get("primary"):
|
|
58
|
+
transformed_user["organization_name"] = org.get("name")
|
|
59
|
+
transformed_user["organization_title"] = org.get("title")
|
|
60
|
+
transformed_user["organization_department"] = org.get("department")
|
|
61
|
+
results.append(transformed_user)
|
|
62
|
+
return results
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@timeit
|
|
66
|
+
def load_googleworkspace_users(
|
|
67
|
+
neo4j_session: neo4j.Session,
|
|
68
|
+
data: list[dict[str, Any]],
|
|
69
|
+
googleworkspace_update_tag: int,
|
|
70
|
+
customer_id: str,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Load Google Workspace users
|
|
74
|
+
"""
|
|
75
|
+
logger.info(
|
|
76
|
+
"Ingesting %s Google Workspace users for customer %s", len(data), customer_id
|
|
77
|
+
)
|
|
78
|
+
# Load users with relationship to tenant
|
|
79
|
+
load(
|
|
80
|
+
neo4j_session,
|
|
81
|
+
GoogleWorkspaceUserSchema(),
|
|
82
|
+
data,
|
|
83
|
+
lastupdated=googleworkspace_update_tag,
|
|
84
|
+
CUSTOMER_ID=customer_id,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@timeit
|
|
89
|
+
def cleanup_googleworkspace_users(
|
|
90
|
+
neo4j_session: neo4j.Session,
|
|
91
|
+
common_job_parameters: dict[str, Any],
|
|
92
|
+
) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Clean up Google Workspace users
|
|
95
|
+
"""
|
|
96
|
+
logger.debug("Running Google Workspace users cleanup job")
|
|
97
|
+
GraphJob.from_node_schema(GoogleWorkspaceUserSchema(), common_job_parameters).run(
|
|
98
|
+
neo4j_session
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@timeit
|
|
103
|
+
def sync_googleworkspace_users(
|
|
104
|
+
neo4j_session: neo4j.Session,
|
|
105
|
+
admin: Resource,
|
|
106
|
+
googleworkspace_update_tag: int,
|
|
107
|
+
common_job_parameters: dict[str, Any],
|
|
108
|
+
) -> list[str]:
|
|
109
|
+
"""
|
|
110
|
+
GET Google Workspace user objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
|
|
111
|
+
|
|
112
|
+
:param neo4j_session: The Neo4j session
|
|
113
|
+
:param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
|
|
114
|
+
See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
|
|
115
|
+
:param googleworkspace_update_tag: The timestamp value to set our new Neo4j nodes with
|
|
116
|
+
:param common_job_parameters: Parameters to carry to the Neo4j jobs
|
|
117
|
+
:return: List of user IDs
|
|
118
|
+
"""
|
|
119
|
+
logger.debug("Syncing Google Workspace Users")
|
|
120
|
+
|
|
121
|
+
# 1. GET - Fetch data from API
|
|
122
|
+
resp_objs = get_all_users(admin)
|
|
123
|
+
|
|
124
|
+
# 2. TRANSFORM - Shape data for ingestion
|
|
125
|
+
raw_users = transform_users(resp_objs)
|
|
126
|
+
|
|
127
|
+
# 3. LOAD - Ingest to Neo4j using data model
|
|
128
|
+
load_googleworkspace_users(
|
|
129
|
+
neo4j_session,
|
|
130
|
+
raw_users,
|
|
131
|
+
googleworkspace_update_tag,
|
|
132
|
+
common_job_parameters["CUSTOMER_ID"],
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# 4. CLEANUP - Remove stale data
|
|
136
|
+
cleanup_googleworkspace_users(neo4j_session, common_job_parameters)
|
|
137
|
+
|
|
138
|
+
return [user["id"] for user in raw_users]
|
|
@@ -16,7 +16,8 @@ from google.oauth2.service_account import Credentials as ServiceAccountCredentia
|
|
|
16
16
|
from googleapiclient.discovery import Resource
|
|
17
17
|
|
|
18
18
|
from cartography.config import Config
|
|
19
|
-
from cartography.intel.gsuite import
|
|
19
|
+
from cartography.intel.gsuite import groups
|
|
20
|
+
from cartography.intel.gsuite import users
|
|
20
21
|
from cartography.util import timeit
|
|
21
22
|
|
|
22
23
|
OAUTH_SCOPES = [
|
|
@@ -119,7 +120,6 @@ def start_gsuite_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
|
|
|
119
120
|
scopes=OAUTH_SCOPES,
|
|
120
121
|
)
|
|
121
122
|
creds.refresh(Request())
|
|
122
|
-
creds = creds.create_scoped(OAUTH_SCOPES)
|
|
123
123
|
except DefaultCredentialsError as e:
|
|
124
124
|
logger.error(
|
|
125
125
|
(
|
|
@@ -147,16 +147,24 @@ def start_gsuite_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
|
|
|
147
147
|
)
|
|
148
148
|
return
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
resources.admin,
|
|
154
|
-
config.update_tag,
|
|
155
|
-
common_job_parameters,
|
|
150
|
+
logger.warning(
|
|
151
|
+
"The GSuite module is deprecated and will no longer receive updates. It will be completely removed in the 1.0.0 release. "
|
|
152
|
+
"For migration, please refer to the Google Workspace module configuration."
|
|
156
153
|
)
|
|
157
|
-
|
|
154
|
+
|
|
155
|
+
resources = _initialize_resources(creds)
|
|
156
|
+
customer_ids = users.sync_gsuite_users(
|
|
158
157
|
neo4j_session,
|
|
159
158
|
resources.admin,
|
|
160
159
|
config.update_tag,
|
|
161
160
|
common_job_parameters,
|
|
162
161
|
)
|
|
162
|
+
for customer_id in customer_ids:
|
|
163
|
+
scoped_job_parameters = common_job_parameters.copy()
|
|
164
|
+
scoped_job_parameters["CUSTOMER_ID"] = customer_id
|
|
165
|
+
groups.sync_gsuite_groups(
|
|
166
|
+
neo4j_session,
|
|
167
|
+
resources.admin,
|
|
168
|
+
config.update_tag,
|
|
169
|
+
scoped_job_parameters,
|
|
170
|
+
)
|