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,216 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Framework and Fact execution logic for Cartography rules.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from neo4j import Driver
|
|
6
|
+
from neo4j import GraphDatabase
|
|
7
|
+
|
|
8
|
+
from cartography.client.core.tx import read_list_of_dicts_tx
|
|
9
|
+
from cartography.rules.data.rules import RULES
|
|
10
|
+
from cartography.rules.formatters import _format_and_output_results
|
|
11
|
+
from cartography.rules.formatters import _generate_neo4j_browser_url
|
|
12
|
+
from cartography.rules.spec.model import Fact
|
|
13
|
+
from cartography.rules.spec.model import Maturity
|
|
14
|
+
from cartography.rules.spec.model import Rule
|
|
15
|
+
from cartography.rules.spec.result import CounterResult
|
|
16
|
+
from cartography.rules.spec.result import FactResult
|
|
17
|
+
from cartography.rules.spec.result import RuleResult
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _run_fact(
|
|
21
|
+
fact: Fact,
|
|
22
|
+
rule: Rule,
|
|
23
|
+
driver: Driver,
|
|
24
|
+
database: str,
|
|
25
|
+
counter: CounterResult,
|
|
26
|
+
output_format: str,
|
|
27
|
+
neo4j_uri: str,
|
|
28
|
+
) -> FactResult:
|
|
29
|
+
"""Execute a single fact and return the result."""
|
|
30
|
+
if output_format == "text":
|
|
31
|
+
print(
|
|
32
|
+
f"\n\033[1mFact {counter.current_fact}/{counter.total_facts}: {fact.name}\033[0m"
|
|
33
|
+
)
|
|
34
|
+
# Display rule
|
|
35
|
+
print(f" \033[36m{'Rule:':<12}\033[0m {rule.id} - {rule.name}")
|
|
36
|
+
# Display fact details
|
|
37
|
+
print(f" \033[36m{'Fact ID:':<12}\033[0m {fact.id}")
|
|
38
|
+
print(f" \033[36m{'Description:':<12}\033[0m {fact.description}")
|
|
39
|
+
print(f" \033[36m{'Provider:':<12}\033[0m {fact.module.value}")
|
|
40
|
+
|
|
41
|
+
# Generate and display clickable Neo4j Browser URL
|
|
42
|
+
browser_url = _generate_neo4j_browser_url(neo4j_uri, fact.cypher_visual_query)
|
|
43
|
+
print(
|
|
44
|
+
f" \033[36m{'Neo4j Query:':<12}\033[0m \033]8;;{browser_url}\033\\Click to run visual query\033]8;;\033\\"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
with driver.session(database=database) as session:
|
|
48
|
+
raw_findings = session.execute_read(read_list_of_dicts_tx, fact.cypher_query)
|
|
49
|
+
findings = rule.parse_results(fact, raw_findings)
|
|
50
|
+
findings_count = len(findings)
|
|
51
|
+
|
|
52
|
+
if output_format == "text":
|
|
53
|
+
if findings_count > 0:
|
|
54
|
+
print(f" \033[36m{'Results:':<12}\033[0m {findings_count} item(s) found")
|
|
55
|
+
|
|
56
|
+
# Show sample findings
|
|
57
|
+
print(" Sample results:")
|
|
58
|
+
for idx, finding in enumerate(findings[:3]): # Show first 3
|
|
59
|
+
# Format rule output nicely
|
|
60
|
+
formatted_items = []
|
|
61
|
+
for key, value in finding.__class__.model_fields.items():
|
|
62
|
+
if value is not None:
|
|
63
|
+
# Truncate long values
|
|
64
|
+
actual_value = getattr(finding, key)
|
|
65
|
+
str_value = str(actual_value)
|
|
66
|
+
if len(str_value) > 50:
|
|
67
|
+
str_value = str_value[:47] + "..."
|
|
68
|
+
formatted_items.append(f"{key}={str_value}")
|
|
69
|
+
if formatted_items:
|
|
70
|
+
print(f" {idx + 1}. {', '.join(formatted_items)}")
|
|
71
|
+
|
|
72
|
+
if findings_count > 3:
|
|
73
|
+
print(
|
|
74
|
+
f" ... and {findings_count - 3} more (use --output json to see all)"
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
print(f" \033[36m{'Results:':<12}\033[0m No items found")
|
|
78
|
+
|
|
79
|
+
# Create and return fact result
|
|
80
|
+
counter.total_findings += findings_count
|
|
81
|
+
|
|
82
|
+
return FactResult(
|
|
83
|
+
fact_id=fact.id,
|
|
84
|
+
fact_name=fact.name,
|
|
85
|
+
fact_description=fact.description,
|
|
86
|
+
fact_provider=fact.module.value,
|
|
87
|
+
findings=findings,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _run_single_rule(
|
|
92
|
+
rule_name: str,
|
|
93
|
+
driver: GraphDatabase.driver,
|
|
94
|
+
database: str,
|
|
95
|
+
output_format: str,
|
|
96
|
+
neo4j_uri: str,
|
|
97
|
+
fact_filter: str | None = None,
|
|
98
|
+
exclude_experimental: bool = False,
|
|
99
|
+
) -> RuleResult:
|
|
100
|
+
"""Execute a single rule and return results."""
|
|
101
|
+
rule = RULES[rule_name]
|
|
102
|
+
counter = CounterResult()
|
|
103
|
+
|
|
104
|
+
filtered_facts: list[Fact] = []
|
|
105
|
+
for fact in rule.facts:
|
|
106
|
+
if exclude_experimental and fact.maturity != Maturity.STABLE:
|
|
107
|
+
continue
|
|
108
|
+
if fact_filter:
|
|
109
|
+
if fact.id.lower() != fact_filter.lower():
|
|
110
|
+
continue
|
|
111
|
+
counter.total_facts += 1
|
|
112
|
+
filtered_facts.append(fact)
|
|
113
|
+
|
|
114
|
+
if output_format == "text":
|
|
115
|
+
print(f"Executing {rule.name} rule")
|
|
116
|
+
if fact_filter:
|
|
117
|
+
print(f"Filtered to fact: {fact_filter}")
|
|
118
|
+
print(f"Total facts: {counter.total_facts}")
|
|
119
|
+
|
|
120
|
+
# Execute requirements and collect results
|
|
121
|
+
rule_results = []
|
|
122
|
+
|
|
123
|
+
for fact in filtered_facts:
|
|
124
|
+
counter.current_fact += 1
|
|
125
|
+
fact_result = _run_fact(
|
|
126
|
+
fact,
|
|
127
|
+
rule,
|
|
128
|
+
driver,
|
|
129
|
+
database,
|
|
130
|
+
counter,
|
|
131
|
+
output_format,
|
|
132
|
+
neo4j_uri,
|
|
133
|
+
)
|
|
134
|
+
rule_results.append(fact_result)
|
|
135
|
+
|
|
136
|
+
# Create and return rule result
|
|
137
|
+
return RuleResult(
|
|
138
|
+
rule_id=rule.id,
|
|
139
|
+
rule_name=rule.name,
|
|
140
|
+
rule_description=rule.description,
|
|
141
|
+
facts=rule_results,
|
|
142
|
+
counter=counter,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def run_rules(
|
|
147
|
+
rule_names: list[str],
|
|
148
|
+
uri: str,
|
|
149
|
+
neo4j_user: str,
|
|
150
|
+
neo4j_password: str,
|
|
151
|
+
neo4j_database: str,
|
|
152
|
+
output_format: str = "text",
|
|
153
|
+
fact_filter: str | None = None,
|
|
154
|
+
exclude_experimental: bool = False,
|
|
155
|
+
):
|
|
156
|
+
"""
|
|
157
|
+
Execute the specified rules and present results.
|
|
158
|
+
|
|
159
|
+
:param rule_names: The names of the rules to execute.
|
|
160
|
+
:param uri: The URI of the Neo4j database. E.g. "bolt://localhost:7687" or "neo4j+s://tenant123.databases.neo4j.io:7687"
|
|
161
|
+
:param neo4j_user: The username for the Neo4j database.
|
|
162
|
+
:param neo4j_password: The password for the Neo4j database.
|
|
163
|
+
:param neo4j_database: The name of the Neo4j database.
|
|
164
|
+
:param output_format: Either "text" or "json". Defaults to "text".
|
|
165
|
+
:param fact_filter: Optional fact ID to filter execution (case-insensitive).
|
|
166
|
+
:param exclude_experimental: Whether to exclude experimental facts from execution.
|
|
167
|
+
:return: The exit code.
|
|
168
|
+
"""
|
|
169
|
+
# Validate all rules exist
|
|
170
|
+
for rule_name in rule_names:
|
|
171
|
+
if rule_name not in RULES:
|
|
172
|
+
if output_format == "text":
|
|
173
|
+
print(f"Unknown rule: {rule_name}")
|
|
174
|
+
print(f"Available rules: {', '.join(RULES.keys())}")
|
|
175
|
+
return 1
|
|
176
|
+
|
|
177
|
+
# Connect to Neo4j
|
|
178
|
+
if output_format == "text":
|
|
179
|
+
print(f"Connecting to Neo4j at {uri}...")
|
|
180
|
+
driver = GraphDatabase.driver(uri, auth=(neo4j_user, neo4j_password))
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
driver.verify_connectivity()
|
|
184
|
+
|
|
185
|
+
# Execute rules
|
|
186
|
+
all_results = []
|
|
187
|
+
total_facts = 0
|
|
188
|
+
total_findings = 0
|
|
189
|
+
|
|
190
|
+
for i, rule_name in enumerate(rule_names):
|
|
191
|
+
if output_format == "text" and len(rule_names) > 1:
|
|
192
|
+
if i > 0:
|
|
193
|
+
print("\n" + "=" * 60)
|
|
194
|
+
print(f"Executing rule {i + 1}/{len(rule_names)}: {rule_name}")
|
|
195
|
+
|
|
196
|
+
rule_result = _run_single_rule(
|
|
197
|
+
rule_name,
|
|
198
|
+
driver,
|
|
199
|
+
neo4j_database,
|
|
200
|
+
output_format,
|
|
201
|
+
uri,
|
|
202
|
+
fact_filter,
|
|
203
|
+
exclude_experimental,
|
|
204
|
+
)
|
|
205
|
+
all_results.append(rule_result)
|
|
206
|
+
total_facts += rule_result.counter.total_facts
|
|
207
|
+
total_findings += rule_result.counter.total_findings
|
|
208
|
+
|
|
209
|
+
# Output results
|
|
210
|
+
_format_and_output_results(
|
|
211
|
+
all_results, rule_names, output_format, total_facts, total_findings
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return 0
|
|
215
|
+
finally:
|
|
216
|
+
driver.close()
|
|
File without changes
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from dataclasses import field
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any
|
|
7
|
+
from typing import no_type_check
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from pydantic import ConfigDict
|
|
11
|
+
from pydantic import model_validator
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Module(str, Enum):
|
|
17
|
+
"""Services that can be monitored"""
|
|
18
|
+
|
|
19
|
+
AIRBYTE = "Airbyte"
|
|
20
|
+
"""Airbyte data integration"""
|
|
21
|
+
|
|
22
|
+
ANTHROPIC = "Anthropic"
|
|
23
|
+
"""Anthropic AI"""
|
|
24
|
+
|
|
25
|
+
AWS = "AWS"
|
|
26
|
+
"""Amazon Web Services"""
|
|
27
|
+
|
|
28
|
+
AZURE = "Azure"
|
|
29
|
+
"""Microsoft Azure"""
|
|
30
|
+
|
|
31
|
+
BIGFIX = "BigFix"
|
|
32
|
+
"""BigFix patch management"""
|
|
33
|
+
|
|
34
|
+
CLOUDFLARE = "Cloudflare"
|
|
35
|
+
"""Cloudflare services"""
|
|
36
|
+
|
|
37
|
+
CROWDSTRIKE = "CrowdStrike"
|
|
38
|
+
"""CrowdStrike endpoint security"""
|
|
39
|
+
|
|
40
|
+
DIGITALOCEAN = "DigitalOcean"
|
|
41
|
+
"""DigitalOcean cloud services"""
|
|
42
|
+
|
|
43
|
+
DUO = "Duo"
|
|
44
|
+
"""Duo authentication"""
|
|
45
|
+
|
|
46
|
+
ENTRA = "Entra"
|
|
47
|
+
"""Entra identity and access management"""
|
|
48
|
+
|
|
49
|
+
GCP = "GCP"
|
|
50
|
+
"""Google Cloud Platform"""
|
|
51
|
+
|
|
52
|
+
GITHUB = "GitHub"
|
|
53
|
+
"""GitHub source code management"""
|
|
54
|
+
|
|
55
|
+
GOOGLEWORKSPACE = "GoogleWorkspace"
|
|
56
|
+
"""Google Workspace identity and access management"""
|
|
57
|
+
|
|
58
|
+
JAMF = "Jamf"
|
|
59
|
+
"""Jamf endpoint security"""
|
|
60
|
+
|
|
61
|
+
KANDJI = "Kandji"
|
|
62
|
+
"""Kandji endpoint security"""
|
|
63
|
+
|
|
64
|
+
KEYCLOAK = "Keycloak"
|
|
65
|
+
"""Keycloak identity and access management"""
|
|
66
|
+
|
|
67
|
+
KUBERNETES = "Kubernetes"
|
|
68
|
+
"""Kubernetes cluster security"""
|
|
69
|
+
|
|
70
|
+
LASTPASS = "LastPass"
|
|
71
|
+
"""LastPass password manager"""
|
|
72
|
+
|
|
73
|
+
OCI = "OCI"
|
|
74
|
+
"""Oracle Cloud Infrastructure"""
|
|
75
|
+
|
|
76
|
+
OKTA = "Okta"
|
|
77
|
+
"""Okta identity and access management"""
|
|
78
|
+
|
|
79
|
+
OPENAI = "OpenAI"
|
|
80
|
+
"""OpenAI"""
|
|
81
|
+
|
|
82
|
+
PAGERDUTY = "PagerDuty"
|
|
83
|
+
"""PagerDuty incident response"""
|
|
84
|
+
|
|
85
|
+
SCALEWAY = "Scaleway"
|
|
86
|
+
"""Scaleway cloud services"""
|
|
87
|
+
|
|
88
|
+
SEMGREP = "Semgrep"
|
|
89
|
+
"""Semgrep code security"""
|
|
90
|
+
|
|
91
|
+
SENTINELONE = "SentinelOne"
|
|
92
|
+
"""SentinelOne endpoint security"""
|
|
93
|
+
|
|
94
|
+
SNIPEIT = "Snipe-IT"
|
|
95
|
+
"""Snipe-IT asset management"""
|
|
96
|
+
|
|
97
|
+
SPACELIFT = "SpaceLift"
|
|
98
|
+
"""SpaceLift infrastructure as code"""
|
|
99
|
+
|
|
100
|
+
TAILSCALE = "TailScale"
|
|
101
|
+
"""TailScale VPN"""
|
|
102
|
+
|
|
103
|
+
TRIVY = "Trivy"
|
|
104
|
+
"""Trivy vulnerability scanner"""
|
|
105
|
+
|
|
106
|
+
CROSS_CLOUD = "Cross-Cloud"
|
|
107
|
+
"""Multi-cloud or provider-agnostic rules"""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Maturity(str, Enum):
|
|
111
|
+
"""Maturity levels for Facts."""
|
|
112
|
+
|
|
113
|
+
EXPERIMENTAL = "EXPERIMENTAL"
|
|
114
|
+
"""Experimental: Initial version, may be unstable or incomplete."""
|
|
115
|
+
|
|
116
|
+
STABLE = "STABLE"
|
|
117
|
+
"""Stable: Well-tested and reliable for production use."""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
MODULE_TO_CARTOGRAPHY_INTEL = {
|
|
121
|
+
Module.AIRBYTE: "airbyte",
|
|
122
|
+
Module.ANTHROPIC: "anthropic",
|
|
123
|
+
Module.AWS: "aws",
|
|
124
|
+
Module.AZURE: "azure",
|
|
125
|
+
Module.BIGFIX: "bigfix",
|
|
126
|
+
Module.CLOUDFLARE: "cloudflare",
|
|
127
|
+
Module.CROWDSTRIKE: "crowdstrike",
|
|
128
|
+
Module.DIGITALOCEAN: "digitalocean",
|
|
129
|
+
Module.DUO: "duo",
|
|
130
|
+
Module.ENTRA: "entra",
|
|
131
|
+
Module.GCP: "gcp",
|
|
132
|
+
Module.GITHUB: "github",
|
|
133
|
+
Module.GOOGLEWORKSPACE: "googleworkspace",
|
|
134
|
+
Module.JAMF: "jamf",
|
|
135
|
+
Module.KANDJI: "kandji",
|
|
136
|
+
Module.KEYCLOAK: "keycloak",
|
|
137
|
+
Module.KUBERNETES: "kubernetes",
|
|
138
|
+
Module.LASTPASS: "lastpass",
|
|
139
|
+
Module.OCI: "oci",
|
|
140
|
+
Module.OKTA: "okta",
|
|
141
|
+
Module.OPENAI: "openai",
|
|
142
|
+
Module.PAGERDUTY: "pagerduty",
|
|
143
|
+
Module.SCALEWAY: "scaleway",
|
|
144
|
+
Module.SEMGREP: "semgrep",
|
|
145
|
+
Module.SENTINELONE: "sentinelone",
|
|
146
|
+
Module.SNIPEIT: "snipeit",
|
|
147
|
+
Module.SPACELIFT: "spacelift",
|
|
148
|
+
Module.TAILSCALE: "tailscale",
|
|
149
|
+
Module.TRIVY: "trivy",
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@dataclass(frozen=True)
|
|
154
|
+
class RuleReference:
|
|
155
|
+
"""A reference document for a Rule."""
|
|
156
|
+
|
|
157
|
+
text: str
|
|
158
|
+
url: str
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass(frozen=True)
|
|
162
|
+
class Fact:
|
|
163
|
+
"""A Fact gathers information about the environment using a Cypher query."""
|
|
164
|
+
|
|
165
|
+
id: str
|
|
166
|
+
"""A descriptive identifier for the Fact. By convention, should be lowercase and use underscores like `rule-name-module`."""
|
|
167
|
+
name: str
|
|
168
|
+
"""A descriptive name for the Fact."""
|
|
169
|
+
description: str
|
|
170
|
+
"""More details about the Fact. Information on details that we're querying for."""
|
|
171
|
+
module: Module
|
|
172
|
+
"""The Module that the Fact is associated with e.g. AWS, Azure, GCP, etc."""
|
|
173
|
+
maturity: Maturity
|
|
174
|
+
"""The maturity level of the Fact query."""
|
|
175
|
+
# TODO can we lint the queries. full-on integ tests here are overkill though.
|
|
176
|
+
cypher_query: str
|
|
177
|
+
"""The Cypher query to gather information about the environment. Returns data field by field e.g. `RETURN node.prop1, node.prop2`."""
|
|
178
|
+
cypher_visual_query: str
|
|
179
|
+
"""
|
|
180
|
+
Same as `cypher_query`, returns it in a visual format for the web interface with `.. RETURN *`.
|
|
181
|
+
Often includes additional relationships to help give context.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class Finding(BaseModel):
|
|
186
|
+
"""Base class for Rule finding models."""
|
|
187
|
+
|
|
188
|
+
# TODO: make this property mandatory one all modules have been updated to new datamodel
|
|
189
|
+
source: str | None = None
|
|
190
|
+
"""The source of the Fact data, e.g. the specific Cartography module that ingested the data. This field is useful especially for CROSS_CLOUD facts."""
|
|
191
|
+
extra: dict[str, Any] = {}
|
|
192
|
+
"""A dictionary to hold any extra fields returned by the Fact query that are not explicitly defined in the output model."""
|
|
193
|
+
|
|
194
|
+
# Config to coerce numbers to strings during instantiation
|
|
195
|
+
model_config = ConfigDict(coerce_numbers_to_str=True)
|
|
196
|
+
|
|
197
|
+
# Coerce o strings
|
|
198
|
+
@no_type_check
|
|
199
|
+
@model_validator(mode="before")
|
|
200
|
+
@classmethod
|
|
201
|
+
def coerce_to_string(cls, data: Any) -> Any:
|
|
202
|
+
if not isinstance(data, dict):
|
|
203
|
+
return data
|
|
204
|
+
|
|
205
|
+
for name, f in cls.model_fields.items():
|
|
206
|
+
if f.annotation is not str:
|
|
207
|
+
continue
|
|
208
|
+
if name not in data:
|
|
209
|
+
continue
|
|
210
|
+
v = data[name]
|
|
211
|
+
if isinstance(v, (list, tuple, set)):
|
|
212
|
+
data[name] = ", ".join(v)
|
|
213
|
+
if isinstance(v, dict):
|
|
214
|
+
data[name] = json.dumps(v)
|
|
215
|
+
|
|
216
|
+
return data
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@dataclass(frozen=True)
|
|
220
|
+
class Rule:
|
|
221
|
+
"""A Rule represents a security issue or misconfiguration detected in the environment."""
|
|
222
|
+
|
|
223
|
+
id: str
|
|
224
|
+
"""A unique identifier for the Rule. Should be globally unique within Cartography."""
|
|
225
|
+
name: str
|
|
226
|
+
"""A brief name for the Rule."""
|
|
227
|
+
tags: tuple[str, ...]
|
|
228
|
+
"""Tags associated with the Rule for categorization and filtering."""
|
|
229
|
+
description: str
|
|
230
|
+
"""A brief description of the Rule. Can include details about the security issue or misconfiguration."""
|
|
231
|
+
version: str
|
|
232
|
+
"""The version of the Rule definition."""
|
|
233
|
+
facts: tuple[Fact, ...]
|
|
234
|
+
"""The Facts that contribute to this Rule."""
|
|
235
|
+
output_model: type[Finding]
|
|
236
|
+
"""The output model class for the Rule."""
|
|
237
|
+
references: list[RuleReference] = field(default_factory=list)
|
|
238
|
+
"""References or links to external resources related to the Rule."""
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def modules(self) -> set[Module]:
|
|
242
|
+
"""Returns the set of modules associated with this rule."""
|
|
243
|
+
return {fact.module for fact in self.facts}
|
|
244
|
+
|
|
245
|
+
def get_fact_by_id(self, fact_id: str) -> Fact | None:
|
|
246
|
+
"""Returns a fact by its ID, or None if not found."""
|
|
247
|
+
for fact in self.facts:
|
|
248
|
+
if fact.id.lower() == fact_id.lower():
|
|
249
|
+
return fact
|
|
250
|
+
return None
|
|
251
|
+
|
|
252
|
+
def parse_results(
|
|
253
|
+
self, fact: Fact, fact_results: list[dict[str, Any]]
|
|
254
|
+
) -> list[Finding]:
|
|
255
|
+
# DOC
|
|
256
|
+
result: list[Finding] = []
|
|
257
|
+
for result_item in fact_results:
|
|
258
|
+
parsed_output: dict[str, Any] = {"extra": {}, "source": fact.module.value}
|
|
259
|
+
for key, value in result_item.items():
|
|
260
|
+
if value is None:
|
|
261
|
+
continue
|
|
262
|
+
if key not in self.output_model.model_fields:
|
|
263
|
+
parsed_output["extra"][key] = value
|
|
264
|
+
else:
|
|
265
|
+
parsed_output[key] = value
|
|
266
|
+
result.append(self.output_model(**parsed_output))
|
|
267
|
+
return result
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Execution result classes
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import field
|
|
4
|
+
|
|
5
|
+
from cartography.rules.spec.model import Finding
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CounterResult:
|
|
10
|
+
current_fact: int = 0
|
|
11
|
+
total_facts: int = 0
|
|
12
|
+
total_findings: int = 0
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class FactResult:
|
|
17
|
+
"""
|
|
18
|
+
Results for a single Fact.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
fact_id: str
|
|
22
|
+
fact_name: str
|
|
23
|
+
fact_description: str
|
|
24
|
+
fact_provider: str
|
|
25
|
+
findings: list[Finding] = field(default_factory=list)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class RuleResult:
|
|
30
|
+
"""
|
|
31
|
+
Results for a single Rule.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
rule_id: str
|
|
35
|
+
rule_name: str
|
|
36
|
+
rule_description: str
|
|
37
|
+
counter: CounterResult
|
|
38
|
+
facts: list[FactResult] = field(default_factory=list)
|
cartography/sync.py
CHANGED
|
@@ -13,6 +13,7 @@ import neo4j.exceptions
|
|
|
13
13
|
from neo4j import GraphDatabase
|
|
14
14
|
from statsd import StatsClient
|
|
15
15
|
|
|
16
|
+
import cartography.intel.airbyte
|
|
16
17
|
import cartography.intel.analysis
|
|
17
18
|
import cartography.intel.anthropic
|
|
18
19
|
import cartography.intel.aws
|
|
@@ -27,16 +28,26 @@ import cartography.intel.duo
|
|
|
27
28
|
import cartography.intel.entra
|
|
28
29
|
import cartography.intel.gcp
|
|
29
30
|
import cartography.intel.github
|
|
31
|
+
import cartography.intel.googleworkspace
|
|
30
32
|
import cartography.intel.gsuite
|
|
33
|
+
import cartography.intel.jamf
|
|
31
34
|
import cartography.intel.kandji
|
|
35
|
+
import cartography.intel.keycloak
|
|
32
36
|
import cartography.intel.kubernetes
|
|
33
37
|
import cartography.intel.lastpass
|
|
34
38
|
import cartography.intel.oci
|
|
35
39
|
import cartography.intel.okta
|
|
40
|
+
import cartography.intel.ontology
|
|
36
41
|
import cartography.intel.openai
|
|
42
|
+
import cartography.intel.pagerduty
|
|
43
|
+
import cartography.intel.scaleway
|
|
37
44
|
import cartography.intel.semgrep
|
|
45
|
+
import cartography.intel.sentinelone
|
|
46
|
+
import cartography.intel.slack
|
|
38
47
|
import cartography.intel.snipeit
|
|
48
|
+
import cartography.intel.spacelift
|
|
39
49
|
import cartography.intel.tailscale
|
|
50
|
+
import cartography.intel.trivy
|
|
40
51
|
from cartography.config import Config
|
|
41
52
|
from cartography.stats import set_stats_client
|
|
42
53
|
from cartography.util import STATUS_FAILURE
|
|
@@ -45,9 +56,10 @@ from cartography.util import STATUS_SUCCESS
|
|
|
45
56
|
logger = logging.getLogger(__name__)
|
|
46
57
|
|
|
47
58
|
|
|
48
|
-
TOP_LEVEL_MODULES = OrderedDict(
|
|
59
|
+
TOP_LEVEL_MODULES: OrderedDict[str, Callable[..., None]] = OrderedDict(
|
|
49
60
|
{ # preserve order so that the default sync always runs `analysis` at the very end
|
|
50
61
|
"create-indexes": cartography.intel.create_indexes.run,
|
|
62
|
+
"airbyte": cartography.intel.airbyte.start_airbyte_ingestion,
|
|
51
63
|
"anthropic": cartography.intel.anthropic.start_anthropic_ingestion,
|
|
52
64
|
"aws": cartography.intel.aws.start_aws_ingestion,
|
|
53
65
|
"azure": cartography.intel.azure.start_azure_ingestion,
|
|
@@ -55,6 +67,7 @@ TOP_LEVEL_MODULES = OrderedDict(
|
|
|
55
67
|
"cloudflare": cartography.intel.cloudflare.start_cloudflare_ingestion,
|
|
56
68
|
"crowdstrike": cartography.intel.crowdstrike.start_crowdstrike_ingestion,
|
|
57
69
|
"gcp": cartography.intel.gcp.start_gcp_ingestion,
|
|
70
|
+
"googleworkspace": cartography.intel.googleworkspace.start_googleworkspace_ingestion,
|
|
58
71
|
"gsuite": cartography.intel.gsuite.start_gsuite_ingestion,
|
|
59
72
|
"cve": cartography.intel.cve.start_cve_ingestion,
|
|
60
73
|
"oci": cartography.intel.oci.start_oci_ingestion,
|
|
@@ -63,13 +76,23 @@ TOP_LEVEL_MODULES = OrderedDict(
|
|
|
63
76
|
"github": cartography.intel.github.start_github_ingestion,
|
|
64
77
|
"digitalocean": cartography.intel.digitalocean.start_digitalocean_ingestion,
|
|
65
78
|
"kandji": cartography.intel.kandji.start_kandji_ingestion,
|
|
79
|
+
"keycloak": cartography.intel.keycloak.start_keycloak_ingestion,
|
|
66
80
|
"kubernetes": cartography.intel.kubernetes.start_k8s_ingestion,
|
|
67
81
|
"lastpass": cartography.intel.lastpass.start_lastpass_ingestion,
|
|
68
82
|
"bigfix": cartography.intel.bigfix.start_bigfix_ingestion,
|
|
69
83
|
"duo": cartography.intel.duo.start_duo_ingestion,
|
|
84
|
+
"scaleway": cartography.intel.scaleway.start_scaleway_ingestion,
|
|
70
85
|
"semgrep": cartography.intel.semgrep.start_semgrep_ingestion,
|
|
71
86
|
"snipeit": cartography.intel.snipeit.start_snipeit_ingestion,
|
|
72
87
|
"tailscale": cartography.intel.tailscale.start_tailscale_ingestion,
|
|
88
|
+
"jamf": cartography.intel.jamf.start_jamf_ingestion,
|
|
89
|
+
"pagerduty": cartography.intel.pagerduty.start_pagerduty_ingestion,
|
|
90
|
+
"trivy": cartography.intel.trivy.start_trivy_ingestion,
|
|
91
|
+
"sentinelone": cartography.intel.sentinelone.start_sentinelone_ingestion,
|
|
92
|
+
"slack": cartography.intel.slack.start_slack_ingestion,
|
|
93
|
+
"spacelift": cartography.intel.spacelift.start_spacelift_ingestion,
|
|
94
|
+
"ontology": cartography.intel.ontology.run,
|
|
95
|
+
# Analysis should be the last stage
|
|
73
96
|
"analysis": cartography.intel.analysis.run,
|
|
74
97
|
}
|
|
75
98
|
)
|
|
@@ -197,14 +220,11 @@ class Sync:
|
|
|
197
220
|
intel_module_info.name,
|
|
198
221
|
)
|
|
199
222
|
available_modules[intel_module_info.name] = v
|
|
223
|
+
available_modules["ontology"] = cartography.intel.ontology.run
|
|
200
224
|
available_modules["analysis"] = cartography.intel.analysis.run
|
|
201
225
|
return available_modules
|
|
202
226
|
|
|
203
227
|
|
|
204
|
-
# Used to avoid repeatedly calling Sync.list_intel_modules()
|
|
205
|
-
TOP_LEVEL_MODULES = Sync.list_intel_modules()
|
|
206
|
-
|
|
207
|
-
|
|
208
228
|
def run_with_config(sync: Sync, config: Union[Config, argparse.Namespace]) -> int:
|
|
209
229
|
"""
|
|
210
230
|
Execute the cartography.sync.Sync.run method with parameters built from the given configuration object.
|