cartography 0.93.0rc1__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/__main__.py +1 -2
- cartography/_version.py +34 -0
- cartography/cli.py +903 -225
- cartography/client/aws/__init__.py +19 -0
- cartography/client/aws/ecr.py +51 -0
- cartography/client/core/tx.py +400 -27
- cartography/config.py +215 -10
- cartography/data/azure_permission_relationships.yaml +20 -0
- cartography/data/gcp_permission_relationships.yaml +21 -0
- cartography/data/indexes.cypher +1 -200
- cartography/data/jobs/analysis/aws_ec2_asset_exposure.json +17 -2
- cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +2 -2
- cartography/data/jobs/analysis/gcp_compute_asset_inet_exposure.json +1 -1
- cartography/data/jobs/analysis/keycloak_inheritance.json +30 -0
- cartography/data/jobs/cleanup/crowdstrike_import_cleanup.json +0 -5
- cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
- cartography/data/jobs/cleanup/github_repos_cleanup.json +27 -0
- cartography/data/jobs/scoped_analysis/aws_ec2_iaminstanceprofile.json +15 -0
- cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json +13 -13
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +72 -75
- cartography/driftdetect/detect_deviations.py +7 -3
- cartography/driftdetect/get_states.py +20 -8
- cartography/driftdetect/model.py +5 -5
- cartography/driftdetect/serializers.py +8 -6
- cartography/driftdetect/storage.py +2 -2
- cartography/graph/cleanupbuilder.py +255 -35
- cartography/graph/job.py +104 -20
- cartography/graph/querybuilder.py +689 -91
- cartography/graph/statement.py +49 -36
- 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/analysis.py +4 -1
- cartography/intel/anthropic/__init__.py +62 -0
- cartography/intel/anthropic/apikeys.py +72 -0
- cartography/intel/anthropic/users.py +75 -0
- cartography/intel/anthropic/util.py +51 -0
- cartography/intel/anthropic/workspaces.py +95 -0
- cartography/intel/aws/__init__.py +137 -59
- cartography/intel/aws/acm.py +124 -0
- cartography/intel/aws/apigateway.py +482 -217
- cartography/intel/aws/apigatewayv2.py +116 -0
- cartography/intel/aws/cloudtrail.py +105 -0
- cartography/intel/aws/cloudtrail_management_events.py +962 -0
- cartography/intel/aws/cloudwatch.py +239 -0
- cartography/intel/aws/codebuild.py +132 -0
- cartography/intel/aws/cognito.py +201 -0
- cartography/intel/aws/config.py +63 -23
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +254 -189
- cartography/intel/aws/ec2/elastic_ip_addresses.py +44 -14
- cartography/intel/aws/ec2/images.py +74 -39
- cartography/intel/aws/ec2/instances.py +262 -137
- cartography/intel/aws/ec2/internet_gateways.py +44 -13
- cartography/intel/aws/ec2/key_pairs.py +72 -39
- cartography/intel/aws/ec2/launch_templates.py +143 -66
- cartography/intel/aws/ec2/load_balancer_v2s.py +119 -45
- cartography/intel/aws/ec2/load_balancers.py +165 -147
- cartography/intel/aws/ec2/network_acls.py +233 -0
- cartography/intel/aws/ec2/network_interfaces.py +150 -87
- cartography/intel/aws/ec2/reserved_instances.py +48 -17
- cartography/intel/aws/ec2/route_tables.py +327 -0
- cartography/intel/aws/ec2/security_groups.py +189 -121
- cartography/intel/aws/ec2/snapshots.py +93 -91
- cartography/intel/aws/ec2/subnets.py +70 -58
- cartography/intel/aws/ec2/tgw.py +111 -39
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +157 -116
- cartography/intel/aws/ec2/vpc_peerings.py +317 -121
- cartography/intel/aws/ecr.py +336 -93
- cartography/intel/aws/ecr_image_layers.py +923 -0
- cartography/intel/aws/ecs.py +310 -403
- cartography/intel/aws/efs.py +261 -0
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +130 -83
- cartography/intel/aws/elasticsearch.py +70 -24
- cartography/intel/aws/emr.py +61 -23
- 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 +978 -464
- cartography/intel/aws/iam_instance_profiles.py +73 -0
- cartography/intel/aws/identitycenter.py +847 -0
- cartography/intel/aws/inspector.py +330 -133
- cartography/intel/aws/kms.py +235 -209
- cartography/intel/aws/lambda_function.py +328 -176
- cartography/intel/aws/organizations.py +40 -19
- cartography/intel/aws/permission_relationships.py +144 -68
- cartography/intel/aws/rds.py +467 -412
- cartography/intel/aws/redshift.py +116 -50
- cartography/intel/aws/resourcegroupstaggingapi.py +198 -82
- cartography/intel/aws/resources.py +80 -42
- cartography/intel/aws/route53.py +419 -318
- cartography/intel/aws/s3.py +489 -96
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +217 -40
- cartography/intel/aws/securityhub.py +23 -10
- cartography/intel/aws/sns.py +226 -0
- cartography/intel/aws/sqs.py +74 -96
- cartography/intel/aws/ssm.py +142 -33
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +259 -46
- cartography/intel/azure/aks.py +175 -0
- cartography/intel/azure/app_service.py +105 -0
- cartography/intel/azure/compute.py +141 -120
- cartography/intel/azure/container_instances.py +95 -0
- cartography/intel/azure/cosmosdb.py +706 -519
- 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 +436 -392
- cartography/intel/azure/storage.py +467 -335
- cartography/intel/azure/subscription.py +49 -55
- cartography/intel/azure/tenant.py +46 -28
- cartography/intel/azure/util/common.py +13 -0
- cartography/intel/azure/util/credentials.py +58 -143
- cartography/intel/azure/util/tag.py +41 -0
- cartography/intel/bigfix/__init__.py +2 -2
- cartography/intel/bigfix/computers.py +93 -65
- cartography/intel/cloudflare/__init__.py +74 -0
- cartography/intel/cloudflare/accounts.py +57 -0
- cartography/intel/cloudflare/dnsrecords.py +64 -0
- cartography/intel/cloudflare/members.py +75 -0
- cartography/intel/cloudflare/roles.py +65 -0
- cartography/intel/cloudflare/zones.py +64 -0
- cartography/intel/create_indexes.py +5 -3
- cartography/intel/crowdstrike/__init__.py +26 -12
- cartography/intel/crowdstrike/endpoints.py +17 -45
- cartography/intel/crowdstrike/spotlight.py +13 -5
- cartography/intel/cve/__init__.py +91 -26
- cartography/intel/cve/feed.py +77 -56
- cartography/intel/digitalocean/__init__.py +22 -13
- cartography/intel/digitalocean/compute.py +75 -108
- cartography/intel/digitalocean/management.py +44 -80
- cartography/intel/digitalocean/platform.py +48 -43
- cartography/intel/dns.py +41 -12
- cartography/intel/duo/__init__.py +21 -16
- cartography/intel/duo/api_host.py +14 -9
- cartography/intel/duo/endpoints.py +50 -45
- cartography/intel/duo/groups.py +18 -14
- cartography/intel/duo/phones.py +37 -34
- cartography/intel/duo/tokens.py +26 -23
- cartography/intel/duo/users.py +54 -50
- cartography/intel/duo/web_authn_credentials.py +30 -25
- cartography/intel/entra/__init__.py +160 -0
- 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 +136 -0
- cartography/intel/entra/service_principals.py +217 -0
- cartography/intel/entra/users.py +259 -0
- cartography/intel/gcp/__init__.py +381 -175
- 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 +521 -325
- 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 +134 -179
- cartography/intel/gcp/gke.py +100 -107
- cartography/intel/gcp/iam.py +262 -0
- cartography/intel/gcp/permission_relationships.py +394 -0
- cartography/intel/gcp/policy_bindings.py +225 -0
- cartography/intel/gcp/storage.py +103 -158
- cartography/intel/github/__init__.py +66 -27
- cartography/intel/github/commits.py +423 -0
- cartography/intel/github/repos.py +871 -160
- cartography/intel/github/teams.py +386 -53
- cartography/intel/github/users.py +214 -49
- cartography/intel/github/util.py +50 -35
- 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 +101 -42
- cartography/intel/gsuite/groups.py +291 -0
- cartography/intel/gsuite/users.py +142 -0
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +37 -8
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +40 -10
- 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 +60 -55
- cartography/intel/kubernetes/pods.py +171 -75
- cartography/intel/kubernetes/rbac.py +597 -0
- cartography/intel/kubernetes/secrets.py +95 -45
- cartography/intel/kubernetes/services.py +131 -63
- cartography/intel/kubernetes/util.py +142 -14
- cartography/intel/lastpass/__init__.py +2 -2
- cartography/intel/lastpass/users.py +23 -12
- cartography/intel/oci/__init__.py +44 -11
- cartography/intel/oci/iam.py +157 -47
- cartography/intel/oci/organizations.py +16 -7
- cartography/intel/oci/utils.py +71 -25
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +57 -25
- cartography/intel/okta/awssaml.py +105 -41
- cartography/intel/okta/factors.py +19 -5
- cartography/intel/okta/groups.py +61 -31
- cartography/intel/okta/organization.py +8 -2
- cartography/intel/okta/origins.py +9 -3
- cartography/intel/okta/roles.py +20 -7
- cartography/intel/okta/users.py +31 -10
- cartography/intel/okta/utils.py +6 -4
- 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/openai/__init__.py +86 -0
- cartography/intel/openai/adminapikeys.py +89 -0
- cartography/intel/openai/apikeys.py +96 -0
- cartography/intel/openai/projects.py +97 -0
- cartography/intel/openai/serviceaccounts.py +82 -0
- cartography/intel/openai/users.py +75 -0
- cartography/intel/openai/util.py +45 -0
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +31 -12
- cartography/intel/pagerduty/schedules.py +21 -8
- cartography/intel/pagerduty/services.py +18 -7
- cartography/intel/pagerduty/teams.py +13 -5
- cartography/intel/pagerduty/users.py +6 -2
- cartography/intel/pagerduty/vendors.py +6 -2
- 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/semgrep/__init__.py +30 -5
- cartography/intel/semgrep/dependencies.py +255 -0
- cartography/intel/semgrep/deployment.py +69 -0
- cartography/intel/semgrep/findings.py +157 -117
- 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/snipeit/__init__.py +44 -0
- cartography/intel/snipeit/asset.py +80 -0
- cartography/intel/snipeit/user.py +78 -0
- cartography/intel/snipeit/util.py +40 -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/tailscale/__init__.py +77 -0
- cartography/intel/tailscale/acls.py +146 -0
- cartography/intel/tailscale/devices.py +127 -0
- cartography/intel/tailscale/postureintegrations.py +81 -0
- cartography/intel/tailscale/tailnets.py +76 -0
- cartography/intel/tailscale/users.py +80 -0
- cartography/intel/tailscale/utils.py +132 -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/__init__.py +0 -0
- cartography/models/anthropic/apikey.py +94 -0
- cartography/models/anthropic/organization.py +19 -0
- cartography/models/anthropic/user.py +52 -0
- cartography/models/anthropic/workspace.py +90 -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/apigateway.py +51 -0
- cartography/models/aws/apigateway/apigatewaycertificate.py +72 -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/apigateway/apigatewayresource.py +70 -0
- cartography/models/aws/apigateway/apigatewaystage.py +75 -0
- cartography/models/aws/apigatewayv2/__init__.py +0 -0
- cartography/models/aws/apigatewayv2/apigatewayv2.py +53 -0
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/management_events.py +153 -0
- cartography/models/aws/cloudtrail/trail.py +106 -0
- cartography/models/aws/cloudwatch/__init__.py +0 -0
- cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
- cartography/models/aws/cloudwatch/loggroup.py +52 -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/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +27 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +224 -0
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +85 -38
- cartography/models/aws/ec2/keypair.py +59 -0
- cartography/models/aws/ec2/keypair_instance.py +76 -0
- cartography/models/aws/ec2/launch_configurations.py +59 -0
- cartography/models/aws/ec2/launch_template_versions.py +48 -38
- cartography/models/aws/ec2/launch_templates.py +21 -17
- cartography/models/aws/ec2/load_balancer_listeners.py +72 -0
- cartography/models/aws/ec2/load_balancers.py +112 -0
- cartography/models/aws/ec2/network_acl_rules.py +106 -0
- cartography/models/aws/ec2/network_acls.py +95 -0
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +57 -37
- cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
- cartography/models/aws/ec2/reservations.py +18 -14
- cartography/models/aws/ec2/route_table_associations.py +97 -0
- cartography/models/aws/ec2/route_tables.py +128 -0
- cartography/models/aws/ec2/routes.py +85 -0
- cartography/models/aws/ec2/security_group_rules.py +109 -0
- cartography/models/aws/ec2/security_groups.py +90 -0
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/snapshots.py +58 -0
- cartography/models/aws/ec2/subnet_instance.py +26 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +42 -31
- cartography/models/aws/ec2/subnets.py +65 -0
- cartography/models/aws/ec2/volumes.py +67 -40
- 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/__init__.py +0 -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 +79 -0
- cartography/models/aws/eks/clusters.py +23 -21
- 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/emr.py +32 -30
- 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/__init__.py +0 -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/instanceprofile.py +76 -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/__init__.py +0 -0
- cartography/models/aws/identitycenter/awsidentitycenter.py +49 -0
- cartography/models/aws/identitycenter/awspermissionset.py +162 -0
- cartography/models/aws/identitycenter/awssogroup.py +70 -0
- cartography/models/aws/identitycenter/awsssouser.py +110 -0
- cartography/models/aws/inspector/findings.py +124 -58
- cartography/models/aws/inspector/packages.py +18 -42
- 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/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/s3/notification.py +24 -0
- cartography/models/aws/secretsmanager/__init__.py +0 -0
- cartography/models/aws/secretsmanager/secret.py +106 -0
- cartography/models/aws/secretsmanager/secret_version.py +114 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- 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/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- cartography/models/aws/ssm/parameters.py +84 -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 +42 -38
- cartography/models/bigfix/bigfix_root.py +3 -3
- cartography/models/cloudflare/__init__.py +0 -0
- cartography/models/cloudflare/account.py +25 -0
- cartography/models/cloudflare/dnsrecord.py +55 -0
- cartography/models/cloudflare/member.py +86 -0
- cartography/models/cloudflare/role.py +44 -0
- cartography/models/cloudflare/zone.py +59 -0
- cartography/models/core/common.py +53 -2
- cartography/models/core/nodes.py +20 -4
- cartography/models/core/relationships.py +58 -6
- cartography/models/crowdstrike/__init__.py +0 -0
- cartography/models/crowdstrike/hosts.py +51 -0
- cartography/models/cve/cve.py +34 -32
- cartography/models/cve/cve_feed.py +6 -6
- cartography/models/digitalocean/__init__.py +0 -0
- cartography/models/digitalocean/account.py +21 -0
- cartography/models/digitalocean/droplet.py +58 -0
- cartography/models/digitalocean/project.py +48 -0
- cartography/models/duo/api_host.py +3 -3
- cartography/models/duo/endpoint.py +43 -41
- cartography/models/duo/group.py +14 -14
- cartography/models/duo/phone.py +27 -27
- cartography/models/duo/token.py +16 -16
- cartography/models/duo/user.py +50 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/__init__.py +0 -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/ou.py +48 -0
- cartography/models/entra/service_principal.py +104 -0
- cartography/models/entra/tenant.py +39 -0
- cartography/models/entra/user.py +90 -0
- 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 +73 -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/orgs.py +27 -0
- cartography/models/github/teams.py +74 -22
- cartography/models/github/users.py +149 -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 +22 -17
- cartography/models/kandji/tenant.py +6 -4
- 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/tenant.py +3 -3
- cartography/models/lastpass/user.py +36 -28
- 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/__init__.py +0 -0
- cartography/models/openai/adminapikey.py +94 -0
- cartography/models/openai/apikey.py +88 -0
- cartography/models/openai/organization.py +17 -0
- cartography/models/openai/project.py +89 -0
- cartography/models/openai/serviceaccount.py +50 -0
- cartography/models/openai/user.py +53 -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/semgrep/dependencies.py +102 -0
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -40
- cartography/models/semgrep/locations.py +27 -21
- 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/__init__.py +0 -0
- cartography/models/snipeit/asset.py +92 -0
- cartography/models/snipeit/tenant.py +19 -0
- cartography/models/snipeit/user.py +60 -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/__init__.py +0 -0
- cartography/models/tailscale/device.py +96 -0
- cartography/models/tailscale/group.py +86 -0
- cartography/models/tailscale/postureintegration.py +58 -0
- cartography/models/tailscale/tag.py +102 -0
- cartography/models/tailscale/tailnet.py +29 -0
- cartography/models/tailscale/user.py +57 -0
- 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/stats.py +4 -4
- cartography/sync.py +137 -31
- cartography/util.py +187 -77
- cartography-0.123.0.dist-info/METADATA +230 -0
- cartography-0.123.0.dist-info/RECORD +856 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/WHEEL +1 -1
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/entry_points.txt +1 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info/licenses}/LICENSE +1 -1
- cartography/data/jobs/analysis/aws_ec2_iaminstance.json +0 -10
- cartography/data/jobs/analysis/aws_ec2_iaminstanceprofile.json +0 -10
- cartography/data/jobs/cleanup/aws_apigateway_details.json +0 -10
- 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_apigateway_cleanup.json +0 -45
- 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_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/crxcavator_import_cleanup.json +0 -18
- 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/github_users_cleanup.json +0 -23
- 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/crxcavator/__init__.py +0 -44
- cartography/intel/crxcavator/crxcavator.py +0 -329
- cartography/intel/gcp/crm.py +0 -302
- cartography/intel/gsuite/api.py +0 -284
- cartography/models/aws/ec2/keypairs.py +0 -64
- cartography-0.93.0rc1.dist-info/METADATA +0 -55
- cartography-0.93.0rc1.dist-info/NOTICE +0 -4
- cartography-0.93.0rc1.dist-info/RECORD +0 -341
- /cartography/data/jobs/{analysis → scoped_analysis}/aws_s3acl_analysis.json +0 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,962 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from typing import Any
|
|
6
|
+
from typing import Dict
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
import boto3
|
|
10
|
+
import neo4j
|
|
11
|
+
|
|
12
|
+
from cartography.client.core.tx import load_matchlinks
|
|
13
|
+
from cartography.graph.job import GraphJob
|
|
14
|
+
from cartography.intel.aws.ec2.util import get_botocore_config
|
|
15
|
+
from cartography.models.aws.cloudtrail.management_events import AssumedRoleMatchLink
|
|
16
|
+
from cartography.models.aws.cloudtrail.management_events import (
|
|
17
|
+
AssumedRoleWithSAMLMatchLink,
|
|
18
|
+
)
|
|
19
|
+
from cartography.models.aws.cloudtrail.management_events import (
|
|
20
|
+
GitHubRepoAssumeRoleWithWebIdentityMatchLink,
|
|
21
|
+
)
|
|
22
|
+
from cartography.util import aws_handle_regions
|
|
23
|
+
from cartography.util import timeit
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@timeit
|
|
29
|
+
@aws_handle_regions
|
|
30
|
+
def get_assume_role_events(
|
|
31
|
+
boto3_session: boto3.Session, region: str, lookback_hours: int
|
|
32
|
+
) -> List[Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
Fetch CloudTrail AssumeRole events from the specified time period.
|
|
35
|
+
|
|
36
|
+
Focuses specifically on standard AssumeRole events, excluding SAML and WebIdentity variants.
|
|
37
|
+
|
|
38
|
+
:type boto3_session: boto3.Session
|
|
39
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
40
|
+
:type region: str
|
|
41
|
+
:param region: The AWS region to fetch events from
|
|
42
|
+
:type lookback_hours: int
|
|
43
|
+
:param lookback_hours: Number of hours back to retrieve events from
|
|
44
|
+
:rtype: List[Dict[str, Any]]
|
|
45
|
+
:return: List of CloudTrail AssumeRole events
|
|
46
|
+
"""
|
|
47
|
+
client = boto3_session.client(
|
|
48
|
+
"cloudtrail", region_name=region, config=get_botocore_config()
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Calculate time range
|
|
52
|
+
end_time = datetime.utcnow()
|
|
53
|
+
start_time = end_time - timedelta(hours=lookback_hours)
|
|
54
|
+
|
|
55
|
+
logger.info(
|
|
56
|
+
f"Fetching CloudTrail AssumeRole events for region '{region}' "
|
|
57
|
+
f"from {start_time} to {end_time} ({lookback_hours} hours)"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
paginator = client.get_paginator("lookup_events")
|
|
61
|
+
|
|
62
|
+
page_iterator = paginator.paginate(
|
|
63
|
+
LookupAttributes=[
|
|
64
|
+
{"AttributeKey": "EventName", "AttributeValue": "AssumeRole"}
|
|
65
|
+
],
|
|
66
|
+
StartTime=start_time,
|
|
67
|
+
EndTime=end_time,
|
|
68
|
+
PaginationConfig={
|
|
69
|
+
"MaxItems": 10000, # Reasonable limit to prevent excessive API calls
|
|
70
|
+
"PageSize": 50, # CloudTrail API limit per page
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
all_events = []
|
|
75
|
+
for page in page_iterator:
|
|
76
|
+
all_events.extend(page.get("Events", []))
|
|
77
|
+
|
|
78
|
+
logger.info(f"Retrieved {len(all_events)} AssumeRole events from region '{region}'")
|
|
79
|
+
|
|
80
|
+
return all_events
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@timeit
|
|
84
|
+
@aws_handle_regions
|
|
85
|
+
def get_saml_role_events(
|
|
86
|
+
boto3_session: boto3.Session, region: str, lookback_hours: int
|
|
87
|
+
) -> List[Dict[str, Any]]:
|
|
88
|
+
"""
|
|
89
|
+
Fetch CloudTrail AssumeRoleWithSAML events from the specified time period.
|
|
90
|
+
|
|
91
|
+
Focuses specifically on SAML-based role assumption events.
|
|
92
|
+
|
|
93
|
+
:type boto3_session: boto3.Session
|
|
94
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
95
|
+
:type region: str
|
|
96
|
+
:param region: The AWS region to fetch events from
|
|
97
|
+
:type lookback_hours: int
|
|
98
|
+
:param lookback_hours: Number of hours back to retrieve events from
|
|
99
|
+
:rtype: List[Dict[str, Any]]
|
|
100
|
+
:return: List of CloudTrail AssumeRoleWithSAML events
|
|
101
|
+
"""
|
|
102
|
+
client = boto3_session.client(
|
|
103
|
+
"cloudtrail", region_name=region, config=get_botocore_config()
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Calculate time range
|
|
107
|
+
end_time = datetime.utcnow()
|
|
108
|
+
start_time = end_time - timedelta(hours=lookback_hours)
|
|
109
|
+
|
|
110
|
+
logger.info(
|
|
111
|
+
f"Fetching CloudTrail AssumeRoleWithSAML events for region '{region}' "
|
|
112
|
+
f"from {start_time} to {end_time} ({lookback_hours} hours)"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
paginator = client.get_paginator("lookup_events")
|
|
116
|
+
|
|
117
|
+
page_iterator = paginator.paginate(
|
|
118
|
+
LookupAttributes=[
|
|
119
|
+
{"AttributeKey": "EventName", "AttributeValue": "AssumeRoleWithSAML"}
|
|
120
|
+
],
|
|
121
|
+
StartTime=start_time,
|
|
122
|
+
EndTime=end_time,
|
|
123
|
+
PaginationConfig={
|
|
124
|
+
"MaxItems": 10000, # Reasonable limit to prevent excessive API calls
|
|
125
|
+
"PageSize": 50, # CloudTrail API limit per page
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
all_events = []
|
|
130
|
+
for page in page_iterator:
|
|
131
|
+
all_events.extend(page.get("Events", []))
|
|
132
|
+
|
|
133
|
+
logger.info(
|
|
134
|
+
f"Retrieved {len(all_events)} AssumeRoleWithSAML events from region '{region}'"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return all_events
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@timeit
|
|
141
|
+
@aws_handle_regions
|
|
142
|
+
def get_web_identity_role_events(
|
|
143
|
+
boto3_session: boto3.Session, region: str, lookback_hours: int
|
|
144
|
+
) -> List[Dict[str, Any]]:
|
|
145
|
+
"""
|
|
146
|
+
Fetch CloudTrail AssumeRoleWithWebIdentity events from the specified time period.
|
|
147
|
+
|
|
148
|
+
Focuses specifically on WebIdentity-based role assumption events.
|
|
149
|
+
|
|
150
|
+
:type boto3_session: boto3.Session
|
|
151
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
152
|
+
:type region: str
|
|
153
|
+
:param region: The AWS region to fetch events from
|
|
154
|
+
:type lookback_hours: int
|
|
155
|
+
:param lookback_hours: Number of hours back to retrieve events from
|
|
156
|
+
:rtype: List[Dict[str, Any]]
|
|
157
|
+
:return: List of CloudTrail AssumeRoleWithWebIdentity events
|
|
158
|
+
"""
|
|
159
|
+
client = boto3_session.client(
|
|
160
|
+
"cloudtrail", region_name=region, config=get_botocore_config()
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Calculate time range
|
|
164
|
+
end_time = datetime.utcnow()
|
|
165
|
+
start_time = end_time - timedelta(hours=lookback_hours)
|
|
166
|
+
|
|
167
|
+
logger.info(
|
|
168
|
+
f"Fetching CloudTrail AssumeRoleWithWebIdentity events for region '{region}' "
|
|
169
|
+
f"from {start_time} to {end_time} ({lookback_hours} hours)"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
paginator = client.get_paginator("lookup_events")
|
|
173
|
+
|
|
174
|
+
page_iterator = paginator.paginate(
|
|
175
|
+
LookupAttributes=[
|
|
176
|
+
{"AttributeKey": "EventName", "AttributeValue": "AssumeRoleWithWebIdentity"}
|
|
177
|
+
],
|
|
178
|
+
StartTime=start_time,
|
|
179
|
+
EndTime=end_time,
|
|
180
|
+
PaginationConfig={
|
|
181
|
+
"MaxItems": 10000, # Reasonable limit to prevent excessive API calls
|
|
182
|
+
"PageSize": 50, # CloudTrail API limit per page
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
all_events = []
|
|
187
|
+
for page in page_iterator:
|
|
188
|
+
all_events.extend(page.get("Events", []))
|
|
189
|
+
|
|
190
|
+
logger.info(
|
|
191
|
+
f"Retrieved {len(all_events)} AssumeRoleWithWebIdentity events from region '{region}'"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return all_events
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@timeit
|
|
198
|
+
def transform_assume_role_events_to_role_assumptions(
|
|
199
|
+
events: List[Dict[str, Any]],
|
|
200
|
+
) -> List[Dict[str, Any]]:
|
|
201
|
+
"""
|
|
202
|
+
Transform raw CloudTrail AssumeRole events into aggregated role assumption relationships.
|
|
203
|
+
|
|
204
|
+
Focuses specifically on standard AssumeRole events, providing optimized processing
|
|
205
|
+
for the most common role assumption scenario.
|
|
206
|
+
|
|
207
|
+
This function performs the complete transformation pipeline:
|
|
208
|
+
1. Extract role assumption events from CloudTrail AssumeRole data
|
|
209
|
+
2. Aggregate events by (source_principal, destination_principal) pairs
|
|
210
|
+
3. Return aggregated relationships ready for loading
|
|
211
|
+
|
|
212
|
+
:type events: List[Dict[str, Any]]
|
|
213
|
+
:param events: List of raw CloudTrail AssumeRole events from lookup_events API
|
|
214
|
+
:rtype: List[Dict[str, Any]]
|
|
215
|
+
:return: List of aggregated role assumption relationships ready for loading
|
|
216
|
+
"""
|
|
217
|
+
aggregated: Dict[tuple, Dict[str, Any]] = {}
|
|
218
|
+
logger.info(
|
|
219
|
+
f"Transforming {len(events)} CloudTrail AssumeRole events to role assumptions"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
for event in events:
|
|
223
|
+
|
|
224
|
+
cloudtrail_event = json.loads(event["CloudTrailEvent"])
|
|
225
|
+
|
|
226
|
+
# Skip events with null requestParameters since we can't extract roleArn
|
|
227
|
+
if not cloudtrail_event.get("requestParameters"):
|
|
228
|
+
logger.debug(
|
|
229
|
+
f"Skipping CloudTrail AssumeRole event due to missing requestParameters. Event: {event.get('EventId', 'unknown')}"
|
|
230
|
+
)
|
|
231
|
+
continue
|
|
232
|
+
|
|
233
|
+
if cloudtrail_event.get("userIdentity", {}).get("arn"):
|
|
234
|
+
source_principal = cloudtrail_event["userIdentity"]["arn"]
|
|
235
|
+
destination_principal = cloudtrail_event["requestParameters"]["roleArn"]
|
|
236
|
+
else:
|
|
237
|
+
logger.debug(
|
|
238
|
+
f"Skipping CloudTrail AssumeRole event due to missing UserIdentity.arn. Event: {event.get('EventId', 'unknown')}"
|
|
239
|
+
)
|
|
240
|
+
continue
|
|
241
|
+
|
|
242
|
+
destination_principal = cloudtrail_event["requestParameters"]["roleArn"]
|
|
243
|
+
|
|
244
|
+
normalized_source_principal = _convert_assumed_role_arn_to_role_arn(
|
|
245
|
+
source_principal
|
|
246
|
+
)
|
|
247
|
+
normalized_destination_principal = _convert_assumed_role_arn_to_role_arn(
|
|
248
|
+
destination_principal
|
|
249
|
+
)
|
|
250
|
+
event_time = event.get("EventTime")
|
|
251
|
+
|
|
252
|
+
key = (normalized_source_principal, normalized_destination_principal)
|
|
253
|
+
|
|
254
|
+
if key in aggregated:
|
|
255
|
+
aggregated[key]["times_used"] += 1
|
|
256
|
+
# Handle None values safely for time comparisons
|
|
257
|
+
if event_time:
|
|
258
|
+
existing_first = aggregated[key]["first_seen_in_time_window"]
|
|
259
|
+
existing_last = aggregated[key]["last_used"]
|
|
260
|
+
|
|
261
|
+
if existing_first is None or event_time < existing_first:
|
|
262
|
+
aggregated[key]["first_seen_in_time_window"] = event_time
|
|
263
|
+
if existing_last is None or event_time > existing_last:
|
|
264
|
+
aggregated[key]["last_used"] = event_time
|
|
265
|
+
else:
|
|
266
|
+
aggregated[key] = {
|
|
267
|
+
"source_principal_arn": normalized_source_principal,
|
|
268
|
+
"destination_principal_arn": normalized_destination_principal,
|
|
269
|
+
"times_used": 1,
|
|
270
|
+
"first_seen_in_time_window": event_time,
|
|
271
|
+
"last_used": event_time,
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return list(aggregated.values())
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
@timeit
|
|
278
|
+
def transform_saml_role_events_to_role_assumptions(
|
|
279
|
+
events: List[Dict[str, Any]],
|
|
280
|
+
) -> List[Dict[str, Any]]:
|
|
281
|
+
"""
|
|
282
|
+
Transform raw CloudTrail AssumeRoleWithSAML events into aggregated role assumption relationships.
|
|
283
|
+
|
|
284
|
+
Focuses specifically on SAML-based role assumption events, providing optimized processing
|
|
285
|
+
for federated identity scenarios.
|
|
286
|
+
|
|
287
|
+
This function performs the complete transformation pipeline:
|
|
288
|
+
1. Extract role assumption events from CloudTrail AssumeRoleWithSAML data
|
|
289
|
+
2. Aggregate events by (source_principal, destination_principal) pairs
|
|
290
|
+
3. Return aggregated relationships ready for loading
|
|
291
|
+
|
|
292
|
+
:type events: List[Dict[str, Any]]
|
|
293
|
+
:param events: List of raw CloudTrail AssumeRoleWithSAML events from lookup_events API
|
|
294
|
+
:rtype: List[Dict[str, Any]]
|
|
295
|
+
:return: List of aggregated SAML role assumption relationships ready for loading.
|
|
296
|
+
Each dict contains keys: source_principal_arn, destination_principal_arn,
|
|
297
|
+
times_used, first_seen_in_time_window, last_used
|
|
298
|
+
"""
|
|
299
|
+
aggregated: Dict[tuple, Dict[str, Any]] = {}
|
|
300
|
+
logger.info(
|
|
301
|
+
f"Transforming {len(events)} CloudTrail AssumeRoleWithSAML events to role assumptions"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
for event in events:
|
|
305
|
+
|
|
306
|
+
cloudtrail_event = json.loads(event["CloudTrailEvent"])
|
|
307
|
+
|
|
308
|
+
# Skip events with null requestParameters since we can't extract roleArn
|
|
309
|
+
if not cloudtrail_event.get("requestParameters"):
|
|
310
|
+
logger.debug(
|
|
311
|
+
f"Skipping CloudTrail AssumeRoleWithSAML event due to missing requestParameters. Event: {event.get('EventId', 'unknown')}"
|
|
312
|
+
)
|
|
313
|
+
continue
|
|
314
|
+
|
|
315
|
+
response_elements = cloudtrail_event.get("responseElements", {})
|
|
316
|
+
assumed_role_user = response_elements.get("assumedRoleUser", {})
|
|
317
|
+
|
|
318
|
+
if assumed_role_user.get("arn"):
|
|
319
|
+
assumed_role_arn = assumed_role_user["arn"]
|
|
320
|
+
# Extract username from assumed role ARN: arn:aws:sts::account:assumed-role/RoleName/username
|
|
321
|
+
source_principal = assumed_role_arn.split("/")[-1]
|
|
322
|
+
destination_principal = cloudtrail_event["requestParameters"]["roleArn"]
|
|
323
|
+
else:
|
|
324
|
+
logger.debug(
|
|
325
|
+
f"Skipping CloudTrail AssumeRoleWithSAML event due to missing assumedRoleUser.arn. Event: {event.get('EventId', 'unknown')}"
|
|
326
|
+
)
|
|
327
|
+
continue
|
|
328
|
+
|
|
329
|
+
event_time = event.get("EventTime")
|
|
330
|
+
|
|
331
|
+
key = (source_principal, destination_principal)
|
|
332
|
+
|
|
333
|
+
if key in aggregated:
|
|
334
|
+
aggregated[key]["times_used"] += 1
|
|
335
|
+
# Handle None values safely for time comparisons
|
|
336
|
+
if event_time:
|
|
337
|
+
existing_first = aggregated[key]["first_seen_in_time_window"]
|
|
338
|
+
existing_last = aggregated[key]["last_used"]
|
|
339
|
+
|
|
340
|
+
if existing_first is None or event_time < existing_first:
|
|
341
|
+
aggregated[key]["first_seen_in_time_window"] = event_time
|
|
342
|
+
if existing_last is None or event_time > existing_last:
|
|
343
|
+
aggregated[key]["last_used"] = event_time
|
|
344
|
+
else:
|
|
345
|
+
aggregated[key] = {
|
|
346
|
+
"source_principal_arn": source_principal,
|
|
347
|
+
"destination_principal_arn": destination_principal,
|
|
348
|
+
"times_used": 1,
|
|
349
|
+
"first_seen_in_time_window": event_time,
|
|
350
|
+
"last_used": event_time,
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return list(aggregated.values())
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@timeit
|
|
357
|
+
def transform_web_identity_role_events_to_role_assumptions(
|
|
358
|
+
events: List[Dict[str, Any]],
|
|
359
|
+
) -> List[Dict[str, Any]]:
|
|
360
|
+
"""
|
|
361
|
+
Transform raw CloudTrail AssumeRoleWithWebIdentity events into aggregated role assumption relationships.
|
|
362
|
+
|
|
363
|
+
Focuses specifically on WebIdentity-based role assumption events, providing optimized processing
|
|
364
|
+
for federated web identity scenarios.
|
|
365
|
+
|
|
366
|
+
This function performs the complete transformation pipeline:
|
|
367
|
+
1. Extract role assumption events from CloudTrail AssumeRoleWithWebIdentity data
|
|
368
|
+
2. Aggregate events by (source_principal, destination_principal) pairs
|
|
369
|
+
3. Return aggregated relationships ready for loading
|
|
370
|
+
|
|
371
|
+
:type events: List[Dict[str, Any]]
|
|
372
|
+
:param events: List of raw CloudTrail AssumeRoleWithWebIdentity events from lookup_events API
|
|
373
|
+
:rtype: List[Dict[str, Any]]
|
|
374
|
+
:return: List of aggregated WebIdentity role assumption relationships ready for loading.
|
|
375
|
+
Each dict contains keys: source_repo_fullname, destination_principal_arn,
|
|
376
|
+
times_used, first_seen_in_time_window, last_used
|
|
377
|
+
"""
|
|
378
|
+
github_aggregated: Dict[tuple, Dict[str, Any]] = {}
|
|
379
|
+
logger.info(
|
|
380
|
+
f"Transforming {len(events)} CloudTrail AssumeRoleWithWebIdentity events to role assumptions"
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
for event in events:
|
|
384
|
+
|
|
385
|
+
cloudtrail_event = json.loads(event["CloudTrailEvent"])
|
|
386
|
+
|
|
387
|
+
# Skip events with null requestParameters since we can't extract roleArn
|
|
388
|
+
if not cloudtrail_event.get("requestParameters"):
|
|
389
|
+
logger.debug(
|
|
390
|
+
f"Skipping CloudTrail AssumeRoleWithWebIdentity event due to missing requestParameters. Event: {event.get('EventId', 'unknown')}"
|
|
391
|
+
)
|
|
392
|
+
continue
|
|
393
|
+
|
|
394
|
+
user_identity = cloudtrail_event.get("userIdentity", {})
|
|
395
|
+
|
|
396
|
+
if user_identity.get("type") == "WebIdentityUser" and user_identity.get(
|
|
397
|
+
"userName"
|
|
398
|
+
):
|
|
399
|
+
identity_provider = user_identity.get("identityProvider", "unknown")
|
|
400
|
+
destination_principal = cloudtrail_event["requestParameters"]["roleArn"]
|
|
401
|
+
event_time = event.get("EventTime")
|
|
402
|
+
|
|
403
|
+
# Only process GitHub Actions events
|
|
404
|
+
if "token.actions.githubusercontent.com" in identity_provider:
|
|
405
|
+
# Extract GitHub repo fullname from userName format: "repo:{organization}/{repository}:{context}"
|
|
406
|
+
user_name = user_identity.get("userName", "")
|
|
407
|
+
if not user_name:
|
|
408
|
+
logger.debug(
|
|
409
|
+
f"Missing userName in GitHub WebIdentity event: {event.get('EventId', 'unknown')}"
|
|
410
|
+
)
|
|
411
|
+
continue
|
|
412
|
+
|
|
413
|
+
github_repo = _extract_github_repo_from_username(user_name)
|
|
414
|
+
key = (github_repo, destination_principal)
|
|
415
|
+
|
|
416
|
+
if key in github_aggregated:
|
|
417
|
+
github_aggregated[key]["times_used"] += 1
|
|
418
|
+
# Handle None values safely for time comparisons
|
|
419
|
+
if event_time:
|
|
420
|
+
existing_first = github_aggregated[key][
|
|
421
|
+
"first_seen_in_time_window"
|
|
422
|
+
]
|
|
423
|
+
existing_last = github_aggregated[key]["last_used"]
|
|
424
|
+
|
|
425
|
+
if existing_first is None or event_time < existing_first:
|
|
426
|
+
github_aggregated[key][
|
|
427
|
+
"first_seen_in_time_window"
|
|
428
|
+
] = event_time
|
|
429
|
+
if existing_last is None or event_time > existing_last:
|
|
430
|
+
github_aggregated[key]["last_used"] = event_time
|
|
431
|
+
else:
|
|
432
|
+
github_aggregated[key] = {
|
|
433
|
+
"source_repo_fullname": github_repo,
|
|
434
|
+
"destination_principal_arn": destination_principal,
|
|
435
|
+
"times_used": 1,
|
|
436
|
+
"first_seen_in_time_window": event_time,
|
|
437
|
+
"last_used": event_time,
|
|
438
|
+
}
|
|
439
|
+
else:
|
|
440
|
+
# Skip non-GitHub events for now
|
|
441
|
+
continue
|
|
442
|
+
else:
|
|
443
|
+
continue
|
|
444
|
+
# Return aggregated relationships directly
|
|
445
|
+
return list(github_aggregated.values())
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
@timeit
|
|
449
|
+
def load_role_assumptions(
|
|
450
|
+
neo4j_session: neo4j.Session,
|
|
451
|
+
aggregated_role_assumptions: List[Dict[str, Any]],
|
|
452
|
+
current_aws_account_id: str,
|
|
453
|
+
aws_update_tag: int,
|
|
454
|
+
) -> None:
|
|
455
|
+
"""
|
|
456
|
+
Load aggregated role assumption relationships into Neo4j using MatchLink pattern.
|
|
457
|
+
|
|
458
|
+
Creates direct ASSUMED_ROLE relationships with aggregated properties:
|
|
459
|
+
(AWSUser|AWSRole|AWSPrincipal)-[:ASSUMED_ROLE {lastupdated, times_used, first_seen_in_time_window, last_used}]->(AWSRole)
|
|
460
|
+
|
|
461
|
+
Assumes that both source principals and destination roles already exist in the graph.
|
|
462
|
+
|
|
463
|
+
:type neo4j_session: neo4j.Session
|
|
464
|
+
:param neo4j_session: The Neo4j session to use for database operations
|
|
465
|
+
:type aggregated_role_assumptions: List[Dict[str, Any]]
|
|
466
|
+
:param aggregated_role_assumptions: List of aggregated role assumption relationships from transform function
|
|
467
|
+
:type current_aws_account_id: str
|
|
468
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
469
|
+
:type aws_update_tag: int
|
|
470
|
+
:param aws_update_tag: Timestamp tag for tracking data freshness
|
|
471
|
+
:rtype: None
|
|
472
|
+
"""
|
|
473
|
+
# Use MatchLink to create relationships between existing nodes
|
|
474
|
+
matchlink_schema = AssumedRoleMatchLink()
|
|
475
|
+
|
|
476
|
+
load_matchlinks(
|
|
477
|
+
neo4j_session,
|
|
478
|
+
matchlink_schema,
|
|
479
|
+
aggregated_role_assumptions,
|
|
480
|
+
lastupdated=aws_update_tag,
|
|
481
|
+
_sub_resource_label="AWSAccount",
|
|
482
|
+
_sub_resource_id=current_aws_account_id,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
logger.info(
|
|
486
|
+
f"Successfully loaded {len(aggregated_role_assumptions)} role assumption relationships"
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
@timeit
|
|
491
|
+
def load_saml_role_assumptions(
|
|
492
|
+
neo4j_session: neo4j.Session,
|
|
493
|
+
aggregated_role_assumptions: List[Dict[str, Any]],
|
|
494
|
+
current_aws_account_id: str,
|
|
495
|
+
aws_update_tag: int,
|
|
496
|
+
) -> None:
|
|
497
|
+
"""
|
|
498
|
+
Load aggregated SAML role assumption relationships into Neo4j using MatchLink pattern.
|
|
499
|
+
|
|
500
|
+
Creates direct ASSUMED_ROLE_WITH_SAML relationships with aggregated properties:
|
|
501
|
+
(AWSRole)-[:ASSUMED_ROLE_WITH_SAML {lastupdated, times_used, first_seen_in_time_window, last_used}]->(AWSRole)
|
|
502
|
+
|
|
503
|
+
Assumes that both source principals and destination roles already exist in the graph.
|
|
504
|
+
|
|
505
|
+
:type neo4j_session: neo4j.Session
|
|
506
|
+
:param neo4j_session: The Neo4j session to use for database operations
|
|
507
|
+
:type aggregated_role_assumptions: List[Dict[str, Any]]
|
|
508
|
+
:param aggregated_role_assumptions: List of aggregated SAML role assumption relationships from transform function
|
|
509
|
+
:type current_aws_account_id: str
|
|
510
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
511
|
+
:type aws_update_tag: int
|
|
512
|
+
:param aws_update_tag: Timestamp tag for tracking data freshness
|
|
513
|
+
:rtype: None
|
|
514
|
+
"""
|
|
515
|
+
# Use MatchLink to create relationships between existing nodes
|
|
516
|
+
matchlink_schema = AssumedRoleWithSAMLMatchLink()
|
|
517
|
+
|
|
518
|
+
load_matchlinks(
|
|
519
|
+
neo4j_session,
|
|
520
|
+
matchlink_schema,
|
|
521
|
+
aggregated_role_assumptions,
|
|
522
|
+
lastupdated=aws_update_tag,
|
|
523
|
+
_sub_resource_label="AWSAccount",
|
|
524
|
+
_sub_resource_id=current_aws_account_id,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
logger.info(
|
|
528
|
+
f"Successfully loaded {len(aggregated_role_assumptions)} SAML role assumption relationships"
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
@timeit
|
|
533
|
+
def load_web_identity_role_assumptions(
|
|
534
|
+
neo4j_session: neo4j.Session,
|
|
535
|
+
aggregated_role_assumptions: List[Dict[str, Any]],
|
|
536
|
+
current_aws_account_id: str,
|
|
537
|
+
aws_update_tag: int,
|
|
538
|
+
) -> None:
|
|
539
|
+
"""
|
|
540
|
+
Load aggregated WebIdentity role assumption relationships into Neo4j using MatchLink pattern.
|
|
541
|
+
|
|
542
|
+
Creates direct ASSUMED_ROLE_WITH_WEB_IDENTITY relationships with aggregated properties:
|
|
543
|
+
(GitHubRepository)-[:ASSUMED_ROLE_WITH_WEB_IDENTITY {lastupdated, times_used, first_seen_in_time_window, last_used}]->(AWSRole)
|
|
544
|
+
|
|
545
|
+
Assumes that both source principals and destination roles already exist in the graph.
|
|
546
|
+
|
|
547
|
+
:type neo4j_session: neo4j.Session
|
|
548
|
+
:param neo4j_session: The Neo4j session to use for database operations
|
|
549
|
+
:type aggregated_role_assumptions: List[Dict[str, Any]]
|
|
550
|
+
:param aggregated_role_assumptions: List of aggregated WebIdentity role assumption relationships from transform function
|
|
551
|
+
:type current_aws_account_id: str
|
|
552
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
553
|
+
:type aws_update_tag: int
|
|
554
|
+
:param aws_update_tag: Timestamp tag for tracking data freshness
|
|
555
|
+
:rtype: None
|
|
556
|
+
"""
|
|
557
|
+
# Use MatchLink to create relationships between existing nodes
|
|
558
|
+
matchlink_schema = GitHubRepoAssumeRoleWithWebIdentityMatchLink()
|
|
559
|
+
|
|
560
|
+
load_matchlinks(
|
|
561
|
+
neo4j_session,
|
|
562
|
+
matchlink_schema,
|
|
563
|
+
aggregated_role_assumptions,
|
|
564
|
+
lastupdated=aws_update_tag,
|
|
565
|
+
_sub_resource_label="AWSAccount",
|
|
566
|
+
_sub_resource_id=current_aws_account_id,
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
logger.info(
|
|
570
|
+
f"Successfully loaded {len(aggregated_role_assumptions)} WebIdentity role assumption relationships"
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def _convert_assumed_role_arn_to_role_arn(assumed_role_arn: str) -> str:
|
|
575
|
+
"""
|
|
576
|
+
Convert an assumed role ARN to the original role ARN.
|
|
577
|
+
|
|
578
|
+
Example:
|
|
579
|
+
Input: "arn:aws:sts::123456789012:assumed-role/MyRole/session-name"
|
|
580
|
+
Output: "arn:aws:iam::123456789012:role/MyRole"
|
|
581
|
+
"""
|
|
582
|
+
|
|
583
|
+
# Split the ARN into parts
|
|
584
|
+
arn_parts = assumed_role_arn.split(":")
|
|
585
|
+
if len(arn_parts) >= 6 and arn_parts[2] == "sts" and "assumed-role" in arn_parts[5]:
|
|
586
|
+
# Extract account ID and role name
|
|
587
|
+
account_id = arn_parts[4]
|
|
588
|
+
resource_part = arn_parts[5] # "assumed-role/MyRole/session-name"
|
|
589
|
+
role_name = resource_part.split("/")[1] # Extract "MyRole"
|
|
590
|
+
|
|
591
|
+
# Construct the IAM role ARN
|
|
592
|
+
return f"arn:aws:iam::{account_id}:role/{role_name}"
|
|
593
|
+
|
|
594
|
+
# Return original ARN if conversion fails
|
|
595
|
+
return assumed_role_arn
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def _extract_github_repo_from_username(user_name: str) -> str:
|
|
599
|
+
"""
|
|
600
|
+
Extract GitHub repository fullname from CloudTrail userName field.
|
|
601
|
+
|
|
602
|
+
GitHub Actions CloudTrail events have userName in the format:
|
|
603
|
+
"repo:{organization}/{repository}:{context}"
|
|
604
|
+
"""
|
|
605
|
+
if not user_name:
|
|
606
|
+
return ""
|
|
607
|
+
|
|
608
|
+
parts = user_name.split(":")
|
|
609
|
+
|
|
610
|
+
# Need at least 3 parts: ["repo", "{organization}/{repository}", "{context}"]
|
|
611
|
+
if len(parts) < 3 or parts[0] != "repo":
|
|
612
|
+
return ""
|
|
613
|
+
|
|
614
|
+
# Extract "{organization}/{repository}"
|
|
615
|
+
repo_fullname = parts[1]
|
|
616
|
+
|
|
617
|
+
# Validate it looks like "{organization}/{repository}" format
|
|
618
|
+
if repo_fullname.count("/") != 1:
|
|
619
|
+
return ""
|
|
620
|
+
|
|
621
|
+
# Ensure both organization and repo exist
|
|
622
|
+
owner, repo = repo_fullname.split("/")
|
|
623
|
+
if not owner or not repo:
|
|
624
|
+
return ""
|
|
625
|
+
|
|
626
|
+
return repo_fullname
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
@timeit
|
|
630
|
+
def cleanup(
|
|
631
|
+
neo4j_session: neo4j.Session, current_aws_account_id: str, update_tag: int
|
|
632
|
+
) -> None:
|
|
633
|
+
"""
|
|
634
|
+
Run CloudTrail management events cleanup job to remove stale ASSUMED_ROLE relationships.
|
|
635
|
+
|
|
636
|
+
:type neo4j_session: neo4j.Session
|
|
637
|
+
:param neo4j_session: The Neo4j session to use for database operations
|
|
638
|
+
:type current_aws_account_id: str
|
|
639
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
640
|
+
:type update_tag: int
|
|
641
|
+
:param update_tag: Timestamp tag for tracking data freshness
|
|
642
|
+
:rtype: None
|
|
643
|
+
"""
|
|
644
|
+
logger.info("Running CloudTrail management events cleanup job.")
|
|
645
|
+
|
|
646
|
+
matchlink_schema = AssumedRoleMatchLink()
|
|
647
|
+
cleanup_job = GraphJob.from_matchlink(
|
|
648
|
+
matchlink_schema,
|
|
649
|
+
"AWSAccount",
|
|
650
|
+
current_aws_account_id,
|
|
651
|
+
update_tag,
|
|
652
|
+
)
|
|
653
|
+
cleanup_job.run(neo4j_session)
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
@timeit
|
|
657
|
+
def sync_assume_role_events(
|
|
658
|
+
neo4j_session: neo4j.Session,
|
|
659
|
+
boto3_session: boto3.Session,
|
|
660
|
+
regions: List[str],
|
|
661
|
+
current_aws_account_id: str,
|
|
662
|
+
update_tag: int,
|
|
663
|
+
common_job_parameters: Dict[str, Any],
|
|
664
|
+
) -> None:
|
|
665
|
+
"""
|
|
666
|
+
Sync CloudTrail management events to create ASSUMED_ROLE relationships.
|
|
667
|
+
|
|
668
|
+
This function orchestrates the complete process:
|
|
669
|
+
1. Fetch CloudTrail management events region by region
|
|
670
|
+
2. Transform events into role assumption records per region
|
|
671
|
+
3. Load role assumption relationships into Neo4j for each region
|
|
672
|
+
4. Run cleanup after processing all regions
|
|
673
|
+
|
|
674
|
+
The resulting graph contains direct relationships like:
|
|
675
|
+
(AWSUser|AWSRole|AWSPrincipal)-[:ASSUMED_ROLE {times_used, first_seen_in_time_window, last_used, lastupdated}]->(AWSRole)
|
|
676
|
+
|
|
677
|
+
:type neo4j_session: neo4j.Session
|
|
678
|
+
:param neo4j_session: The Neo4j session
|
|
679
|
+
:type boto3_session: boto3.Session
|
|
680
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
681
|
+
:type regions: List[str]
|
|
682
|
+
:param regions: List of AWS regions to sync
|
|
683
|
+
:type current_aws_account_id: str
|
|
684
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
685
|
+
:type aws_update_tag: int
|
|
686
|
+
:param aws_update_tag: Timestamp tag for tracking data freshness
|
|
687
|
+
:rtype: None
|
|
688
|
+
"""
|
|
689
|
+
# Extract lookback hours from common_job_parameters (set by CLI parameter)
|
|
690
|
+
lookback_hours = common_job_parameters.get(
|
|
691
|
+
"aws_cloudtrail_management_events_lookback_hours"
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
if not lookback_hours:
|
|
695
|
+
logger.info(
|
|
696
|
+
"CloudTrail management events sync skipped - no lookback period specified"
|
|
697
|
+
)
|
|
698
|
+
return
|
|
699
|
+
|
|
700
|
+
logger.info(
|
|
701
|
+
f"Syncing {len(regions)} regions with {lookback_hours} hour lookback period"
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
total_role_assumptions = 0
|
|
705
|
+
|
|
706
|
+
# Process events region by region
|
|
707
|
+
for region in regions:
|
|
708
|
+
logger.info(f"Processing CloudTrail events for region {region}")
|
|
709
|
+
|
|
710
|
+
# Process AssumeRole events specifically
|
|
711
|
+
logger.info(f"Fetching AssumeRole events specifically for region {region}")
|
|
712
|
+
assume_role_events = get_assume_role_events(
|
|
713
|
+
boto3_session=boto3_session,
|
|
714
|
+
region=region,
|
|
715
|
+
lookback_hours=lookback_hours,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Transform AssumeRole events to role assumptions
|
|
719
|
+
assume_role_assumptions = transform_assume_role_events_to_role_assumptions(
|
|
720
|
+
events=assume_role_events,
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
# Load AssumeRole assumptions for this region
|
|
724
|
+
load_role_assumptions(
|
|
725
|
+
neo4j_session=neo4j_session,
|
|
726
|
+
aggregated_role_assumptions=assume_role_assumptions,
|
|
727
|
+
current_aws_account_id=current_aws_account_id,
|
|
728
|
+
aws_update_tag=update_tag,
|
|
729
|
+
)
|
|
730
|
+
total_role_assumptions += len(assume_role_assumptions)
|
|
731
|
+
logger.info(
|
|
732
|
+
f"Loaded {len(assume_role_assumptions)} AssumeRole assumptions for region {region}"
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
# Run cleanup for stale relationships after processing all regions
|
|
736
|
+
cleanup(neo4j_session, current_aws_account_id, update_tag)
|
|
737
|
+
|
|
738
|
+
logger.info(
|
|
739
|
+
f"CloudTrail management events sync completed successfully. "
|
|
740
|
+
f"Processed {total_role_assumptions} total role assumption events across {len(regions)} regions."
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
@timeit
|
|
745
|
+
def sync_saml_role_events(
|
|
746
|
+
neo4j_session: neo4j.Session,
|
|
747
|
+
boto3_session: boto3.Session,
|
|
748
|
+
regions: List[str],
|
|
749
|
+
current_aws_account_id: str,
|
|
750
|
+
update_tag: int,
|
|
751
|
+
common_job_parameters: Dict[str, Any],
|
|
752
|
+
) -> None:
|
|
753
|
+
"""
|
|
754
|
+
Sync CloudTrail SAML management events to create ASSUMED_ROLE_WITH_SAML relationships.
|
|
755
|
+
|
|
756
|
+
This function orchestrates the complete process:
|
|
757
|
+
1. Fetch CloudTrail SAML management events region by region
|
|
758
|
+
2. Transform events into role assumption records per region
|
|
759
|
+
3. Load role assumption relationships into Neo4j for each region
|
|
760
|
+
|
|
761
|
+
The resulting graph contains direct relationships like:
|
|
762
|
+
(AWSRole)-[:ASSUMED_ROLE_WITH_SAML {times_used, first_seen_in_time_window, last_used, lastupdated}]->(AWSRole)
|
|
763
|
+
|
|
764
|
+
:type neo4j_session: neo4j.Session
|
|
765
|
+
:param neo4j_session: The Neo4j session
|
|
766
|
+
:type boto3_session: boto3.Session
|
|
767
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
768
|
+
:type regions: List[str]
|
|
769
|
+
:param regions: List of AWS regions to sync
|
|
770
|
+
:type current_aws_account_id: str
|
|
771
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
772
|
+
:type update_tag: int
|
|
773
|
+
:param update_tag: Timestamp tag for tracking data freshness
|
|
774
|
+
:rtype: None
|
|
775
|
+
"""
|
|
776
|
+
# Extract lookback hours from common_job_parameters (set by CLI parameter)
|
|
777
|
+
lookback_hours = common_job_parameters.get(
|
|
778
|
+
"aws_cloudtrail_management_events_lookback_hours"
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
if not lookback_hours:
|
|
782
|
+
logger.info(
|
|
783
|
+
"CloudTrail SAML management events sync skipped - no lookback period specified"
|
|
784
|
+
)
|
|
785
|
+
return
|
|
786
|
+
|
|
787
|
+
logger.info(
|
|
788
|
+
f"Syncing SAML events for {len(regions)} regions with {lookback_hours} hour lookback period"
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
total_saml_role_assumptions = 0
|
|
792
|
+
|
|
793
|
+
# Process events region by region
|
|
794
|
+
for region in regions:
|
|
795
|
+
logger.info(f"Processing CloudTrail SAML events for region {region}")
|
|
796
|
+
|
|
797
|
+
# Process AssumeRoleWithSAML events specifically
|
|
798
|
+
logger.info(
|
|
799
|
+
f"Fetching AssumeRoleWithSAML events specifically for region {region}"
|
|
800
|
+
)
|
|
801
|
+
saml_role_events = get_saml_role_events(
|
|
802
|
+
boto3_session=boto3_session,
|
|
803
|
+
region=region,
|
|
804
|
+
lookback_hours=lookback_hours,
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
# Transform AssumeRoleWithSAML events to role assumptions
|
|
808
|
+
saml_role_assumptions = transform_saml_role_events_to_role_assumptions(
|
|
809
|
+
events=saml_role_events,
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
# Load SAML role assumptions for this region
|
|
813
|
+
load_saml_role_assumptions(
|
|
814
|
+
neo4j_session=neo4j_session,
|
|
815
|
+
aggregated_role_assumptions=saml_role_assumptions,
|
|
816
|
+
current_aws_account_id=current_aws_account_id,
|
|
817
|
+
aws_update_tag=update_tag,
|
|
818
|
+
)
|
|
819
|
+
total_saml_role_assumptions += len(saml_role_assumptions)
|
|
820
|
+
logger.info(
|
|
821
|
+
f"Loaded {len(saml_role_assumptions)} SAML role assumptions for region {region}"
|
|
822
|
+
)
|
|
823
|
+
|
|
824
|
+
logger.info(
|
|
825
|
+
f"CloudTrail SAML management events sync completed successfully. "
|
|
826
|
+
f"Processed {total_saml_role_assumptions} total SAML role assumption events across {len(regions)} regions."
|
|
827
|
+
)
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
@timeit
|
|
831
|
+
def sync_web_identity_role_events(
|
|
832
|
+
neo4j_session: neo4j.Session,
|
|
833
|
+
boto3_session: boto3.Session,
|
|
834
|
+
regions: List[str],
|
|
835
|
+
current_aws_account_id: str,
|
|
836
|
+
update_tag: int,
|
|
837
|
+
common_job_parameters: Dict[str, Any],
|
|
838
|
+
) -> None:
|
|
839
|
+
"""
|
|
840
|
+
Sync CloudTrail WebIdentity management events to create ASSUMED_ROLE_WITH_WEB_IDENTITY relationships.
|
|
841
|
+
|
|
842
|
+
This function orchestrates the complete process:
|
|
843
|
+
1. Fetch CloudTrail WebIdentity management events region by region
|
|
844
|
+
2. Transform events into role assumption records per region
|
|
845
|
+
3. Load role assumption relationships into Neo4j for each region
|
|
846
|
+
|
|
847
|
+
The resulting graph contains direct relationships like:
|
|
848
|
+
(GitHubRepository)-[:ASSUMED_ROLE_WITH_WEB_IDENTITY {times_used, first_seen_in_time_window, last_used, lastupdated}]->(AWSRole)
|
|
849
|
+
|
|
850
|
+
:type neo4j_session: neo4j.Session
|
|
851
|
+
:param neo4j_session: The Neo4j session
|
|
852
|
+
:type boto3_session: boto3.Session
|
|
853
|
+
:param boto3_session: The boto3 session to use for API calls
|
|
854
|
+
:type regions: List[str]
|
|
855
|
+
:param regions: List of AWS regions to sync
|
|
856
|
+
:type current_aws_account_id: str
|
|
857
|
+
:param current_aws_account_id: The AWS account ID being synced
|
|
858
|
+
:type update_tag: int
|
|
859
|
+
:param update_tag: Timestamp tag for tracking data freshness
|
|
860
|
+
:rtype: None
|
|
861
|
+
"""
|
|
862
|
+
# Extract lookback hours from common_job_parameters (set by CLI parameter)
|
|
863
|
+
lookback_hours = common_job_parameters.get(
|
|
864
|
+
"aws_cloudtrail_management_events_lookback_hours"
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
if not lookback_hours:
|
|
868
|
+
logger.info(
|
|
869
|
+
"CloudTrail WebIdentity management events sync skipped - no lookback period specified"
|
|
870
|
+
)
|
|
871
|
+
return
|
|
872
|
+
|
|
873
|
+
logger.info(
|
|
874
|
+
f"Syncing WebIdentity events for {len(regions)} regions with {lookback_hours} hour lookback period"
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
total_web_identity_role_assumptions = 0
|
|
878
|
+
|
|
879
|
+
# Process events region by region
|
|
880
|
+
for region in regions:
|
|
881
|
+
logger.info(f"Processing CloudTrail WebIdentity events for region {region}")
|
|
882
|
+
|
|
883
|
+
# Process AssumeRoleWithWebIdentity events specifically
|
|
884
|
+
logger.info(
|
|
885
|
+
f"Fetching AssumeRoleWithWebIdentity events specifically for region {region}"
|
|
886
|
+
)
|
|
887
|
+
web_identity_role_events = get_web_identity_role_events(
|
|
888
|
+
boto3_session=boto3_session,
|
|
889
|
+
region=region,
|
|
890
|
+
lookback_hours=lookback_hours,
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
# Transform AssumeRoleWithWebIdentity events to role assumptions
|
|
894
|
+
web_identity_role_assumptions = (
|
|
895
|
+
transform_web_identity_role_events_to_role_assumptions(
|
|
896
|
+
events=web_identity_role_events,
|
|
897
|
+
)
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
# Load WebIdentity role assumptions for this region
|
|
901
|
+
load_web_identity_role_assumptions(
|
|
902
|
+
neo4j_session=neo4j_session,
|
|
903
|
+
aggregated_role_assumptions=web_identity_role_assumptions,
|
|
904
|
+
current_aws_account_id=current_aws_account_id,
|
|
905
|
+
aws_update_tag=update_tag,
|
|
906
|
+
)
|
|
907
|
+
total_web_identity_role_assumptions += len(web_identity_role_assumptions)
|
|
908
|
+
logger.info(
|
|
909
|
+
f"Loaded {len(web_identity_role_assumptions)} WebIdentity role assumptions for region {region}"
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
logger.info(
|
|
913
|
+
f"CloudTrail WebIdentity management events sync completed successfully. "
|
|
914
|
+
f"Processed {total_web_identity_role_assumptions} total WebIdentity role assumption events across {len(regions)} regions."
|
|
915
|
+
)
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
# Main sync function for when we decide to add more event types
|
|
919
|
+
@timeit
|
|
920
|
+
def sync(
|
|
921
|
+
neo4j_session: neo4j.Session,
|
|
922
|
+
boto3_session: boto3.Session,
|
|
923
|
+
regions: List[str],
|
|
924
|
+
current_aws_account_id: str,
|
|
925
|
+
update_tag: int,
|
|
926
|
+
common_job_parameters: Dict[str, Any],
|
|
927
|
+
) -> None:
|
|
928
|
+
"""
|
|
929
|
+
Main sync function for CloudTrail management events.
|
|
930
|
+
|
|
931
|
+
Syncs AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity events to create separate
|
|
932
|
+
relationship types in the graph for security analysis.
|
|
933
|
+
"""
|
|
934
|
+
# Sync regular AssumeRole events
|
|
935
|
+
sync_assume_role_events(
|
|
936
|
+
neo4j_session=neo4j_session,
|
|
937
|
+
boto3_session=boto3_session,
|
|
938
|
+
regions=regions,
|
|
939
|
+
current_aws_account_id=current_aws_account_id,
|
|
940
|
+
update_tag=update_tag,
|
|
941
|
+
common_job_parameters=common_job_parameters,
|
|
942
|
+
)
|
|
943
|
+
|
|
944
|
+
# Sync SAML AssumeRoleWithSAML events
|
|
945
|
+
sync_saml_role_events(
|
|
946
|
+
neo4j_session=neo4j_session,
|
|
947
|
+
boto3_session=boto3_session,
|
|
948
|
+
regions=regions,
|
|
949
|
+
current_aws_account_id=current_aws_account_id,
|
|
950
|
+
update_tag=update_tag,
|
|
951
|
+
common_job_parameters=common_job_parameters,
|
|
952
|
+
)
|
|
953
|
+
|
|
954
|
+
# Sync WebIdentity AssumeRoleWithWebIdentity events
|
|
955
|
+
sync_web_identity_role_events(
|
|
956
|
+
neo4j_session=neo4j_session,
|
|
957
|
+
boto3_session=boto3_session,
|
|
958
|
+
regions=regions,
|
|
959
|
+
current_aws_account_id=current_aws_account_id,
|
|
960
|
+
update_tag=update_tag,
|
|
961
|
+
common_job_parameters=common_job_parameters,
|
|
962
|
+
)
|