cartography 0.102.0rc2__py3-none-any.whl → 0.103.0rc1__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 +302 -253
- cartography/client/core/tx.py +39 -18
- cartography/config.py +4 -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/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/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 +53 -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/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/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/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/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/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/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/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/stats.py +3 -3
- cartography/sync.py +107 -31
- cartography/util.py +84 -62
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
- cartography-0.103.0rc1.dist-info/RECORD +396 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
- cartography-0.102.0rc2.dist-info/RECORD +0 -381
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -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(
|
|
@@ -8,20 +8,28 @@ from typing import List
|
|
|
8
8
|
import boto3
|
|
9
9
|
import neo4j
|
|
10
10
|
|
|
11
|
-
from .util import get_botocore_config
|
|
12
11
|
from cartography.client.core.tx import load
|
|
13
12
|
from cartography.graph.job import GraphJob
|
|
14
13
|
from cartography.models.aws.ec2.networkinterfaces import EC2NetworkInterfaceSchema
|
|
15
|
-
from cartography.models.aws.ec2.privateip_networkinterface import
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
from cartography.models.aws.ec2.privateip_networkinterface import (
|
|
15
|
+
EC2PrivateIpNetworkInterfaceSchema,
|
|
16
|
+
)
|
|
17
|
+
from cartography.models.aws.ec2.securitygroup_networkinterface import (
|
|
18
|
+
EC2SecurityGroupNetworkInterfaceSchema,
|
|
19
|
+
)
|
|
20
|
+
from cartography.models.aws.ec2.subnet_networkinterface import (
|
|
21
|
+
EC2SubnetNetworkInterfaceSchema,
|
|
22
|
+
)
|
|
18
23
|
from cartography.util import aws_handle_regions
|
|
19
24
|
from cartography.util import timeit
|
|
20
25
|
|
|
26
|
+
from .util import get_botocore_config
|
|
27
|
+
|
|
21
28
|
logger = logging.getLogger(__name__)
|
|
22
29
|
|
|
23
30
|
Ec2NetworkData = namedtuple(
|
|
24
|
-
"Ec2NetworkData",
|
|
31
|
+
"Ec2NetworkData",
|
|
32
|
+
[
|
|
25
33
|
"network_interface_list",
|
|
26
34
|
"private_ip_list",
|
|
27
35
|
"sg_list",
|
|
@@ -32,16 +40,26 @@ Ec2NetworkData = namedtuple(
|
|
|
32
40
|
|
|
33
41
|
@timeit
|
|
34
42
|
@aws_handle_regions
|
|
35
|
-
def get_network_interface_data(
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
def get_network_interface_data(
|
|
44
|
+
boto3_session: boto3.session.Session,
|
|
45
|
+
region: str,
|
|
46
|
+
) -> List[Dict[str, Any]]:
|
|
47
|
+
client = boto3_session.client(
|
|
48
|
+
"ec2",
|
|
49
|
+
region_name=region,
|
|
50
|
+
config=get_botocore_config(),
|
|
51
|
+
)
|
|
52
|
+
paginator = client.get_paginator("describe_network_interfaces")
|
|
38
53
|
subnets: List[Dict] = []
|
|
39
54
|
for page in paginator.paginate():
|
|
40
|
-
subnets.extend(page[
|
|
55
|
+
subnets.extend(page["NetworkInterfaces"])
|
|
41
56
|
return subnets
|
|
42
57
|
|
|
43
58
|
|
|
44
|
-
def transform_network_interface_data(
|
|
59
|
+
def transform_network_interface_data(
|
|
60
|
+
data_list: List[Dict[str, Any]],
|
|
61
|
+
region: str,
|
|
62
|
+
) -> Ec2NetworkData:
|
|
45
63
|
network_interface_list = []
|
|
46
64
|
private_ip_list = []
|
|
47
65
|
sg_list = []
|
|
@@ -52,45 +70,52 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
|
|
|
52
70
|
# https://aws.amazon.com/premiumsupport/knowledge-center/elb-find-load-balancer-IP/
|
|
53
71
|
elb_v1_id = None
|
|
54
72
|
elb_v2_id = None
|
|
55
|
-
elb_match = re.match(
|
|
73
|
+
elb_match = re.match(
|
|
74
|
+
r"^ELB (?:net|app)/([^\/]+)\/(.*)",
|
|
75
|
+
network_interface.get("Description", ""),
|
|
76
|
+
)
|
|
56
77
|
if elb_match:
|
|
57
|
-
elb_v1_id = f
|
|
78
|
+
elb_v1_id = f"{elb_match[1]}-{elb_match[2]}.elb.{region}.amazonaws.com"
|
|
58
79
|
else:
|
|
59
|
-
elb_match = re.match(r
|
|
80
|
+
elb_match = re.match(r"^ELB (.*)", network_interface.get("Description", ""))
|
|
60
81
|
if elb_match:
|
|
61
82
|
elb_v2_id = elb_match[1]
|
|
62
83
|
# TODO issue #1024 change this to arn when ready
|
|
63
|
-
network_interface_id = network_interface[
|
|
84
|
+
network_interface_id = network_interface["NetworkInterfaceId"]
|
|
64
85
|
network_interface_list.append(
|
|
65
86
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
"Id": network_interface_id,
|
|
88
|
+
"NetworkInterfaceId": network_interface["NetworkInterfaceId"],
|
|
89
|
+
"Description": network_interface["Description"],
|
|
90
|
+
"InstanceId": network_interface.get("Attachment", {}).get("InstanceId"),
|
|
91
|
+
"InterfaceType": network_interface["InterfaceType"],
|
|
92
|
+
"MacAddress": network_interface["MacAddress"],
|
|
93
|
+
"PrivateDnsName": network_interface.get("PrivateDnsName"),
|
|
94
|
+
"PrivateIpAddress": network_interface["PrivateIpAddress"],
|
|
95
|
+
"PublicIp": network_interface.get("Association", {}).get("PublicIp"),
|
|
96
|
+
"RequesterId": network_interface.get("RequesterId"),
|
|
97
|
+
"RequesterManaged": network_interface["RequesterManaged"],
|
|
98
|
+
"SourceDestCheck": network_interface["SourceDestCheck"],
|
|
99
|
+
"Status": network_interface["Status"],
|
|
100
|
+
"SubnetId": network_interface["SubnetId"],
|
|
101
|
+
"ElbV1Id": elb_v1_id,
|
|
102
|
+
"ElbV2Id": elb_v2_id,
|
|
82
103
|
},
|
|
83
104
|
)
|
|
84
|
-
if network_interface.get(
|
|
85
|
-
for private_ip_address in network_interface[
|
|
105
|
+
if network_interface.get("PrivateIpAddresses"):
|
|
106
|
+
for private_ip_address in network_interface["PrivateIpAddresses"]:
|
|
86
107
|
private_ip_list.append(
|
|
87
108
|
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
"Id": f"{network_interface['NetworkInterfaceId']}:{private_ip_address['PrivateIpAddress']}",
|
|
110
|
+
"NetworkInterfaceId": network_interface["NetworkInterfaceId"],
|
|
111
|
+
"IpOwnerId": private_ip_address.get("Association", {}).get(
|
|
112
|
+
"IpOwnerId",
|
|
113
|
+
),
|
|
114
|
+
"Primary": private_ip_address["Primary"],
|
|
115
|
+
"PrivateIpAddress": private_ip_address["PrivateIpAddress"],
|
|
116
|
+
"PublicIp": private_ip_address.get("Association", {}).get(
|
|
117
|
+
"PublicIp",
|
|
118
|
+
),
|
|
94
119
|
},
|
|
95
120
|
)
|
|
96
121
|
|
|
@@ -98,19 +123,19 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
|
|
|
98
123
|
for group in network_interface["Groups"]:
|
|
99
124
|
sg_list.append(
|
|
100
125
|
{
|
|
101
|
-
|
|
102
|
-
|
|
126
|
+
"GroupId": group["GroupId"],
|
|
127
|
+
"NetworkInterfaceId": network_interface_id,
|
|
103
128
|
},
|
|
104
129
|
)
|
|
105
130
|
|
|
106
|
-
subnet_id = network_interface.get(
|
|
131
|
+
subnet_id = network_interface.get("SubnetId")
|
|
107
132
|
if subnet_id:
|
|
108
133
|
subnet_list.append(
|
|
109
134
|
{
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
135
|
+
"NetworkInterfaceId": network_interface_id,
|
|
136
|
+
"SubnetId": subnet_id,
|
|
137
|
+
"ElbV1Id": elb_v1_id,
|
|
138
|
+
"ElbV2Id": elb_v2_id,
|
|
114
139
|
},
|
|
115
140
|
)
|
|
116
141
|
|
|
@@ -124,11 +149,11 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
|
|
|
124
149
|
|
|
125
150
|
@timeit
|
|
126
151
|
def load_network_interfaces(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
152
|
+
neo4j_session: neo4j.Session,
|
|
153
|
+
data: List[Dict[str, Any]],
|
|
154
|
+
region: str,
|
|
155
|
+
aws_account_id: str,
|
|
156
|
+
update_tag: int,
|
|
132
157
|
) -> None:
|
|
133
158
|
logger.info(f"Loading {len(data)} network interfaces in {region}.")
|
|
134
159
|
load(
|
|
@@ -143,11 +168,11 @@ def load_network_interfaces(
|
|
|
143
168
|
|
|
144
169
|
@timeit
|
|
145
170
|
def load_private_ip_network_interface(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
171
|
+
neo4j_session: neo4j.Session,
|
|
172
|
+
data: List[Dict[str, Any]],
|
|
173
|
+
region: str,
|
|
174
|
+
aws_account_id: str,
|
|
175
|
+
update_tag: int,
|
|
151
176
|
) -> None:
|
|
152
177
|
"""
|
|
153
178
|
Private IPs as known by describe-network-interfaces.
|
|
@@ -165,11 +190,11 @@ def load_private_ip_network_interface(
|
|
|
165
190
|
|
|
166
191
|
@timeit
|
|
167
192
|
def load_security_group_network_interface(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
neo4j_session: neo4j.Session,
|
|
194
|
+
data: List[Dict[str, Any]],
|
|
195
|
+
region: str,
|
|
196
|
+
aws_account_id: str,
|
|
197
|
+
update_tag: int,
|
|
173
198
|
) -> None:
|
|
174
199
|
"""
|
|
175
200
|
Security groups as known by describe-network-interfaces.
|
|
@@ -187,11 +212,11 @@ def load_security_group_network_interface(
|
|
|
187
212
|
|
|
188
213
|
@timeit
|
|
189
214
|
def load_subnet_network_interface(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
215
|
+
neo4j_session: neo4j.Session,
|
|
216
|
+
data: List[Dict[str, Any]],
|
|
217
|
+
region: str,
|
|
218
|
+
aws_account_id: str,
|
|
219
|
+
update_tag: int,
|
|
195
220
|
) -> None:
|
|
196
221
|
"""
|
|
197
222
|
Subnets as known by describe-network-interfaces.
|
|
@@ -208,38 +233,72 @@ def load_subnet_network_interface(
|
|
|
208
233
|
|
|
209
234
|
|
|
210
235
|
def load_network_data(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
236
|
+
neo4j_session: neo4j.Session,
|
|
237
|
+
region: str,
|
|
238
|
+
current_aws_account_id: str,
|
|
239
|
+
update_tag: int,
|
|
240
|
+
network_interface_list: List[Dict[str, Any]],
|
|
241
|
+
private_ip_list: List[Dict[str, Any]],
|
|
242
|
+
subnet_list: List[Dict[str, Any]],
|
|
243
|
+
sg_list: List[Dict[str, Any]],
|
|
219
244
|
) -> None:
|
|
220
|
-
load_network_interfaces(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
245
|
+
load_network_interfaces(
|
|
246
|
+
neo4j_session,
|
|
247
|
+
network_interface_list,
|
|
248
|
+
region,
|
|
249
|
+
current_aws_account_id,
|
|
250
|
+
update_tag,
|
|
251
|
+
)
|
|
252
|
+
load_private_ip_network_interface(
|
|
253
|
+
neo4j_session,
|
|
254
|
+
private_ip_list,
|
|
255
|
+
region,
|
|
256
|
+
current_aws_account_id,
|
|
257
|
+
update_tag,
|
|
258
|
+
)
|
|
259
|
+
load_subnet_network_interface(
|
|
260
|
+
neo4j_session,
|
|
261
|
+
subnet_list,
|
|
262
|
+
region,
|
|
263
|
+
current_aws_account_id,
|
|
264
|
+
update_tag,
|
|
265
|
+
)
|
|
266
|
+
load_security_group_network_interface(
|
|
267
|
+
neo4j_session,
|
|
268
|
+
sg_list,
|
|
269
|
+
region,
|
|
270
|
+
current_aws_account_id,
|
|
271
|
+
update_tag,
|
|
272
|
+
)
|
|
224
273
|
|
|
225
274
|
|
|
226
275
|
@timeit
|
|
227
|
-
def cleanup_network_interfaces(
|
|
228
|
-
|
|
229
|
-
|
|
276
|
+
def cleanup_network_interfaces(
|
|
277
|
+
neo4j_session: neo4j.Session,
|
|
278
|
+
common_job_parameters: Dict,
|
|
279
|
+
) -> None:
|
|
280
|
+
GraphJob.from_node_schema(EC2NetworkInterfaceSchema(), common_job_parameters).run(
|
|
281
|
+
neo4j_session,
|
|
282
|
+
)
|
|
283
|
+
GraphJob.from_node_schema(
|
|
284
|
+
EC2PrivateIpNetworkInterfaceSchema(),
|
|
285
|
+
common_job_parameters,
|
|
286
|
+
).run(neo4j_session)
|
|
230
287
|
|
|
231
288
|
|
|
232
289
|
@timeit
|
|
233
290
|
def sync_network_interfaces(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
291
|
+
neo4j_session: neo4j.Session,
|
|
292
|
+
boto3_session: boto3.session.Session,
|
|
293
|
+
regions: List[str],
|
|
294
|
+
current_aws_account_id: str,
|
|
295
|
+
update_tag: int,
|
|
296
|
+
common_job_parameters: Dict,
|
|
240
297
|
) -> None:
|
|
241
298
|
for region in regions:
|
|
242
|
-
logger.info(
|
|
299
|
+
logger.info(
|
|
300
|
+
f"Syncing EC2 network interfaces for region '{region}' in account '{current_aws_account_id}'.",
|
|
301
|
+
)
|
|
243
302
|
data = get_network_interface_data(boto3_session, region)
|
|
244
303
|
ec2_network_data = transform_network_interface_data(data, region)
|
|
245
304
|
load_network_data(
|