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,291 @@
|
|
|
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.gsuite.group import GSuiteGroupSchema
|
|
12
|
+
from cartography.models.gsuite.group import GSuiteGroupToGroupMemberRel
|
|
13
|
+
from cartography.models.gsuite.group import GSuiteGroupToGroupOwnerRel
|
|
14
|
+
from cartography.models.gsuite.tenant import GSuiteTenantSchema
|
|
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_all_groups(
|
|
24
|
+
admin: Resource, customer_id: str = "my_customer"
|
|
25
|
+
) -> list[dict[str, Any]]:
|
|
26
|
+
"""
|
|
27
|
+
Return list of Google Groups in your organization
|
|
28
|
+
Returns empty list if we are unable to enumerate the groups for any reasons
|
|
29
|
+
|
|
30
|
+
googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials, cache_discovery=False)
|
|
31
|
+
|
|
32
|
+
:param admin: google's apiclient discovery resource object. From googleapiclient.discovery.build
|
|
33
|
+
See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
|
|
34
|
+
:return: list of Google groups in domain
|
|
35
|
+
"""
|
|
36
|
+
request = admin.groups().list(
|
|
37
|
+
customer=customer_id,
|
|
38
|
+
maxResults=20,
|
|
39
|
+
orderBy="email",
|
|
40
|
+
)
|
|
41
|
+
response_objects = []
|
|
42
|
+
while request is not None:
|
|
43
|
+
try:
|
|
44
|
+
resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
45
|
+
response_objects.extend(resp.get("groups", []))
|
|
46
|
+
request = admin.groups().list_next(request, resp)
|
|
47
|
+
except HttpError as e:
|
|
48
|
+
if (
|
|
49
|
+
e.resp.status == 403
|
|
50
|
+
and "Request had insufficient authentication scopes" in str(e)
|
|
51
|
+
):
|
|
52
|
+
logger.error(
|
|
53
|
+
"Missing required GSuite scopes. If using the gcloud CLI, "
|
|
54
|
+
"run: gcloud auth application-default login --scopes="
|
|
55
|
+
'"https://www.googleapis.com/auth/admin.directory.user.readonly,'
|
|
56
|
+
"https://www.googleapis.com/auth/admin.directory.group.readonly,"
|
|
57
|
+
"https://www.googleapis.com/auth/admin.directory.group.member.readonly,"
|
|
58
|
+
'https://www.googleapis.com/auth/cloud-platform"'
|
|
59
|
+
)
|
|
60
|
+
raise
|
|
61
|
+
return response_objects
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@timeit
|
|
65
|
+
def get_members_for_groups(
|
|
66
|
+
admin: Resource, groups_email: list[str]
|
|
67
|
+
) -> dict[str, list[dict[str, Any]]]:
|
|
68
|
+
"""Get all members for given groups emails
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
admin (Resource): google's apiclient discovery resource object. From googleapiclient.discovery.build
|
|
72
|
+
See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
|
|
73
|
+
groups_email (list[str]): List of group email addresses to get members for
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
:return: list of dictionaries representing Users or Groups grouped by group email
|
|
77
|
+
"""
|
|
78
|
+
results: dict[str, list[dict]] = {}
|
|
79
|
+
for group_email in groups_email:
|
|
80
|
+
request = admin.members().list(
|
|
81
|
+
groupKey=group_email,
|
|
82
|
+
maxResults=500,
|
|
83
|
+
)
|
|
84
|
+
members: list[dict] = []
|
|
85
|
+
while request is not None:
|
|
86
|
+
resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
87
|
+
members = members + resp.get("members", [])
|
|
88
|
+
request = admin.members().list_next(request, resp)
|
|
89
|
+
results[group_email] = members
|
|
90
|
+
|
|
91
|
+
return results
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@timeit
|
|
95
|
+
def transform_groups(
|
|
96
|
+
groups: list[dict], group_memberships: dict[str, list[dict[str, Any]]]
|
|
97
|
+
) -> tuple[list[dict], list[dict], list[dict]]:
|
|
98
|
+
"""Strips list of API response objects to return list of group objects only and lists of subgroup relationships
|
|
99
|
+
|
|
100
|
+
:param groups: Raw groups from Google API
|
|
101
|
+
:param group_memberships: Group memberships data
|
|
102
|
+
:return: tuple of (groups, group_member_relationships, group_owner_relationships)
|
|
103
|
+
"""
|
|
104
|
+
transformed_groups: list[dict] = []
|
|
105
|
+
group_member_relationships: list[dict] = []
|
|
106
|
+
group_owner_relationships: list[dict] = []
|
|
107
|
+
|
|
108
|
+
for group in groups:
|
|
109
|
+
group_id = group["id"]
|
|
110
|
+
group_email = group["email"]
|
|
111
|
+
group["member_ids"] = []
|
|
112
|
+
group["owner_ids"] = []
|
|
113
|
+
|
|
114
|
+
for member in group_memberships.get(group_email, []):
|
|
115
|
+
if member["type"] == "GROUP":
|
|
116
|
+
# Create group-to-group relationships
|
|
117
|
+
relationship_data = {
|
|
118
|
+
"parent_group_id": group_id,
|
|
119
|
+
"subgroup_id": member.get("id"),
|
|
120
|
+
"role": member.get("role"),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if member.get("role") == "OWNER":
|
|
124
|
+
group_owner_relationships.append(relationship_data)
|
|
125
|
+
else:
|
|
126
|
+
group_member_relationships.append(relationship_data)
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
# Handle user memberships
|
|
130
|
+
if member.get("role") == "OWNER":
|
|
131
|
+
group["owner_ids"].append(member.get("id"))
|
|
132
|
+
group["member_ids"].append(member.get("id"))
|
|
133
|
+
|
|
134
|
+
transformed_groups.append(group)
|
|
135
|
+
|
|
136
|
+
return transformed_groups, group_member_relationships, group_owner_relationships
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@timeit
|
|
140
|
+
def load_gsuite_groups(
|
|
141
|
+
neo4j_session: neo4j.Session,
|
|
142
|
+
groups: list[dict],
|
|
143
|
+
customer_id: str,
|
|
144
|
+
gsuite_update_tag: int,
|
|
145
|
+
) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Load GSuite groups using the modern data model
|
|
148
|
+
"""
|
|
149
|
+
logger.info("Ingesting %d gsuite groups", len(groups))
|
|
150
|
+
|
|
151
|
+
# Load tenant first if it doesn't exist
|
|
152
|
+
tenant_data = [{"id": customer_id}]
|
|
153
|
+
load(
|
|
154
|
+
neo4j_session,
|
|
155
|
+
GSuiteTenantSchema(),
|
|
156
|
+
tenant_data,
|
|
157
|
+
lastupdated=gsuite_update_tag,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Load groups with relationship to tenant
|
|
161
|
+
load(
|
|
162
|
+
neo4j_session,
|
|
163
|
+
GSuiteGroupSchema(),
|
|
164
|
+
groups,
|
|
165
|
+
lastupdated=gsuite_update_tag,
|
|
166
|
+
CUSTOMER_ID=customer_id,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@timeit
|
|
171
|
+
def load_gsuite_group_to_group_relationships(
|
|
172
|
+
neo4j_session: neo4j.Session,
|
|
173
|
+
group_member_relationships: list[dict],
|
|
174
|
+
group_owner_relationships: list[dict],
|
|
175
|
+
customer_id: str,
|
|
176
|
+
gsuite_update_tag: int,
|
|
177
|
+
) -> None:
|
|
178
|
+
"""
|
|
179
|
+
Load GSuite group-to-group relationships using MatchLinks
|
|
180
|
+
"""
|
|
181
|
+
logger.info(
|
|
182
|
+
"Ingesting %d group member relationships", len(group_member_relationships)
|
|
183
|
+
)
|
|
184
|
+
logger.info(
|
|
185
|
+
"Ingesting %d group owner relationships", len(group_owner_relationships)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Load group member relationships (Group -> Group MEMBER)
|
|
189
|
+
if group_member_relationships:
|
|
190
|
+
load_matchlinks(
|
|
191
|
+
neo4j_session,
|
|
192
|
+
GSuiteGroupToGroupMemberRel(),
|
|
193
|
+
group_member_relationships,
|
|
194
|
+
lastupdated=gsuite_update_tag,
|
|
195
|
+
_sub_resource_label="GSuiteTenant",
|
|
196
|
+
_sub_resource_id=customer_id,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Load group owner relationships (Group -> Group OWNER)
|
|
200
|
+
if group_owner_relationships:
|
|
201
|
+
load_matchlinks(
|
|
202
|
+
neo4j_session,
|
|
203
|
+
GSuiteGroupToGroupOwnerRel(),
|
|
204
|
+
group_owner_relationships,
|
|
205
|
+
lastupdated=gsuite_update_tag,
|
|
206
|
+
_sub_resource_label="GSuiteTenant",
|
|
207
|
+
_sub_resource_id=customer_id,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@timeit
|
|
212
|
+
def cleanup_gsuite_groups(
|
|
213
|
+
neo4j_session: neo4j.Session,
|
|
214
|
+
common_job_parameters: dict[str, Any],
|
|
215
|
+
customer_id: str,
|
|
216
|
+
gsuite_update_tag: int,
|
|
217
|
+
) -> None:
|
|
218
|
+
"""
|
|
219
|
+
Clean up GSuite groups and group-to-group relationships using the modern data model
|
|
220
|
+
"""
|
|
221
|
+
logger.debug("Running GSuite groups cleanup job")
|
|
222
|
+
|
|
223
|
+
# Cleanup group nodes
|
|
224
|
+
GraphJob.from_node_schema(GSuiteGroupSchema(), common_job_parameters).run(
|
|
225
|
+
neo4j_session
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Cleanup group-to-group member relationships
|
|
229
|
+
GraphJob.from_matchlink(
|
|
230
|
+
GSuiteGroupToGroupMemberRel(),
|
|
231
|
+
"GSuiteTenant",
|
|
232
|
+
customer_id,
|
|
233
|
+
gsuite_update_tag,
|
|
234
|
+
).run(neo4j_session)
|
|
235
|
+
|
|
236
|
+
# Cleanup group-to-group owner relationships
|
|
237
|
+
GraphJob.from_matchlink(
|
|
238
|
+
GSuiteGroupToGroupOwnerRel(),
|
|
239
|
+
"GSuiteTenant",
|
|
240
|
+
customer_id,
|
|
241
|
+
gsuite_update_tag,
|
|
242
|
+
).run(neo4j_session)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@timeit
|
|
246
|
+
def sync_gsuite_groups(
|
|
247
|
+
neo4j_session: neo4j.Session,
|
|
248
|
+
admin: Resource,
|
|
249
|
+
gsuite_update_tag: int,
|
|
250
|
+
common_job_parameters: dict[str, Any],
|
|
251
|
+
) -> None:
|
|
252
|
+
"""
|
|
253
|
+
GET GSuite group objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
|
|
254
|
+
|
|
255
|
+
:param neo4j_session: The Neo4j session
|
|
256
|
+
:param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
|
|
257
|
+
See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
|
|
258
|
+
:param gsuite_update_tag: The timestamp value to set our new Neo4j nodes with
|
|
259
|
+
:param common_job_parameters: Parameters to carry to the Neo4j jobs
|
|
260
|
+
:return: Nothing
|
|
261
|
+
"""
|
|
262
|
+
logger.debug("Syncing GSuite Groups")
|
|
263
|
+
|
|
264
|
+
customer_id = common_job_parameters.get(
|
|
265
|
+
"CUSTOMER_ID", "my_customer"
|
|
266
|
+
) # Default to "my_customer" for backward compatibility
|
|
267
|
+
|
|
268
|
+
# 1. GET - Fetch data from API
|
|
269
|
+
resp_objs = get_all_groups(admin, customer_id)
|
|
270
|
+
group_members = get_members_for_groups(admin, [resp["email"] for resp in resp_objs])
|
|
271
|
+
|
|
272
|
+
# 2. TRANSFORM - Shape data for ingestion
|
|
273
|
+
groups, group_member_relationships, group_owner_relationships = transform_groups(
|
|
274
|
+
resp_objs, group_members
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# 3. LOAD - Ingest to Neo4j using data model
|
|
278
|
+
load_gsuite_groups(neo4j_session, groups, customer_id, gsuite_update_tag)
|
|
279
|
+
|
|
280
|
+
# Load group-to-group relationships after groups are loaded
|
|
281
|
+
load_gsuite_group_to_group_relationships(
|
|
282
|
+
neo4j_session,
|
|
283
|
+
group_member_relationships,
|
|
284
|
+
group_owner_relationships,
|
|
285
|
+
customer_id,
|
|
286
|
+
gsuite_update_tag,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# 4. CLEANUP - Remove stale data
|
|
290
|
+
cleanup_params = {**common_job_parameters, "CUSTOMER_ID": customer_id}
|
|
291
|
+
cleanup_gsuite_groups(neo4j_session, cleanup_params, customer_id, gsuite_update_tag)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import neo4j
|
|
6
|
+
from googleapiclient.discovery import Resource
|
|
7
|
+
|
|
8
|
+
from cartography.client.core.tx import load
|
|
9
|
+
from cartography.graph.job import GraphJob
|
|
10
|
+
from cartography.models.gsuite.tenant import GSuiteTenantSchema
|
|
11
|
+
from cartography.models.gsuite.user import GSuiteUserSchema
|
|
12
|
+
from cartography.util import timeit
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
GOOGLE_API_NUM_RETRIES = 5
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@timeit
|
|
20
|
+
def get_all_users(admin: Resource) -> list[dict]:
|
|
21
|
+
"""
|
|
22
|
+
Return list of Google Users in your organization
|
|
23
|
+
Returns empty list if we are unable to enumerate the users for any reasons
|
|
24
|
+
https://developers.google.com/admin-sdk/directory/v1/guides/manage-users
|
|
25
|
+
|
|
26
|
+
:param admin: apiclient discovery resource object
|
|
27
|
+
:return: list of Google users in domain
|
|
28
|
+
see https://developers.google.com/admin-sdk/directory/v1/guides/manage-users#get_all_domain_users
|
|
29
|
+
"""
|
|
30
|
+
request = admin.users().list(
|
|
31
|
+
customer="my_customer",
|
|
32
|
+
maxResults=500,
|
|
33
|
+
orderBy="email",
|
|
34
|
+
)
|
|
35
|
+
response_objects = []
|
|
36
|
+
while request is not None:
|
|
37
|
+
resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
|
|
38
|
+
response_objects.append(resp)
|
|
39
|
+
request = admin.users().list_next(request, resp)
|
|
40
|
+
return response_objects
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@timeit
|
|
44
|
+
def transform_users(response_objects: list[dict]) -> dict[str, list[dict[str, Any]]]:
|
|
45
|
+
"""Transform list of API response objects to return list of user objects with flattened structure grouped by customerId
|
|
46
|
+
:param response_objects: Raw API response objects
|
|
47
|
+
:return: list of dictionary objects for data model consumption
|
|
48
|
+
"""
|
|
49
|
+
results = defaultdict(list)
|
|
50
|
+
for response_object in response_objects:
|
|
51
|
+
for user in response_object["users"]:
|
|
52
|
+
# Flatten the nested name structure
|
|
53
|
+
transformed_user = user.copy()
|
|
54
|
+
if "name" in user and isinstance(user["name"], dict):
|
|
55
|
+
transformed_user["name"] = user["name"].get("fullName")
|
|
56
|
+
transformed_user["family_name"] = user["name"].get("familyName")
|
|
57
|
+
transformed_user["given_name"] = user["name"].get("givenName")
|
|
58
|
+
results[transformed_user["customerId"]].append(transformed_user)
|
|
59
|
+
return results
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@timeit
|
|
63
|
+
def load_gsuite_users(
|
|
64
|
+
neo4j_session: neo4j.Session,
|
|
65
|
+
users_by_customer: dict[str, list[dict]],
|
|
66
|
+
gsuite_update_tag: int,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Load GSuite users using the modern data model
|
|
70
|
+
"""
|
|
71
|
+
logger.info("Ingesting %s gsuite tenants", len(users_by_customer))
|
|
72
|
+
tenant_data = [{"id": customer_id} for customer_id in users_by_customer.keys()]
|
|
73
|
+
load(
|
|
74
|
+
neo4j_session,
|
|
75
|
+
GSuiteTenantSchema(),
|
|
76
|
+
tenant_data,
|
|
77
|
+
lastupdated=gsuite_update_tag,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
for customer_id, users in users_by_customer.items():
|
|
81
|
+
logger.info(
|
|
82
|
+
"Ingesting %s gsuite users for customer %s", len(users), customer_id
|
|
83
|
+
)
|
|
84
|
+
# Load users with relationship to tenant
|
|
85
|
+
load(
|
|
86
|
+
neo4j_session,
|
|
87
|
+
GSuiteUserSchema(),
|
|
88
|
+
users,
|
|
89
|
+
lastupdated=gsuite_update_tag,
|
|
90
|
+
CUSTOMER_ID=customer_id,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@timeit
|
|
95
|
+
def cleanup_gsuite_users(
|
|
96
|
+
neo4j_session: neo4j.Session,
|
|
97
|
+
common_job_parameters: dict[str, Any],
|
|
98
|
+
) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Clean up GSuite users using the modern data model
|
|
101
|
+
"""
|
|
102
|
+
logger.debug("Running GSuite users cleanup job")
|
|
103
|
+
GraphJob.from_node_schema(GSuiteUserSchema(), common_job_parameters).run(
|
|
104
|
+
neo4j_session
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@timeit
|
|
109
|
+
def sync_gsuite_users(
|
|
110
|
+
neo4j_session: neo4j.Session,
|
|
111
|
+
admin: Resource,
|
|
112
|
+
gsuite_update_tag: int,
|
|
113
|
+
common_job_parameters: dict[str, Any],
|
|
114
|
+
) -> list[str]:
|
|
115
|
+
"""
|
|
116
|
+
GET GSuite user objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
|
|
117
|
+
|
|
118
|
+
:param neo4j_session: The Neo4j session
|
|
119
|
+
:param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
|
|
120
|
+
See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
|
|
121
|
+
:param gsuite_update_tag: The timestamp value to set our new Neo4j nodes with
|
|
122
|
+
:param common_job_parameters: Parameters to carry to the Neo4j jobs
|
|
123
|
+
:return: list of customer IDs
|
|
124
|
+
"""
|
|
125
|
+
logger.debug("Syncing GSuite Users")
|
|
126
|
+
|
|
127
|
+
# 1. GET - Fetch data from API
|
|
128
|
+
resp_objs = get_all_users(admin)
|
|
129
|
+
|
|
130
|
+
# 2. TRANSFORM - Shape data for ingestion
|
|
131
|
+
users_by_customers = transform_users(resp_objs)
|
|
132
|
+
|
|
133
|
+
# 3. LOAD - Ingest to Neo4j using data model
|
|
134
|
+
load_gsuite_users(neo4j_session, users_by_customers, gsuite_update_tag)
|
|
135
|
+
|
|
136
|
+
# 4. CLEANUP - Remove stale data
|
|
137
|
+
for customer_id in users_by_customers.keys():
|
|
138
|
+
cleanup_params = {**common_job_parameters, "CUSTOMER_ID": customer_id}
|
|
139
|
+
cleanup_gsuite_users(neo4j_session, cleanup_params)
|
|
140
|
+
|
|
141
|
+
# Return the list of customer IDs
|
|
142
|
+
return list(users_by_customers.keys())
|
|
@@ -4,6 +4,7 @@ from typing import List
|
|
|
4
4
|
|
|
5
5
|
import neo4j
|
|
6
6
|
|
|
7
|
+
from cartography.client.core.tx import run_write_query
|
|
7
8
|
from cartography.intel.jamf.util import call_jamf_api
|
|
8
9
|
from cartography.util import run_cleanup_job
|
|
9
10
|
from cartography.util import timeit
|
|
@@ -35,7 +36,12 @@ def load_computer_groups(
|
|
|
35
36
|
g.lastupdated = $UpdateTag
|
|
36
37
|
"""
|
|
37
38
|
groups = data.get("computer_groups")
|
|
38
|
-
|
|
39
|
+
run_write_query(
|
|
40
|
+
neo4j_session,
|
|
41
|
+
ingest_groups,
|
|
42
|
+
JsonData=groups,
|
|
43
|
+
UpdateTag=update_tag,
|
|
44
|
+
)
|
|
39
45
|
|
|
40
46
|
|
|
41
47
|
@timeit
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import neo4j
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
import cartography.intel.keycloak.authenticationexecutions
|
|
7
|
+
import cartography.intel.keycloak.authenticationflows
|
|
8
|
+
import cartography.intel.keycloak.clients
|
|
9
|
+
import cartography.intel.keycloak.groups
|
|
10
|
+
import cartography.intel.keycloak.identityproviders
|
|
11
|
+
import cartography.intel.keycloak.organizations
|
|
12
|
+
import cartography.intel.keycloak.realms
|
|
13
|
+
import cartography.intel.keycloak.roles
|
|
14
|
+
import cartography.intel.keycloak.scopes
|
|
15
|
+
import cartography.intel.keycloak.users
|
|
16
|
+
from cartography.config import Config
|
|
17
|
+
from cartography.util import timeit
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
_TIMEOUT = (60, 60)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@timeit
|
|
24
|
+
def start_keycloak_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
25
|
+
"""
|
|
26
|
+
If this module is configured, perform ingestion of Keycloak data. Otherwise warn and exit
|
|
27
|
+
:param neo4j_session: Neo4J session for database interface
|
|
28
|
+
:param config: A cartography.config object
|
|
29
|
+
:return: None
|
|
30
|
+
"""
|
|
31
|
+
if (
|
|
32
|
+
not config.keycloak_client_id
|
|
33
|
+
or not config.keycloak_client_secret
|
|
34
|
+
or not config.keycloak_url
|
|
35
|
+
or not config.keycloak_realm
|
|
36
|
+
):
|
|
37
|
+
logger.info(
|
|
38
|
+
"Keycloak import is not configured - skipping this module. "
|
|
39
|
+
"See docs to configure.",
|
|
40
|
+
)
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
# Create requests sessions
|
|
44
|
+
with requests.session() as api_session:
|
|
45
|
+
payload = {
|
|
46
|
+
"grant_type": "client_credentials",
|
|
47
|
+
"client_id": config.keycloak_client_id,
|
|
48
|
+
"client_secret": config.keycloak_client_secret,
|
|
49
|
+
}
|
|
50
|
+
req = api_session.post(
|
|
51
|
+
f"{config.keycloak_url}/realms/{config.keycloak_realm}/protocol/openid-connect/token",
|
|
52
|
+
data=payload,
|
|
53
|
+
timeout=_TIMEOUT,
|
|
54
|
+
)
|
|
55
|
+
req.raise_for_status()
|
|
56
|
+
api_session.headers.update(
|
|
57
|
+
{"Authorization": f'Bearer {req.json()["access_token"]}'}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
common_job_parameters = {
|
|
61
|
+
"UPDATE_TAG": config.update_tag,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for realm in cartography.intel.keycloak.realms.sync(
|
|
65
|
+
neo4j_session, api_session, config.keycloak_url, common_job_parameters
|
|
66
|
+
):
|
|
67
|
+
realm_scopped_job_parameters = {
|
|
68
|
+
"UPDATE_TAG": config.update_tag,
|
|
69
|
+
"REALM": realm["realm"],
|
|
70
|
+
"REALM_ID": realm["id"],
|
|
71
|
+
}
|
|
72
|
+
cartography.intel.keycloak.users.sync(
|
|
73
|
+
neo4j_session,
|
|
74
|
+
api_session,
|
|
75
|
+
config.keycloak_url,
|
|
76
|
+
realm_scopped_job_parameters,
|
|
77
|
+
)
|
|
78
|
+
cartography.intel.keycloak.identityproviders.sync(
|
|
79
|
+
neo4j_session,
|
|
80
|
+
api_session,
|
|
81
|
+
config.keycloak_url,
|
|
82
|
+
realm_scopped_job_parameters,
|
|
83
|
+
)
|
|
84
|
+
scopes = cartography.intel.keycloak.scopes.sync(
|
|
85
|
+
neo4j_session,
|
|
86
|
+
api_session,
|
|
87
|
+
config.keycloak_url,
|
|
88
|
+
realm_scopped_job_parameters,
|
|
89
|
+
)
|
|
90
|
+
scope_ids = [s["id"] for s in scopes]
|
|
91
|
+
flows = cartography.intel.keycloak.authenticationflows.sync(
|
|
92
|
+
neo4j_session,
|
|
93
|
+
api_session,
|
|
94
|
+
config.keycloak_url,
|
|
95
|
+
realm_scopped_job_parameters,
|
|
96
|
+
)
|
|
97
|
+
flow_aliases_to_id = {f["alias"]: f["id"] for f in flows}
|
|
98
|
+
cartography.intel.keycloak.authenticationexecutions.sync(
|
|
99
|
+
neo4j_session,
|
|
100
|
+
api_session,
|
|
101
|
+
config.keycloak_url,
|
|
102
|
+
realm_scopped_job_parameters,
|
|
103
|
+
list(flow_aliases_to_id.keys()),
|
|
104
|
+
)
|
|
105
|
+
realm_default_flows = {
|
|
106
|
+
"browser": flow_aliases_to_id.get(realm.get("browserFlow")),
|
|
107
|
+
"registration": flow_aliases_to_id.get(realm.get("registrationFlow")),
|
|
108
|
+
"direct_grant": flow_aliases_to_id.get(realm.get("directGrantFlow")),
|
|
109
|
+
"reset_credentials": flow_aliases_to_id.get(
|
|
110
|
+
realm.get("resetCredentialsFlow")
|
|
111
|
+
),
|
|
112
|
+
"client_authentication": flow_aliases_to_id.get(
|
|
113
|
+
realm.get("clientAuthenticationFlow")
|
|
114
|
+
),
|
|
115
|
+
"docker_authentication": flow_aliases_to_id.get(
|
|
116
|
+
realm.get("dockerAuthenticationFlow")
|
|
117
|
+
),
|
|
118
|
+
"first_broker_login": flow_aliases_to_id.get(
|
|
119
|
+
realm.get("firstBrokerLoginFlow")
|
|
120
|
+
),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
clients = cartography.intel.keycloak.clients.sync(
|
|
124
|
+
neo4j_session,
|
|
125
|
+
api_session,
|
|
126
|
+
config.keycloak_url,
|
|
127
|
+
realm_scopped_job_parameters,
|
|
128
|
+
realm_default_flows,
|
|
129
|
+
)
|
|
130
|
+
client_ids = [c["id"] for c in clients]
|
|
131
|
+
cartography.intel.keycloak.roles.sync(
|
|
132
|
+
neo4j_session,
|
|
133
|
+
api_session,
|
|
134
|
+
config.keycloak_url,
|
|
135
|
+
realm_scopped_job_parameters,
|
|
136
|
+
client_ids,
|
|
137
|
+
scope_ids,
|
|
138
|
+
)
|
|
139
|
+
cartography.intel.keycloak.groups.sync(
|
|
140
|
+
neo4j_session,
|
|
141
|
+
api_session,
|
|
142
|
+
config.keycloak_url,
|
|
143
|
+
realm_scopped_job_parameters,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Organizations if they are enabled
|
|
147
|
+
if realm.get("organizationsEnabled", False):
|
|
148
|
+
cartography.intel.keycloak.organizations.sync(
|
|
149
|
+
neo4j_session,
|
|
150
|
+
api_session,
|
|
151
|
+
config.keycloak_url,
|
|
152
|
+
realm_scopped_job_parameters,
|
|
153
|
+
)
|