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
|
@@ -17,34 +17,43 @@ logger = logging.getLogger(__name__)
|
|
|
17
17
|
|
|
18
18
|
@timeit
|
|
19
19
|
@aws_handle_regions
|
|
20
|
-
def get_ec2_key_pairs(
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
def get_ec2_key_pairs(
|
|
21
|
+
boto3_session: boto3.session.Session,
|
|
22
|
+
region: str,
|
|
23
|
+
) -> list[dict[str, Any]]:
|
|
24
|
+
client = boto3_session.client(
|
|
25
|
+
"ec2",
|
|
26
|
+
region_name=region,
|
|
27
|
+
config=get_botocore_config(),
|
|
28
|
+
)
|
|
29
|
+
return client.describe_key_pairs()["KeyPairs"]
|
|
23
30
|
|
|
24
31
|
|
|
25
32
|
def transform_ec2_key_pairs(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
key_pairs: list[dict[str, Any]],
|
|
34
|
+
region: str,
|
|
35
|
+
current_aws_account_id: str,
|
|
29
36
|
) -> list[dict[str, Any]]:
|
|
30
37
|
transformed_key_pairs = []
|
|
31
38
|
for key_pair in key_pairs:
|
|
32
39
|
key_name = key_pair["KeyName"]
|
|
33
|
-
transformed_key_pairs.append(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
transformed_key_pairs.append(
|
|
41
|
+
{
|
|
42
|
+
"KeyPairArn": f"arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}",
|
|
43
|
+
"KeyName": key_name,
|
|
44
|
+
"KeyFingerprint": key_pair.get("KeyFingerprint"),
|
|
45
|
+
},
|
|
46
|
+
)
|
|
38
47
|
return transformed_key_pairs
|
|
39
48
|
|
|
40
49
|
|
|
41
50
|
@timeit
|
|
42
51
|
def load_ec2_key_pairs(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
neo4j_session: neo4j.Session,
|
|
53
|
+
data: list[dict[str, Any]],
|
|
54
|
+
region: str,
|
|
55
|
+
current_aws_account_id: str,
|
|
56
|
+
update_tag: int,
|
|
48
57
|
) -> None:
|
|
49
58
|
# Load EC2 keypairs as known by describe-key-pairs
|
|
50
59
|
logger.info(f"Loading {len(data)} EC2 keypairs for region '{region}' into graph.")
|
|
@@ -59,8 +68,13 @@ def load_ec2_key_pairs(
|
|
|
59
68
|
|
|
60
69
|
|
|
61
70
|
@timeit
|
|
62
|
-
def cleanup_ec2_key_pairs(
|
|
63
|
-
|
|
71
|
+
def cleanup_ec2_key_pairs(
|
|
72
|
+
neo4j_session: neo4j.Session,
|
|
73
|
+
common_job_parameters: Dict,
|
|
74
|
+
) -> None:
|
|
75
|
+
GraphJob.from_node_schema(EC2KeyPairSchema(), common_job_parameters).run(
|
|
76
|
+
neo4j_session,
|
|
77
|
+
)
|
|
64
78
|
|
|
65
79
|
|
|
66
80
|
@timeit
|
|
@@ -73,8 +87,18 @@ def sync_ec2_key_pairs(
|
|
|
73
87
|
common_job_parameters: dict[str, Any],
|
|
74
88
|
) -> None:
|
|
75
89
|
for region in regions:
|
|
76
|
-
logger.info(
|
|
90
|
+
logger.info(
|
|
91
|
+
"Syncing EC2 key pairs for region '%s' in account '%s'.",
|
|
92
|
+
region,
|
|
93
|
+
current_aws_account_id,
|
|
94
|
+
)
|
|
77
95
|
data = get_ec2_key_pairs(boto3_session, region)
|
|
78
96
|
transformed_data = transform_ec2_key_pairs(data, region, current_aws_account_id)
|
|
79
|
-
load_ec2_key_pairs(
|
|
97
|
+
load_ec2_key_pairs(
|
|
98
|
+
neo4j_session,
|
|
99
|
+
transformed_data,
|
|
100
|
+
region,
|
|
101
|
+
current_aws_account_id,
|
|
102
|
+
update_tag,
|
|
103
|
+
)
|
|
80
104
|
cleanup_ec2_key_pairs(neo4j_session, common_job_parameters)
|
|
@@ -5,14 +5,17 @@ import boto3
|
|
|
5
5
|
import botocore
|
|
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
|
-
from cartography.models.aws.ec2.launch_template_versions import
|
|
10
|
+
from cartography.models.aws.ec2.launch_template_versions import (
|
|
11
|
+
LaunchTemplateVersionSchema,
|
|
12
|
+
)
|
|
12
13
|
from cartography.models.aws.ec2.launch_templates import LaunchTemplateSchema
|
|
13
14
|
from cartography.util import aws_handle_regions
|
|
14
15
|
from cartography.util import timeit
|
|
15
16
|
|
|
17
|
+
from .util import get_botocore_config
|
|
18
|
+
|
|
16
19
|
logger = logging.getLogger(__name__)
|
|
17
20
|
|
|
18
21
|
|
|
@@ -22,11 +25,13 @@ def get_launch_templates(
|
|
|
22
25
|
boto3_session: boto3.session.Session,
|
|
23
26
|
region: str,
|
|
24
27
|
) -> list[dict[str, Any]]:
|
|
25
|
-
client = boto3_session.client(
|
|
26
|
-
|
|
28
|
+
client = boto3_session.client(
|
|
29
|
+
"ec2", region_name=region, config=get_botocore_config()
|
|
30
|
+
)
|
|
31
|
+
paginator = client.get_paginator("describe_launch_templates")
|
|
27
32
|
templates: list[dict[str, Any]] = []
|
|
28
33
|
for page in paginator.paginate():
|
|
29
|
-
paginated_templates = page[
|
|
34
|
+
paginated_templates = page["LaunchTemplates"]
|
|
30
35
|
templates.extend(paginated_templates)
|
|
31
36
|
return templates
|
|
32
37
|
|
|
@@ -40,8 +45,10 @@ def get_launch_template_versions(
|
|
|
40
45
|
) -> list[dict[str, Any]]:
|
|
41
46
|
template_versions: list[dict[str, Any]] = []
|
|
42
47
|
for template in launch_templates:
|
|
43
|
-
launch_template_id = template[
|
|
44
|
-
versions = get_launch_template_versions_by_template(
|
|
48
|
+
launch_template_id = template["LaunchTemplateId"]
|
|
49
|
+
versions = get_launch_template_versions_by_template(
|
|
50
|
+
boto3_session, launch_template_id, region
|
|
51
|
+
)
|
|
45
52
|
template_versions.extend(versions)
|
|
46
53
|
|
|
47
54
|
return template_versions
|
|
@@ -50,46 +57,54 @@ def get_launch_template_versions(
|
|
|
50
57
|
@timeit
|
|
51
58
|
@aws_handle_regions
|
|
52
59
|
def get_launch_template_versions_by_template(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
boto3_session: boto3.session.Session,
|
|
61
|
+
launch_template_id: str,
|
|
62
|
+
region: str,
|
|
56
63
|
) -> list[dict[str, Any]]:
|
|
57
|
-
client = boto3_session.client(
|
|
58
|
-
|
|
64
|
+
client = boto3_session.client(
|
|
65
|
+
"ec2", region_name=region, config=get_botocore_config()
|
|
66
|
+
)
|
|
67
|
+
v_paginator = client.get_paginator("describe_launch_template_versions")
|
|
59
68
|
template_versions = []
|
|
60
69
|
try:
|
|
61
70
|
for versions in v_paginator.paginate(LaunchTemplateId=launch_template_id):
|
|
62
|
-
template_versions.extend(versions[
|
|
71
|
+
template_versions.extend(versions["LaunchTemplateVersions"])
|
|
63
72
|
except botocore.exceptions.ClientError as e:
|
|
64
|
-
error_code = e.response[
|
|
65
|
-
if error_code ==
|
|
66
|
-
logger.warning(
|
|
73
|
+
error_code = e.response["Error"]["Code"]
|
|
74
|
+
if error_code == "InvalidLaunchTemplateId.NotFound":
|
|
75
|
+
logger.warning(
|
|
76
|
+
"Launch template %s no longer exists in region %s",
|
|
77
|
+
launch_template_id,
|
|
78
|
+
region,
|
|
79
|
+
)
|
|
67
80
|
else:
|
|
68
81
|
raise
|
|
69
82
|
return template_versions
|
|
70
83
|
|
|
71
84
|
|
|
72
|
-
def transform_launch_templates(
|
|
73
|
-
|
|
85
|
+
def transform_launch_templates(
|
|
86
|
+
templates: list[dict[str, Any]], versions: list[dict[str, Any]]
|
|
87
|
+
) -> list[dict[str, Any]]:
|
|
88
|
+
valid_template_ids = {v["LaunchTemplateId"] for v in versions}
|
|
74
89
|
result: list[dict[str, Any]] = []
|
|
75
90
|
for template in templates:
|
|
76
|
-
if template[
|
|
91
|
+
if template["LaunchTemplateId"] not in valid_template_ids:
|
|
77
92
|
continue
|
|
78
93
|
|
|
79
94
|
current = template.copy()
|
|
80
95
|
# Convert CreateTime to timestamp string
|
|
81
|
-
current[
|
|
96
|
+
current["CreateTime"] = str(int(current["CreateTime"].timestamp()))
|
|
82
97
|
result.append(current)
|
|
83
98
|
return result
|
|
84
99
|
|
|
85
100
|
|
|
86
101
|
@timeit
|
|
87
102
|
def load_launch_templates(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
neo4j_session: neo4j.Session,
|
|
104
|
+
data: list[dict[str, Any]],
|
|
105
|
+
region: str,
|
|
106
|
+
current_aws_account_id: str,
|
|
107
|
+
update_tag: int,
|
|
93
108
|
) -> None:
|
|
94
109
|
load(
|
|
95
110
|
neo4j_session,
|
|
@@ -101,41 +116,45 @@ def load_launch_templates(
|
|
|
101
116
|
)
|
|
102
117
|
|
|
103
118
|
|
|
104
|
-
def transform_launch_template_versions(
|
|
119
|
+
def transform_launch_template_versions(
|
|
120
|
+
versions: list[dict[str, Any]],
|
|
121
|
+
) -> list[dict[str, Any]]:
|
|
105
122
|
result: list[dict[str, Any]] = []
|
|
106
123
|
for version in versions:
|
|
107
124
|
current = version.copy()
|
|
108
125
|
|
|
109
126
|
# Reformat some fields
|
|
110
|
-
current[
|
|
111
|
-
current[
|
|
127
|
+
current["Id"] = f"{version['LaunchTemplateId']}-{version['VersionNumber']}"
|
|
128
|
+
current["CreateTime"] = str(int(version["CreateTime"].timestamp()))
|
|
112
129
|
|
|
113
130
|
# Handle the nested object returned from boto
|
|
114
|
-
ltd = version[
|
|
115
|
-
current[
|
|
116
|
-
current[
|
|
117
|
-
current[
|
|
118
|
-
current[
|
|
119
|
-
current[
|
|
120
|
-
current[
|
|
121
|
-
current[
|
|
122
|
-
current[
|
|
123
|
-
current[
|
|
124
|
-
current[
|
|
125
|
-
current[
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
ltd = version["LaunchTemplateData"]
|
|
132
|
+
current["KernelId"] = ltd.get("KernelId")
|
|
133
|
+
current["EbsOptimized"] = ltd.get("EbsOptimized")
|
|
134
|
+
current["IamInstanceProfileArn"] = ltd.get("IamInstanceProfileArn")
|
|
135
|
+
current["IamInstanceProfileName"] = ltd.get("IamInstanceProfileName")
|
|
136
|
+
current["ImageId"] = ltd.get("ImageId")
|
|
137
|
+
current["InstanceType"] = ltd.get("InstanceType")
|
|
138
|
+
current["KeyName"] = ltd.get("KeyName")
|
|
139
|
+
current["MonitoringEnabled"] = ltd.get("MonitoringEnabled")
|
|
140
|
+
current["RamdiskId"] = ltd.get("RamdiskId")
|
|
141
|
+
current["DisableApiTermination"] = ltd.get("DisableApiTermination")
|
|
142
|
+
current["InstanceInitiatedShutDownBehavior"] = ltd.get(
|
|
143
|
+
"InstanceInitiatedShutDownBehavior",
|
|
144
|
+
)
|
|
145
|
+
current["SecurityGroupIds"] = ltd.get("SecurityGroupIds")
|
|
146
|
+
current["SecurityGroups"] = ltd.get("SecurityGroups")
|
|
128
147
|
result.append(current)
|
|
129
148
|
return result
|
|
130
149
|
|
|
131
150
|
|
|
132
151
|
@timeit
|
|
133
152
|
def load_launch_template_versions(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
153
|
+
neo4j_session: neo4j.Session,
|
|
154
|
+
data: list[dict[str, Any]],
|
|
155
|
+
region: str,
|
|
156
|
+
current_aws_account_id: str,
|
|
157
|
+
update_tag: int,
|
|
139
158
|
) -> None:
|
|
140
159
|
load(
|
|
141
160
|
neo4j_session,
|
|
@@ -148,35 +167,58 @@ def load_launch_template_versions(
|
|
|
148
167
|
|
|
149
168
|
|
|
150
169
|
@timeit
|
|
151
|
-
def cleanup(
|
|
170
|
+
def cleanup(
|
|
171
|
+
neo4j_session: neo4j.Session,
|
|
172
|
+
common_job_parameters: dict[str, Any],
|
|
173
|
+
) -> None:
|
|
152
174
|
logger.info("Running launch template cleanup job.")
|
|
153
|
-
cleanup_job = GraphJob.from_node_schema(
|
|
175
|
+
cleanup_job = GraphJob.from_node_schema(
|
|
176
|
+
LaunchTemplateSchema(),
|
|
177
|
+
common_job_parameters,
|
|
178
|
+
)
|
|
154
179
|
cleanup_job.run(neo4j_session)
|
|
155
180
|
|
|
156
|
-
cleanup_job = GraphJob.from_node_schema(
|
|
181
|
+
cleanup_job = GraphJob.from_node_schema(
|
|
182
|
+
LaunchTemplateVersionSchema(),
|
|
183
|
+
common_job_parameters,
|
|
184
|
+
)
|
|
157
185
|
cleanup_job.run(neo4j_session)
|
|
158
186
|
|
|
159
187
|
|
|
160
188
|
@timeit
|
|
161
189
|
def sync_ec2_launch_templates(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
190
|
+
neo4j_session: neo4j.Session,
|
|
191
|
+
boto3_session: boto3.session.Session,
|
|
192
|
+
regions: list[str],
|
|
193
|
+
current_aws_account_id: str,
|
|
194
|
+
update_tag: int,
|
|
195
|
+
common_job_parameters: dict[str, Any],
|
|
168
196
|
) -> None:
|
|
169
197
|
for region in regions:
|
|
170
|
-
logger.info(
|
|
198
|
+
logger.info(
|
|
199
|
+
f"Syncing launch templates for region '{region}' in account '{current_aws_account_id}'."
|
|
200
|
+
)
|
|
171
201
|
templates = get_launch_templates(boto3_session, region)
|
|
172
202
|
versions = get_launch_template_versions(boto3_session, region, templates)
|
|
173
203
|
|
|
174
204
|
# Transform and load the templates that have versions
|
|
175
205
|
transformed_templates = transform_launch_templates(templates, versions)
|
|
176
|
-
load_launch_templates(
|
|
206
|
+
load_launch_templates(
|
|
207
|
+
neo4j_session,
|
|
208
|
+
transformed_templates,
|
|
209
|
+
region,
|
|
210
|
+
current_aws_account_id,
|
|
211
|
+
update_tag,
|
|
212
|
+
)
|
|
177
213
|
|
|
178
214
|
# Transform and load the versions
|
|
179
215
|
transformed_versions = transform_launch_template_versions(versions)
|
|
180
|
-
load_launch_template_versions(
|
|
216
|
+
load_launch_template_versions(
|
|
217
|
+
neo4j_session,
|
|
218
|
+
transformed_versions,
|
|
219
|
+
region,
|
|
220
|
+
current_aws_account_id,
|
|
221
|
+
update_tag,
|
|
222
|
+
)
|
|
181
223
|
|
|
182
224
|
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -6,38 +6,47 @@ import boto3
|
|
|
6
6
|
import botocore
|
|
7
7
|
import neo4j
|
|
8
8
|
|
|
9
|
-
from .util import get_botocore_config
|
|
10
9
|
from cartography.util import aws_handle_regions
|
|
11
10
|
from cartography.util import run_cleanup_job
|
|
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
|
|
|
17
18
|
@timeit
|
|
18
19
|
@aws_handle_regions
|
|
19
|
-
def get_load_balancer_v2_listeners(
|
|
20
|
-
|
|
20
|
+
def get_load_balancer_v2_listeners(
|
|
21
|
+
client: botocore.client.BaseClient,
|
|
22
|
+
load_balancer_arn: str,
|
|
23
|
+
) -> List[Dict]:
|
|
24
|
+
paginator = client.get_paginator("describe_listeners")
|
|
21
25
|
listeners: List[Dict] = []
|
|
22
26
|
for page in paginator.paginate(LoadBalancerArn=load_balancer_arn):
|
|
23
|
-
listeners.extend(page[
|
|
27
|
+
listeners.extend(page["Listeners"])
|
|
24
28
|
|
|
25
29
|
return listeners
|
|
26
30
|
|
|
27
31
|
|
|
28
32
|
@timeit
|
|
29
|
-
def get_load_balancer_v2_target_groups(
|
|
30
|
-
|
|
33
|
+
def get_load_balancer_v2_target_groups(
|
|
34
|
+
client: botocore.client.BaseClient,
|
|
35
|
+
load_balancer_arn: str,
|
|
36
|
+
) -> List[Dict]:
|
|
37
|
+
paginator = client.get_paginator("describe_target_groups")
|
|
31
38
|
target_groups: List[Dict] = []
|
|
32
39
|
for page in paginator.paginate(LoadBalancerArn=load_balancer_arn):
|
|
33
|
-
target_groups.extend(page[
|
|
40
|
+
target_groups.extend(page["TargetGroups"])
|
|
34
41
|
|
|
35
42
|
# Add instance data
|
|
36
43
|
for target_group in target_groups:
|
|
37
|
-
target_group[
|
|
38
|
-
target_health = client.describe_target_health(
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
target_group["Targets"] = []
|
|
45
|
+
target_health = client.describe_target_health(
|
|
46
|
+
TargetGroupArn=target_group["TargetGroupArn"],
|
|
47
|
+
)
|
|
48
|
+
for target_health_description in target_health["TargetHealthDescriptions"]:
|
|
49
|
+
target_group["Targets"].append(target_health_description["Target"]["Id"])
|
|
41
50
|
|
|
42
51
|
return target_groups
|
|
43
52
|
|
|
@@ -45,22 +54,35 @@ def get_load_balancer_v2_target_groups(client: botocore.client.BaseClient, load_
|
|
|
45
54
|
@timeit
|
|
46
55
|
@aws_handle_regions
|
|
47
56
|
def get_loadbalancer_v2_data(boto3_session: boto3.Session, region: str) -> List[Dict]:
|
|
48
|
-
client = boto3_session.client(
|
|
49
|
-
|
|
57
|
+
client = boto3_session.client(
|
|
58
|
+
"elbv2",
|
|
59
|
+
region_name=region,
|
|
60
|
+
config=get_botocore_config(),
|
|
61
|
+
)
|
|
62
|
+
paginator = client.get_paginator("describe_load_balancers")
|
|
50
63
|
elbv2s: List[Dict] = []
|
|
51
64
|
for page in paginator.paginate():
|
|
52
|
-
elbv2s.extend(page[
|
|
65
|
+
elbv2s.extend(page["LoadBalancers"])
|
|
53
66
|
|
|
54
67
|
# Make extra calls to get listeners
|
|
55
68
|
for elbv2 in elbv2s:
|
|
56
|
-
elbv2[
|
|
57
|
-
|
|
69
|
+
elbv2["Listeners"] = get_load_balancer_v2_listeners(
|
|
70
|
+
client,
|
|
71
|
+
elbv2["LoadBalancerArn"],
|
|
72
|
+
)
|
|
73
|
+
elbv2["TargetGroups"] = get_load_balancer_v2_target_groups(
|
|
74
|
+
client,
|
|
75
|
+
elbv2["LoadBalancerArn"],
|
|
76
|
+
)
|
|
58
77
|
return elbv2s
|
|
59
78
|
|
|
60
79
|
|
|
61
80
|
@timeit
|
|
62
81
|
def load_load_balancer_v2s(
|
|
63
|
-
neo4j_session: neo4j.Session,
|
|
82
|
+
neo4j_session: neo4j.Session,
|
|
83
|
+
data: List[Dict],
|
|
84
|
+
region: str,
|
|
85
|
+
current_aws_account_id: str,
|
|
64
86
|
update_tag: int,
|
|
65
87
|
) -> None:
|
|
66
88
|
ingest_load_balancer_v2 = """
|
|
@@ -95,10 +117,16 @@ def load_load_balancer_v2s(
|
|
|
95
117
|
|
|
96
118
|
if lb["AvailabilityZones"]:
|
|
97
119
|
az = lb["AvailabilityZones"]
|
|
98
|
-
load_load_balancer_v2_subnets(
|
|
120
|
+
load_load_balancer_v2_subnets(
|
|
121
|
+
neo4j_session,
|
|
122
|
+
load_balancer_id,
|
|
123
|
+
az,
|
|
124
|
+
region,
|
|
125
|
+
update_tag,
|
|
126
|
+
)
|
|
99
127
|
|
|
100
128
|
# NLB's don't have SecurityGroups, so check for one first.
|
|
101
|
-
if
|
|
129
|
+
if "SecurityGroups" in lb and lb["SecurityGroups"]:
|
|
102
130
|
ingest_load_balancer_v2_security_group = """
|
|
103
131
|
MATCH (elbv2:LoadBalancerV2{id: $ID}),
|
|
104
132
|
(group:EC2SecurityGroup{groupid: $GROUP_ID})
|
|
@@ -114,20 +142,31 @@ def load_load_balancer_v2s(
|
|
|
114
142
|
update_tag=update_tag,
|
|
115
143
|
)
|
|
116
144
|
|
|
117
|
-
if lb[
|
|
118
|
-
load_load_balancer_v2_listeners(
|
|
145
|
+
if lb["Listeners"]:
|
|
146
|
+
load_load_balancer_v2_listeners(
|
|
147
|
+
neo4j_session,
|
|
148
|
+
load_balancer_id,
|
|
149
|
+
lb["Listeners"],
|
|
150
|
+
update_tag,
|
|
151
|
+
)
|
|
119
152
|
|
|
120
|
-
if lb[
|
|
153
|
+
if lb["TargetGroups"]:
|
|
121
154
|
load_load_balancer_v2_target_groups(
|
|
122
|
-
neo4j_session,
|
|
123
|
-
|
|
155
|
+
neo4j_session,
|
|
156
|
+
load_balancer_id,
|
|
157
|
+
lb["TargetGroups"],
|
|
158
|
+
current_aws_account_id,
|
|
159
|
+
update_tag,
|
|
124
160
|
)
|
|
125
161
|
|
|
126
162
|
|
|
127
163
|
@timeit
|
|
128
164
|
def load_load_balancer_v2_subnets(
|
|
129
|
-
neo4j_session: neo4j.Session,
|
|
130
|
-
|
|
165
|
+
neo4j_session: neo4j.Session,
|
|
166
|
+
load_balancer_id: str,
|
|
167
|
+
az_data: List[Dict],
|
|
168
|
+
region: str,
|
|
169
|
+
update_tag: int,
|
|
131
170
|
) -> None:
|
|
132
171
|
ingest_load_balancer_subnet = """
|
|
133
172
|
MATCH (elbv2:LoadBalancerV2{id: $ID})
|
|
@@ -143,7 +182,7 @@ def load_load_balancer_v2_subnets(
|
|
|
143
182
|
neo4j_session.run(
|
|
144
183
|
ingest_load_balancer_subnet,
|
|
145
184
|
ID=load_balancer_id,
|
|
146
|
-
SubnetId=az[
|
|
185
|
+
SubnetId=az["SubnetId"],
|
|
147
186
|
region=region,
|
|
148
187
|
update_tag=update_tag,
|
|
149
188
|
)
|
|
@@ -151,7 +190,10 @@ def load_load_balancer_v2_subnets(
|
|
|
151
190
|
|
|
152
191
|
@timeit
|
|
153
192
|
def load_load_balancer_v2_target_groups(
|
|
154
|
-
neo4j_session: neo4j.Session,
|
|
193
|
+
neo4j_session: neo4j.Session,
|
|
194
|
+
load_balancer_id: str,
|
|
195
|
+
target_groups: List[Dict],
|
|
196
|
+
current_aws_account_id: str,
|
|
155
197
|
update_tag: int,
|
|
156
198
|
) -> None:
|
|
157
199
|
ingest_instances = """
|
|
@@ -169,7 +211,7 @@ def load_load_balancer_v2_target_groups(
|
|
|
169
211
|
"""
|
|
170
212
|
for target_group in target_groups:
|
|
171
213
|
|
|
172
|
-
if not target_group[
|
|
214
|
+
if not target_group["TargetType"] == "instance":
|
|
173
215
|
# Only working on EC2 Instances now. TODO: Add IP & Lambda EXPOSE.
|
|
174
216
|
continue
|
|
175
217
|
|
|
@@ -179,16 +221,18 @@ def load_load_balancer_v2_target_groups(
|
|
|
179
221
|
ID=load_balancer_id,
|
|
180
222
|
INSTANCE_ID=instance,
|
|
181
223
|
AWS_ACCOUNT_ID=current_aws_account_id,
|
|
182
|
-
TARGET_GROUP_ARN=target_group.get(
|
|
183
|
-
PORT=target_group.get(
|
|
184
|
-
PROTOCOL=target_group.get(
|
|
224
|
+
TARGET_GROUP_ARN=target_group.get("TargetGroupArn"),
|
|
225
|
+
PORT=target_group.get("Port"),
|
|
226
|
+
PROTOCOL=target_group.get("Protocol"),
|
|
185
227
|
update_tag=update_tag,
|
|
186
228
|
)
|
|
187
229
|
|
|
188
230
|
|
|
189
231
|
@timeit
|
|
190
232
|
def load_load_balancer_v2_listeners(
|
|
191
|
-
neo4j_session: neo4j.Session,
|
|
233
|
+
neo4j_session: neo4j.Session,
|
|
234
|
+
load_balancer_id: str,
|
|
235
|
+
listener_data: List[Dict],
|
|
192
236
|
update_tag: int,
|
|
193
237
|
) -> None:
|
|
194
238
|
ingest_listener = """
|
|
@@ -215,18 +259,39 @@ def load_load_balancer_v2_listeners(
|
|
|
215
259
|
|
|
216
260
|
|
|
217
261
|
@timeit
|
|
218
|
-
def cleanup_load_balancer_v2s(
|
|
262
|
+
def cleanup_load_balancer_v2s(
|
|
263
|
+
neo4j_session: neo4j.Session,
|
|
264
|
+
common_job_parameters: Dict,
|
|
265
|
+
) -> None:
|
|
219
266
|
"""Delete elbv2's and dependent resources in the DB without the most recent lastupdated tag."""
|
|
220
|
-
run_cleanup_job(
|
|
267
|
+
run_cleanup_job(
|
|
268
|
+
"aws_ingest_load_balancers_v2_cleanup.json",
|
|
269
|
+
neo4j_session,
|
|
270
|
+
common_job_parameters,
|
|
271
|
+
)
|
|
221
272
|
|
|
222
273
|
|
|
223
274
|
@timeit
|
|
224
275
|
def sync_load_balancer_v2s(
|
|
225
|
-
neo4j_session: neo4j.Session,
|
|
226
|
-
|
|
276
|
+
neo4j_session: neo4j.Session,
|
|
277
|
+
boto3_session: boto3.session.Session,
|
|
278
|
+
regions: List[str],
|
|
279
|
+
current_aws_account_id: str,
|
|
280
|
+
update_tag: int,
|
|
281
|
+
common_job_parameters: Dict,
|
|
227
282
|
) -> None:
|
|
228
283
|
for region in regions:
|
|
229
|
-
logger.info(
|
|
284
|
+
logger.info(
|
|
285
|
+
"Syncing EC2 load balancers v2 for region '%s' in account '%s'.",
|
|
286
|
+
region,
|
|
287
|
+
current_aws_account_id,
|
|
288
|
+
)
|
|
230
289
|
data = get_loadbalancer_v2_data(boto3_session, region)
|
|
231
|
-
load_load_balancer_v2s(
|
|
290
|
+
load_load_balancer_v2s(
|
|
291
|
+
neo4j_session,
|
|
292
|
+
data,
|
|
293
|
+
region,
|
|
294
|
+
current_aws_account_id,
|
|
295
|
+
update_tag,
|
|
296
|
+
)
|
|
232
297
|
cleanup_load_balancer_v2s(neo4j_session, common_job_parameters)
|