cartography 0.102.0rc2__py3-none-any.whl → 0.103.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.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/__main__.py +1 -2
- cartography/_version.py +2 -2
- cartography/cli.py +376 -249
- cartography/client/core/tx.py +39 -18
- cartography/config.py +28 -0
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +71 -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 +35 -15
- cartography/graph/job.py +46 -17
- cartography/graph/querybuilder.py +165 -80
- cartography/graph/statement.py +35 -26
- cartography/intel/analysis.py +4 -1
- cartography/intel/aws/__init__.py +114 -55
- cartography/intel/aws/apigateway.py +134 -63
- cartography/intel/aws/cloudtrail.py +127 -0
- cartography/intel/aws/cloudwatch.py +93 -0
- cartography/intel/aws/config.py +56 -20
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
- cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
- cartography/intel/aws/ec2/images.py +49 -20
- cartography/intel/aws/ec2/instances.py +234 -136
- cartography/intel/aws/ec2/internet_gateways.py +40 -11
- cartography/intel/aws/ec2/key_pairs.py +44 -20
- cartography/intel/aws/ec2/launch_templates.py +101 -59
- cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
- cartography/intel/aws/ec2/load_balancers.py +82 -42
- cartography/intel/aws/ec2/network_acls.py +89 -65
- cartography/intel/aws/ec2/network_interfaces.py +146 -87
- cartography/intel/aws/ec2/reserved_instances.py +45 -16
- cartography/intel/aws/ec2/route_tables.py +138 -98
- cartography/intel/aws/ec2/security_groups.py +71 -21
- cartography/intel/aws/ec2/snapshots.py +61 -22
- cartography/intel/aws/ec2/subnets.py +54 -18
- cartography/intel/aws/ec2/tgw.py +100 -34
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +37 -12
- cartography/intel/aws/ec2/vpc_peerings.py +83 -24
- cartography/intel/aws/ecr.py +88 -32
- cartography/intel/aws/ecs.py +83 -47
- cartography/intel/aws/efs.py +93 -0
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +42 -18
- cartography/intel/aws/elasticsearch.py +57 -20
- cartography/intel/aws/emr.py +61 -23
- cartography/intel/aws/iam.py +401 -145
- cartography/intel/aws/iam_instance_profiles.py +22 -22
- cartography/intel/aws/identitycenter.py +71 -37
- cartography/intel/aws/inspector.py +159 -89
- cartography/intel/aws/kms.py +92 -38
- cartography/intel/aws/lambda_function.py +103 -34
- cartography/intel/aws/organizations.py +30 -10
- cartography/intel/aws/permission_relationships.py +133 -51
- cartography/intel/aws/rds.py +249 -85
- cartography/intel/aws/redshift.py +107 -46
- cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
- cartography/intel/aws/resources.py +57 -46
- cartography/intel/aws/route53.py +108 -61
- cartography/intel/aws/s3.py +168 -83
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +24 -12
- cartography/intel/aws/securityhub.py +20 -9
- cartography/intel/aws/sns.py +166 -0
- cartography/intel/aws/sqs.py +60 -28
- cartography/intel/aws/ssm.py +70 -30
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +78 -19
- cartography/intel/azure/compute.py +101 -27
- cartography/intel/azure/cosmosdb.py +496 -170
- cartography/intel/azure/sql.py +296 -105
- cartography/intel/azure/storage.py +322 -113
- cartography/intel/azure/subscription.py +39 -23
- cartography/intel/azure/tenant.py +13 -4
- cartography/intel/azure/util/credentials.py +95 -55
- 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 +3 -2
- cartography/intel/crowdstrike/__init__.py +11 -9
- cartography/intel/crowdstrike/endpoints.py +5 -1
- cartography/intel/crowdstrike/spotlight.py +8 -3
- cartography/intel/cve/__init__.py +46 -13
- cartography/intel/cve/feed.py +48 -12
- 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 +36 -10
- 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 +25 -7
- cartography/intel/entra/ou.py +112 -0
- cartography/intel/entra/users.py +69 -63
- cartography/intel/gcp/__init__.py +185 -49
- cartography/intel/gcp/compute.py +418 -231
- cartography/intel/gcp/crm.py +96 -43
- cartography/intel/gcp/dns.py +60 -19
- cartography/intel/gcp/gke.py +72 -38
- cartography/intel/gcp/iam.py +61 -41
- cartography/intel/gcp/storage.py +84 -55
- cartography/intel/github/__init__.py +13 -11
- cartography/intel/github/repos.py +270 -137
- cartography/intel/github/teams.py +170 -88
- cartography/intel/github/users.py +70 -39
- cartography/intel/github/util.py +36 -34
- cartography/intel/gsuite/__init__.py +47 -26
- cartography/intel/gsuite/api.py +73 -30
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +30 -7
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +14 -8
- cartography/intel/kubernetes/namespaces.py +7 -4
- cartography/intel/kubernetes/pods.py +7 -4
- cartography/intel/kubernetes/services.py +8 -4
- 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 +134 -38
- cartography/intel/oci/organizations.py +13 -6
- cartography/intel/oci/utils.py +43 -20
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +42 -20
- cartography/intel/okta/awssaml.py +93 -33
- cartography/intel/okta/factors.py +16 -4
- cartography/intel/okta/groups.py +56 -29
- cartography/intel/okta/organization.py +5 -1
- cartography/intel/okta/origins.py +6 -2
- cartography/intel/okta/roles.py +15 -5
- cartography/intel/okta/users.py +20 -8
- cartography/intel/okta/utils.py +6 -4
- cartography/intel/openai/__init__.py +86 -0
- cartography/intel/openai/adminapikeys.py +90 -0
- cartography/intel/openai/apikeys.py +96 -0
- cartography/intel/openai/projects.py +94 -0
- cartography/intel/openai/serviceaccounts.py +82 -0
- cartography/intel/openai/users.py +78 -0
- cartography/intel/openai/util.py +29 -0
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +18 -6
- cartography/intel/pagerduty/schedules.py +12 -4
- cartography/intel/pagerduty/services.py +11 -4
- cartography/intel/pagerduty/teams.py +8 -3
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/semgrep/__init__.py +24 -6
- cartography/intel/semgrep/dependencies.py +50 -28
- cartography/intel/semgrep/deployment.py +3 -1
- cartography/intel/semgrep/findings.py +42 -18
- cartography/intel/snipeit/__init__.py +17 -3
- cartography/intel/snipeit/asset.py +12 -6
- cartography/intel/snipeit/user.py +8 -5
- cartography/intel/snipeit/util.py +9 -4
- 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/models/aws/apigateway.py +21 -17
- cartography/models/aws/apigatewaycertificate.py +28 -22
- cartography/models/aws/apigatewayresource.py +28 -20
- cartography/models/aws/apigatewaystage.py +33 -25
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/trail.py +61 -0
- cartography/models/aws/cloudwatch/__init__.py +0 -0
- cartography/models/aws/cloudwatch/loggroup.py +52 -0
- cartography/models/aws/dynamodb/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +25 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +51 -45
- cartography/models/aws/ec2/keypair.py +21 -16
- cartography/models/aws/ec2/keypair_instance.py +28 -21
- cartography/models/aws/ec2/launch_configurations.py +30 -26
- 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 +27 -23
- cartography/models/aws/ec2/load_balancers.py +47 -37
- cartography/models/aws/ec2/network_acl_rules.py +38 -30
- cartography/models/aws/ec2/network_acls.py +38 -29
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +53 -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 +44 -34
- cartography/models/aws/ec2/route_tables.py +50 -43
- cartography/models/aws/ec2/routes.py +45 -37
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/subnet_instance.py +24 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
- cartography/models/aws/ec2/volumes.py +47 -40
- cartography/models/aws/efs/__init__.py +0 -0
- cartography/models/aws/efs/mount_target.py +52 -0
- cartography/models/aws/eks/clusters.py +23 -21
- cartography/models/aws/emr.py +32 -30
- cartography/models/aws/iam/instanceprofile.py +33 -24
- cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
- cartography/models/aws/identitycenter/awspermissionset.py +37 -29
- cartography/models/aws/identitycenter/awsssouser.py +23 -21
- cartography/models/aws/inspector/findings.py +77 -65
- cartography/models/aws/inspector/packages.py +35 -29
- cartography/models/aws/s3/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- cartography/models/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- 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 +82 -0
- cartography/models/cloudflare/role.py +44 -0
- cartography/models/cloudflare/zone.py +59 -0
- cartography/models/core/common.py +12 -10
- cartography/models/core/nodes.py +5 -2
- cartography/models/core/relationships.py +14 -6
- cartography/models/crowdstrike/hosts.py +37 -35
- 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 +56 -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 +46 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/ou.py +48 -0
- cartography/models/entra/tenant.py +24 -18
- cartography/models/entra/user.py +64 -48
- cartography/models/gcp/iam.py +23 -23
- cartography/models/github/orgs.py +5 -4
- cartography/models/github/teams.py +37 -31
- cartography/models/github/users.py +34 -23
- cartography/models/kandji/device.py +22 -16
- cartography/models/kandji/tenant.py +6 -4
- cartography/models/lastpass/tenant.py +3 -3
- cartography/models/lastpass/user.py +32 -28
- cartography/models/openai/__init__.py +0 -0
- cartography/models/openai/adminapikey.py +90 -0
- cartography/models/openai/apikey.py +84 -0
- cartography/models/openai/organization.py +17 -0
- cartography/models/openai/project.py +70 -0
- cartography/models/openai/serviceaccount.py +50 -0
- cartography/models/openai/user.py +49 -0
- cartography/models/semgrep/dependencies.py +36 -24
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -42
- cartography/models/semgrep/locations.py +27 -21
- cartography/models/snipeit/asset.py +30 -21
- cartography/models/snipeit/tenant.py +6 -4
- cartography/models/snipeit/user.py +19 -12
- cartography/models/tailscale/__init__.py +0 -0
- cartography/models/tailscale/device.py +95 -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 +52 -0
- cartography/stats.py +3 -3
- cartography/sync.py +113 -31
- cartography/util.py +84 -62
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/METADATA +8 -15
- cartography-0.103.0.dist-info/RECORD +442 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
- cartography-0.102.0rc2.dist-info/RECORD +0 -381
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,6 @@ import logging
|
|
|
3
3
|
import boto3
|
|
4
4
|
import neo4j
|
|
5
5
|
|
|
6
|
-
from .util import get_botocore_config
|
|
7
6
|
from cartography.client.core.tx import load
|
|
8
7
|
from cartography.graph.job import GraphJob
|
|
9
8
|
from cartography.models.aws.ec2.load_balancer_listeners import ELBListenerSchema
|
|
@@ -11,6 +10,8 @@ from cartography.models.aws.ec2.load_balancers import LoadBalancerSchema
|
|
|
11
10
|
from cartography.util import aws_handle_regions
|
|
12
11
|
from cartography.util import timeit
|
|
13
12
|
|
|
13
|
+
from .util import get_botocore_config
|
|
14
|
+
|
|
14
15
|
logger = logging.getLogger(__name__)
|
|
15
16
|
|
|
16
17
|
|
|
@@ -29,7 +30,9 @@ def _get_listener_id(load_balancer_id: str, port: int, protocol: str) -> str:
|
|
|
29
30
|
return f"{load_balancer_id}{port}{protocol}"
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
def transform_load_balancer_listener_data(
|
|
33
|
+
def transform_load_balancer_listener_data(
|
|
34
|
+
load_balancer_id: str, listener_data: list[dict]
|
|
35
|
+
) -> list[dict]:
|
|
33
36
|
"""
|
|
34
37
|
Transform load balancer listener data into a format suitable for cartography ingestion.
|
|
35
38
|
|
|
@@ -42,21 +45,27 @@ def transform_load_balancer_listener_data(load_balancer_id: str, listener_data:
|
|
|
42
45
|
"""
|
|
43
46
|
transformed = []
|
|
44
47
|
for listener in listener_data:
|
|
45
|
-
listener_info = listener[
|
|
48
|
+
listener_info = listener["Listener"]
|
|
46
49
|
transformed_listener = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
"id": _get_listener_id(
|
|
51
|
+
load_balancer_id,
|
|
52
|
+
listener_info["LoadBalancerPort"],
|
|
53
|
+
listener_info["Protocol"],
|
|
54
|
+
),
|
|
55
|
+
"port": listener_info.get("LoadBalancerPort"),
|
|
56
|
+
"protocol": listener_info.get("Protocol"),
|
|
57
|
+
"instance_port": listener_info.get("InstancePort"),
|
|
58
|
+
"instance_protocol": listener_info.get("InstanceProtocol"),
|
|
59
|
+
"policy_names": listener.get("PolicyNames", []),
|
|
60
|
+
"LoadBalancerId": load_balancer_id,
|
|
54
61
|
}
|
|
55
62
|
transformed.append(transformed_listener)
|
|
56
63
|
return transformed
|
|
57
64
|
|
|
58
65
|
|
|
59
|
-
def transform_load_balancer_data(
|
|
66
|
+
def transform_load_balancer_data(
|
|
67
|
+
load_balancers: list[dict],
|
|
68
|
+
) -> tuple[list[dict], list[dict]]:
|
|
60
69
|
"""
|
|
61
70
|
Transform load balancer data into a format suitable for cartography ingestion.
|
|
62
71
|
|
|
@@ -70,35 +79,38 @@ def transform_load_balancer_data(load_balancers: list[dict]) -> tuple[list[dict]
|
|
|
70
79
|
listener_data = []
|
|
71
80
|
|
|
72
81
|
for lb in load_balancers:
|
|
73
|
-
load_balancer_id = lb[
|
|
82
|
+
load_balancer_id = lb["DNSName"]
|
|
74
83
|
transformed_lb = {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
"id": load_balancer_id,
|
|
85
|
+
"name": lb["LoadBalancerName"],
|
|
86
|
+
"dnsname": lb["DNSName"],
|
|
87
|
+
"canonicalhostedzonename": lb.get("CanonicalHostedZoneName"),
|
|
88
|
+
"canonicalhostedzonenameid": lb.get("CanonicalHostedZoneNameID"),
|
|
89
|
+
"scheme": lb.get("Scheme"),
|
|
90
|
+
"createdtime": str(lb["CreatedTime"]),
|
|
91
|
+
"GROUP_NAME": lb.get("SourceSecurityGroup", {}).get("GroupName"),
|
|
92
|
+
"GROUP_IDS": [str(group) for group in lb.get("SecurityGroups", [])],
|
|
93
|
+
"INSTANCE_IDS": [
|
|
94
|
+
instance["InstanceId"] for instance in lb.get("Instances", [])
|
|
95
|
+
],
|
|
96
|
+
"LISTENER_IDS": [
|
|
86
97
|
_get_listener_id(
|
|
87
98
|
load_balancer_id,
|
|
88
|
-
listener[
|
|
89
|
-
listener[
|
|
90
|
-
)
|
|
99
|
+
listener["Listener"]["LoadBalancerPort"],
|
|
100
|
+
listener["Listener"]["Protocol"],
|
|
101
|
+
)
|
|
102
|
+
for listener in lb.get("ListenerDescriptions", [])
|
|
91
103
|
],
|
|
92
104
|
}
|
|
93
105
|
transformed.append(transformed_lb)
|
|
94
106
|
|
|
95
107
|
# Classic ELB listeners are not returned anywhere else in AWS, so we must parse them out
|
|
96
108
|
# of the describe_load_balancers response.
|
|
97
|
-
if lb.get(
|
|
109
|
+
if lb.get("ListenerDescriptions"):
|
|
98
110
|
listener_data.extend(
|
|
99
111
|
transform_load_balancer_listener_data(
|
|
100
112
|
load_balancer_id,
|
|
101
|
-
lb.get(
|
|
113
|
+
lb.get("ListenerDescriptions", []),
|
|
102
114
|
),
|
|
103
115
|
)
|
|
104
116
|
|
|
@@ -107,18 +119,25 @@ def transform_load_balancer_data(load_balancers: list[dict]) -> tuple[list[dict]
|
|
|
107
119
|
|
|
108
120
|
@timeit
|
|
109
121
|
@aws_handle_regions
|
|
110
|
-
def get_loadbalancer_data(
|
|
111
|
-
|
|
112
|
-
|
|
122
|
+
def get_loadbalancer_data(
|
|
123
|
+
boto3_session: boto3.session.Session, region: str
|
|
124
|
+
) -> list[dict]:
|
|
125
|
+
client = boto3_session.client(
|
|
126
|
+
"elb", region_name=region, config=get_botocore_config()
|
|
127
|
+
)
|
|
128
|
+
paginator = client.get_paginator("describe_load_balancers")
|
|
113
129
|
elbs: list[dict] = []
|
|
114
130
|
for page in paginator.paginate():
|
|
115
|
-
elbs.extend(page[
|
|
131
|
+
elbs.extend(page["LoadBalancerDescriptions"])
|
|
116
132
|
return elbs
|
|
117
133
|
|
|
118
134
|
|
|
119
135
|
@timeit
|
|
120
136
|
def load_load_balancers(
|
|
121
|
-
neo4j_session: neo4j.Session,
|
|
137
|
+
neo4j_session: neo4j.Session,
|
|
138
|
+
data: list[dict],
|
|
139
|
+
region: str,
|
|
140
|
+
current_aws_account_id: str,
|
|
122
141
|
update_tag: int,
|
|
123
142
|
) -> None:
|
|
124
143
|
load(
|
|
@@ -133,7 +152,10 @@ def load_load_balancers(
|
|
|
133
152
|
|
|
134
153
|
@timeit
|
|
135
154
|
def load_load_balancer_listeners(
|
|
136
|
-
neo4j_session: neo4j.Session,
|
|
155
|
+
neo4j_session: neo4j.Session,
|
|
156
|
+
data: list[dict],
|
|
157
|
+
region: str,
|
|
158
|
+
current_aws_account_id: str,
|
|
137
159
|
update_tag: int,
|
|
138
160
|
) -> None:
|
|
139
161
|
load(
|
|
@@ -147,22 +169,40 @@ def load_load_balancer_listeners(
|
|
|
147
169
|
|
|
148
170
|
|
|
149
171
|
@timeit
|
|
150
|
-
def cleanup_load_balancers(
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
def cleanup_load_balancers(
|
|
173
|
+
neo4j_session: neo4j.Session, common_job_parameters: dict
|
|
174
|
+
) -> None:
|
|
175
|
+
GraphJob.from_node_schema(ELBListenerSchema(), common_job_parameters).run(
|
|
176
|
+
neo4j_session
|
|
177
|
+
)
|
|
178
|
+
GraphJob.from_node_schema(LoadBalancerSchema(), common_job_parameters).run(
|
|
179
|
+
neo4j_session
|
|
180
|
+
)
|
|
153
181
|
|
|
154
182
|
|
|
155
183
|
@timeit
|
|
156
184
|
def sync_load_balancers(
|
|
157
|
-
neo4j_session: neo4j.Session,
|
|
158
|
-
|
|
185
|
+
neo4j_session: neo4j.Session,
|
|
186
|
+
boto3_session: boto3.session.Session,
|
|
187
|
+
regions: list[str],
|
|
188
|
+
current_aws_account_id: str,
|
|
189
|
+
update_tag: int,
|
|
190
|
+
common_job_parameters: dict,
|
|
159
191
|
) -> None:
|
|
160
192
|
for region in regions:
|
|
161
|
-
logger.info(
|
|
193
|
+
logger.info(
|
|
194
|
+
"Syncing EC2 load balancers for region '%s' in account '%s'.",
|
|
195
|
+
region,
|
|
196
|
+
current_aws_account_id,
|
|
197
|
+
)
|
|
162
198
|
data = get_loadbalancer_data(boto3_session, region)
|
|
163
199
|
transformed_data, listener_data = transform_load_balancer_data(data)
|
|
164
200
|
|
|
165
|
-
load_load_balancers(
|
|
166
|
-
|
|
201
|
+
load_load_balancers(
|
|
202
|
+
neo4j_session, transformed_data, region, current_aws_account_id, update_tag
|
|
203
|
+
)
|
|
204
|
+
load_load_balancer_listeners(
|
|
205
|
+
neo4j_session, listener_data, region, current_aws_account_id, update_tag
|
|
206
|
+
)
|
|
167
207
|
|
|
168
208
|
cleanup_load_balancers(neo4j_session, common_job_parameters)
|
|
@@ -5,7 +5,6 @@ from typing import Any
|
|
|
5
5
|
import boto3
|
|
6
6
|
import neo4j
|
|
7
7
|
|
|
8
|
-
from .util import get_botocore_config
|
|
9
8
|
from cartography.client.core.tx import load
|
|
10
9
|
from cartography.graph.job import GraphJob
|
|
11
10
|
from cartography.models.aws.ec2.network_acl_rules import EC2NetworkAclEgressRuleSchema
|
|
@@ -14,51 +13,63 @@ from cartography.models.aws.ec2.network_acls import EC2NetworkAclSchema
|
|
|
14
13
|
from cartography.util import aws_handle_regions
|
|
15
14
|
from cartography.util import timeit
|
|
16
15
|
|
|
16
|
+
from .util import get_botocore_config
|
|
17
|
+
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
18
19
|
|
|
19
20
|
Ec2AclObjects = namedtuple(
|
|
20
|
-
"Ec2AclObjects",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
"Ec2AclObjects",
|
|
22
|
+
[
|
|
23
|
+
"network_acls",
|
|
24
|
+
"inbound_rules",
|
|
25
|
+
"outbound_rules",
|
|
24
26
|
],
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
@timeit
|
|
29
31
|
@aws_handle_regions
|
|
30
|
-
def get_network_acl_data(
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
def get_network_acl_data(
|
|
33
|
+
boto3_session: boto3.session.Session,
|
|
34
|
+
region: str,
|
|
35
|
+
) -> list[dict[str, Any]]:
|
|
36
|
+
client = boto3_session.client(
|
|
37
|
+
"ec2",
|
|
38
|
+
region_name=region,
|
|
39
|
+
config=get_botocore_config(),
|
|
40
|
+
)
|
|
41
|
+
paginator = client.get_paginator("describe_network_acls")
|
|
33
42
|
acls = []
|
|
34
43
|
for page in paginator.paginate():
|
|
35
|
-
acls.extend(page[
|
|
44
|
+
acls.extend(page["NetworkAcls"])
|
|
36
45
|
return acls
|
|
37
46
|
|
|
38
47
|
|
|
39
48
|
def transform_network_acl_data(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
data_list: list[dict[str, Any]],
|
|
50
|
+
region: str,
|
|
51
|
+
current_aws_account_id: str,
|
|
43
52
|
) -> Ec2AclObjects:
|
|
44
53
|
network_acls = []
|
|
45
54
|
inbound_rules = []
|
|
46
55
|
outbound_rules = []
|
|
47
56
|
|
|
48
57
|
for network_acl in data_list:
|
|
49
|
-
network_acl_id = network_acl[
|
|
58
|
+
network_acl_id = network_acl["NetworkAclId"]
|
|
50
59
|
base_network_acl = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
"Id": network_acl_id,
|
|
61
|
+
"Arn": f"arn:aws:ec2:{region}:{current_aws_account_id}:network-acl/{network_acl_id}",
|
|
62
|
+
"IsDefault": network_acl["IsDefault"],
|
|
63
|
+
"VpcId": network_acl["VpcId"],
|
|
64
|
+
"OwnerId": network_acl["OwnerId"],
|
|
56
65
|
}
|
|
57
|
-
if network_acl.get(
|
|
66
|
+
if network_acl.get("Associations") and network_acl["Associations"]:
|
|
58
67
|
# Include subnet associations in the data object if they exist
|
|
59
|
-
for association in network_acl[
|
|
60
|
-
base_network_acl[
|
|
61
|
-
|
|
68
|
+
for association in network_acl["Associations"]:
|
|
69
|
+
base_network_acl["NetworkAclAssociationId"] = association[
|
|
70
|
+
"NetworkAclAssociationId"
|
|
71
|
+
]
|
|
72
|
+
base_network_acl["SubnetId"] = association["SubnetId"]
|
|
62
73
|
network_acls.append(base_network_acl)
|
|
63
74
|
else:
|
|
64
75
|
# Otherwise if there's no associations then don't include that in the data object
|
|
@@ -66,21 +77,21 @@ def transform_network_acl_data(
|
|
|
66
77
|
|
|
67
78
|
if network_acl.get("Entries"):
|
|
68
79
|
for rule in network_acl["Entries"]:
|
|
69
|
-
direction =
|
|
80
|
+
direction = "egress" if rule["Egress"] else "inbound"
|
|
70
81
|
transformed_rule = {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
"Id": f"{network_acl['NetworkAclId']}/{direction}/{rule['RuleNumber']}",
|
|
83
|
+
"CidrBlock": rule.get("CidrBlock"),
|
|
84
|
+
"Ipv6CidrBlock": rule.get("Ipv6CidrBlock"),
|
|
85
|
+
"Egress": rule["Egress"],
|
|
86
|
+
"Protocol": rule["Protocol"],
|
|
87
|
+
"RuleAction": rule["RuleAction"],
|
|
88
|
+
"RuleNumber": rule["RuleNumber"],
|
|
78
89
|
# Add pointer back to the nacl to create an edge
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
"NetworkAclId": network_acl_id,
|
|
91
|
+
"FromPort": rule.get("PortRange", {}).get("FromPort"),
|
|
92
|
+
"ToPort": rule.get("PortRange", {}).get("ToPort"),
|
|
82
93
|
}
|
|
83
|
-
if transformed_rule[
|
|
94
|
+
if transformed_rule["Egress"]:
|
|
84
95
|
outbound_rules.append(transformed_rule)
|
|
85
96
|
else:
|
|
86
97
|
inbound_rules.append(transformed_rule)
|
|
@@ -93,11 +104,11 @@ def transform_network_acl_data(
|
|
|
93
104
|
|
|
94
105
|
@timeit
|
|
95
106
|
def load_all_nacl_data(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
neo4j_session: neo4j.Session,
|
|
108
|
+
ec2_acl_objects: Ec2AclObjects,
|
|
109
|
+
region: str,
|
|
110
|
+
aws_account_id: str,
|
|
111
|
+
update_tag: int,
|
|
101
112
|
) -> None:
|
|
102
113
|
load_network_acls(
|
|
103
114
|
neo4j_session,
|
|
@@ -124,11 +135,11 @@ def load_all_nacl_data(
|
|
|
124
135
|
|
|
125
136
|
@timeit
|
|
126
137
|
def load_network_acls(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
neo4j_session: neo4j.Session,
|
|
139
|
+
data: list[dict[str, Any]],
|
|
140
|
+
region: str,
|
|
141
|
+
aws_account_id: str,
|
|
142
|
+
update_tag: int,
|
|
132
143
|
) -> None:
|
|
133
144
|
logger.info(f"Loading {len(data)} network acls in {region}.")
|
|
134
145
|
load(
|
|
@@ -143,11 +154,11 @@ def load_network_acls(
|
|
|
143
154
|
|
|
144
155
|
@timeit
|
|
145
156
|
def load_network_acl_inbound_rules(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
neo4j_session: neo4j.Session,
|
|
158
|
+
data: list[dict[str, Any]],
|
|
159
|
+
region: str,
|
|
160
|
+
aws_account_id: str,
|
|
161
|
+
update_tag: int,
|
|
151
162
|
) -> None:
|
|
152
163
|
logger.info(f"Loading {len(data)} network acl inbound rules in {region}.")
|
|
153
164
|
load(
|
|
@@ -162,11 +173,11 @@ def load_network_acl_inbound_rules(
|
|
|
162
173
|
|
|
163
174
|
@timeit
|
|
164
175
|
def load_network_acl_egress_rules(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
neo4j_session: neo4j.Session,
|
|
177
|
+
data: list[dict[str, Any]],
|
|
178
|
+
region: str,
|
|
179
|
+
aws_account_id: str,
|
|
180
|
+
update_tag: int,
|
|
170
181
|
) -> None:
|
|
171
182
|
logger.info(f"Loading {len(data)} network acl egress rules in {region}.")
|
|
172
183
|
load(
|
|
@@ -180,23 +191,36 @@ def load_network_acl_egress_rules(
|
|
|
180
191
|
|
|
181
192
|
|
|
182
193
|
@timeit
|
|
183
|
-
def cleanup_network_acls(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
def cleanup_network_acls(
|
|
195
|
+
neo4j_session: neo4j.Session,
|
|
196
|
+
common_job_parameters: dict[str, Any],
|
|
197
|
+
) -> None:
|
|
198
|
+
GraphJob.from_node_schema(EC2NetworkAclSchema(), common_job_parameters).run(
|
|
199
|
+
neo4j_session,
|
|
200
|
+
)
|
|
201
|
+
GraphJob.from_node_schema(
|
|
202
|
+
EC2NetworkAclInboundRuleSchema(),
|
|
203
|
+
common_job_parameters,
|
|
204
|
+
).run(neo4j_session)
|
|
205
|
+
GraphJob.from_node_schema(
|
|
206
|
+
EC2NetworkAclEgressRuleSchema(),
|
|
207
|
+
common_job_parameters,
|
|
208
|
+
).run(neo4j_session)
|
|
187
209
|
|
|
188
210
|
|
|
189
211
|
@timeit
|
|
190
212
|
def sync_network_acls(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
213
|
+
neo4j_session: neo4j.Session,
|
|
214
|
+
boto3_session: boto3.session.Session,
|
|
215
|
+
regions: list[str],
|
|
216
|
+
current_aws_account_id: str,
|
|
217
|
+
update_tag: int,
|
|
218
|
+
common_job_parameters: dict[str, Any],
|
|
197
219
|
) -> None:
|
|
198
220
|
for region in regions:
|
|
199
|
-
logger.info(
|
|
221
|
+
logger.info(
|
|
222
|
+
f"Syncing EC2 network ACLs for region '{region}' in account '{current_aws_account_id}'.",
|
|
223
|
+
)
|
|
200
224
|
data = get_network_acl_data(boto3_session, region)
|
|
201
225
|
ec2_acl_data = transform_network_acl_data(data, region, current_aws_account_id)
|
|
202
226
|
load_all_nacl_data(
|