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
|
@@ -10,10 +10,8 @@ import boto3
|
|
|
10
10
|
import botocore.exceptions
|
|
11
11
|
import neo4j
|
|
12
12
|
|
|
13
|
-
from . import ec2
|
|
14
|
-
from . import organizations
|
|
15
|
-
from .resources import RESOURCE_FUNCTIONS
|
|
16
13
|
from cartography.config import Config
|
|
14
|
+
from cartography.intel.aws.util.common import parse_and_validate_aws_regions
|
|
17
15
|
from cartography.intel.aws.util.common import parse_and_validate_aws_requested_syncs
|
|
18
16
|
from cartography.stats import get_stats_client
|
|
19
17
|
from cartography.util import merge_module_sync_metadata
|
|
@@ -23,22 +21,29 @@ from cartography.util import run_cleanup_job
|
|
|
23
21
|
from cartography.util import run_scoped_analysis_job
|
|
24
22
|
from cartography.util import timeit
|
|
25
23
|
|
|
24
|
+
from . import ec2
|
|
25
|
+
from . import organizations
|
|
26
|
+
from .resources import RESOURCE_FUNCTIONS
|
|
26
27
|
|
|
27
28
|
stat_handler = get_stats_client(__name__)
|
|
28
29
|
logger = logging.getLogger(__name__)
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def _build_aws_sync_kwargs(
|
|
32
|
-
neo4j_session: neo4j.Session,
|
|
33
|
-
|
|
33
|
+
neo4j_session: neo4j.Session,
|
|
34
|
+
boto3_session: boto3.session.Session,
|
|
35
|
+
regions: List[str],
|
|
36
|
+
current_aws_account_id: str,
|
|
37
|
+
sync_tag: int,
|
|
38
|
+
common_job_parameters: Dict[str, Any],
|
|
34
39
|
) -> Dict[str, Any]:
|
|
35
40
|
return {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
"neo4j_session": neo4j_session,
|
|
42
|
+
"boto3_session": boto3_session,
|
|
43
|
+
"regions": regions,
|
|
44
|
+
"current_aws_account_id": current_aws_account_id,
|
|
45
|
+
"update_tag": sync_tag,
|
|
46
|
+
"common_job_parameters": common_job_parameters,
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
|
|
@@ -48,57 +53,71 @@ def _sync_one_account(
|
|
|
48
53
|
current_aws_account_id: str,
|
|
49
54
|
update_tag: int,
|
|
50
55
|
common_job_parameters: Dict[str, Any],
|
|
51
|
-
regions:
|
|
56
|
+
regions: list[str] | None = None,
|
|
52
57
|
aws_requested_syncs: Iterable[str] = RESOURCE_FUNCTIONS.keys(),
|
|
53
58
|
) -> None:
|
|
59
|
+
# Autodiscover the regions supported by the account unless the user has specified the regions to sync.
|
|
54
60
|
if not regions:
|
|
55
61
|
regions = _autodiscover_account_regions(boto3_session, current_aws_account_id)
|
|
56
62
|
|
|
57
63
|
sync_args = _build_aws_sync_kwargs(
|
|
58
|
-
neo4j_session,
|
|
64
|
+
neo4j_session,
|
|
65
|
+
boto3_session,
|
|
66
|
+
regions,
|
|
67
|
+
current_aws_account_id,
|
|
68
|
+
update_tag,
|
|
69
|
+
common_job_parameters,
|
|
59
70
|
)
|
|
60
71
|
|
|
61
72
|
for func_name in aws_requested_syncs:
|
|
62
73
|
if func_name in RESOURCE_FUNCTIONS:
|
|
63
74
|
# Skip permission relationships and tags for now because they rely on data already being in the graph
|
|
64
|
-
if func_name not in [
|
|
75
|
+
if func_name not in [
|
|
76
|
+
"permission_relationships",
|
|
77
|
+
"resourcegroupstaggingapi",
|
|
78
|
+
]:
|
|
65
79
|
RESOURCE_FUNCTIONS[func_name](**sync_args)
|
|
66
80
|
else:
|
|
67
81
|
continue
|
|
68
82
|
else:
|
|
69
|
-
raise ValueError(
|
|
83
|
+
raise ValueError(
|
|
84
|
+
f'AWS sync function "{func_name}" was specified but does not exist. Did you misspell it?',
|
|
85
|
+
)
|
|
70
86
|
|
|
71
87
|
# MAP IAM permissions
|
|
72
|
-
if
|
|
73
|
-
RESOURCE_FUNCTIONS[
|
|
88
|
+
if "permission_relationships" in aws_requested_syncs:
|
|
89
|
+
RESOURCE_FUNCTIONS["permission_relationships"](**sync_args)
|
|
74
90
|
|
|
75
91
|
# AWS Tags - Must always be last.
|
|
76
|
-
if
|
|
77
|
-
RESOURCE_FUNCTIONS[
|
|
92
|
+
if "resourcegroupstaggingapi" in aws_requested_syncs:
|
|
93
|
+
RESOURCE_FUNCTIONS["resourcegroupstaggingapi"](**sync_args)
|
|
78
94
|
|
|
79
95
|
run_scoped_analysis_job(
|
|
80
|
-
|
|
96
|
+
"aws_ec2_iaminstanceprofile.json",
|
|
81
97
|
neo4j_session,
|
|
82
98
|
common_job_parameters,
|
|
83
99
|
)
|
|
84
100
|
|
|
85
101
|
run_analysis_job(
|
|
86
|
-
|
|
102
|
+
"aws_lambda_ecr.json",
|
|
87
103
|
neo4j_session,
|
|
88
104
|
common_job_parameters,
|
|
89
105
|
)
|
|
90
106
|
|
|
91
107
|
merge_module_sync_metadata(
|
|
92
108
|
neo4j_session,
|
|
93
|
-
group_type=
|
|
109
|
+
group_type="AWSAccount",
|
|
94
110
|
group_id=current_aws_account_id,
|
|
95
|
-
synced_type=
|
|
111
|
+
synced_type="AWSAccount",
|
|
96
112
|
update_tag=update_tag,
|
|
97
113
|
stat_handler=stat_handler,
|
|
98
114
|
)
|
|
99
115
|
|
|
100
116
|
|
|
101
|
-
def _autodiscover_account_regions(
|
|
117
|
+
def _autodiscover_account_regions(
|
|
118
|
+
boto3_session: boto3.session.Session,
|
|
119
|
+
account_id: str,
|
|
120
|
+
) -> List[str]:
|
|
102
121
|
regions: List[str] = []
|
|
103
122
|
try:
|
|
104
123
|
regions = ec2.get_ec2_regions(boto3_session)
|
|
@@ -116,27 +135,39 @@ def _autodiscover_account_regions(boto3_session: boto3.session.Session, account_
|
|
|
116
135
|
|
|
117
136
|
|
|
118
137
|
def _autodiscover_accounts(
|
|
119
|
-
neo4j_session: neo4j.Session,
|
|
120
|
-
|
|
138
|
+
neo4j_session: neo4j.Session,
|
|
139
|
+
boto3_session: boto3.session.Session,
|
|
140
|
+
account_id: str,
|
|
141
|
+
sync_tag: int,
|
|
142
|
+
common_job_parameters: Dict,
|
|
121
143
|
) -> None:
|
|
122
144
|
logger.info("Trying to autodiscover accounts.")
|
|
123
145
|
try:
|
|
124
146
|
# Fetch all accounts
|
|
125
|
-
client = boto3_session.client(
|
|
126
|
-
paginator = client.get_paginator(
|
|
147
|
+
client = boto3_session.client("organizations")
|
|
148
|
+
paginator = client.get_paginator("list_accounts")
|
|
127
149
|
accounts: List[Dict] = []
|
|
128
150
|
for page in paginator.paginate():
|
|
129
|
-
accounts.extend(page[
|
|
151
|
+
accounts.extend(page["Accounts"])
|
|
130
152
|
|
|
131
153
|
# Filter out every account which is not in the ACTIVE status
|
|
132
154
|
# and select only the Id and Name fields
|
|
133
|
-
filtered_accounts: Dict[str, str] = {
|
|
155
|
+
filtered_accounts: Dict[str, str] = {
|
|
156
|
+
x["Name"]: x["Id"] for x in accounts if x["Status"] == "ACTIVE"
|
|
157
|
+
}
|
|
134
158
|
|
|
135
159
|
# Add them to the graph
|
|
136
160
|
logger.info("Loading autodiscovered accounts.")
|
|
137
|
-
organizations.load_aws_accounts(
|
|
161
|
+
organizations.load_aws_accounts(
|
|
162
|
+
neo4j_session,
|
|
163
|
+
filtered_accounts,
|
|
164
|
+
sync_tag,
|
|
165
|
+
common_job_parameters,
|
|
166
|
+
)
|
|
138
167
|
except botocore.exceptions.ClientError:
|
|
139
|
-
logger.warning(
|
|
168
|
+
logger.warning(
|
|
169
|
+
f"The current account ({account_id}) doesn't have enough permissions to perform autodiscovery.",
|
|
170
|
+
)
|
|
140
171
|
|
|
141
172
|
|
|
142
173
|
def _sync_multiple_accounts(
|
|
@@ -146,8 +177,9 @@ def _sync_multiple_accounts(
|
|
|
146
177
|
common_job_parameters: Dict[str, Any],
|
|
147
178
|
aws_best_effort_mode: bool,
|
|
148
179
|
aws_requested_syncs: List[str] = [],
|
|
180
|
+
regions: list[str] | None = None,
|
|
149
181
|
) -> bool:
|
|
150
|
-
logger.info("Syncing AWS accounts: %s",
|
|
182
|
+
logger.info("Syncing AWS accounts: %s", ", ".join(accounts.values()))
|
|
151
183
|
organizations.sync(neo4j_session, accounts, sync_tag, common_job_parameters)
|
|
152
184
|
|
|
153
185
|
failed_account_ids = []
|
|
@@ -156,7 +188,11 @@ def _sync_multiple_accounts(
|
|
|
156
188
|
num_accounts = len(accounts)
|
|
157
189
|
|
|
158
190
|
for profile_name, account_id in accounts.items():
|
|
159
|
-
logger.info(
|
|
191
|
+
logger.info(
|
|
192
|
+
"Syncing AWS account with ID '%s' using configured profile '%s'.",
|
|
193
|
+
account_id,
|
|
194
|
+
profile_name,
|
|
195
|
+
)
|
|
160
196
|
common_job_parameters["AWS_ID"] = account_id
|
|
161
197
|
if num_accounts == 1:
|
|
162
198
|
# Use the default boto3 session because boto3 gets confused if you give it a profile name with 1 account
|
|
@@ -164,7 +200,13 @@ def _sync_multiple_accounts(
|
|
|
164
200
|
else:
|
|
165
201
|
boto3_session = boto3.Session(profile_name=profile_name)
|
|
166
202
|
|
|
167
|
-
_autodiscover_accounts(
|
|
203
|
+
_autodiscover_accounts(
|
|
204
|
+
neo4j_session,
|
|
205
|
+
boto3_session,
|
|
206
|
+
account_id,
|
|
207
|
+
sync_tag,
|
|
208
|
+
common_job_parameters,
|
|
209
|
+
)
|
|
168
210
|
|
|
169
211
|
try:
|
|
170
212
|
_sync_one_account(
|
|
@@ -173,6 +215,7 @@ def _sync_multiple_accounts(
|
|
|
173
215
|
account_id,
|
|
174
216
|
sync_tag,
|
|
175
217
|
common_job_parameters,
|
|
218
|
+
regions=regions,
|
|
176
219
|
aws_requested_syncs=aws_requested_syncs, # Could be replaced later with per-account requested syncs
|
|
177
220
|
)
|
|
178
221
|
except Exception as e:
|
|
@@ -180,8 +223,10 @@ def _sync_multiple_accounts(
|
|
|
180
223
|
timestamp = datetime.datetime.now()
|
|
181
224
|
failed_account_ids.append(account_id)
|
|
182
225
|
exception_traceback = traceback.TracebackException.from_exception(e)
|
|
183
|
-
traceback_string =
|
|
184
|
-
exception_tracebacks.append(
|
|
226
|
+
traceback_string = "".join(exception_traceback.format())
|
|
227
|
+
exception_tracebacks.append(
|
|
228
|
+
f"{timestamp} - Exception for account ID: {account_id}\n{traceback_string}",
|
|
229
|
+
)
|
|
185
230
|
logger.warning(
|
|
186
231
|
f"Caught exception syncing account {account_id}. aws-best-effort-mode is on so we are continuing "
|
|
187
232
|
f"on to the next AWS account. All exceptions will be aggregated and re-logged at the end of the "
|
|
@@ -193,24 +238,28 @@ def _sync_multiple_accounts(
|
|
|
193
238
|
raise
|
|
194
239
|
|
|
195
240
|
if failed_account_ids:
|
|
196
|
-
logger.error(f
|
|
197
|
-
raise Exception(
|
|
241
|
+
logger.error(f"AWS sync failed for accounts {failed_account_ids}")
|
|
242
|
+
raise Exception("\n".join(exception_tracebacks))
|
|
198
243
|
|
|
199
244
|
del common_job_parameters["AWS_ID"]
|
|
200
245
|
|
|
201
246
|
# There may be orphan Principals which point outside of known AWS accounts. This job cleans
|
|
202
247
|
# up those nodes after all AWS accounts have been synced.
|
|
203
248
|
if not failed_account_ids:
|
|
204
|
-
run_cleanup_job(
|
|
249
|
+
run_cleanup_job(
|
|
250
|
+
"aws_post_ingestion_principals_cleanup.json",
|
|
251
|
+
neo4j_session,
|
|
252
|
+
common_job_parameters,
|
|
253
|
+
)
|
|
205
254
|
return True
|
|
206
255
|
return False
|
|
207
256
|
|
|
208
257
|
|
|
209
258
|
@timeit
|
|
210
259
|
def _perform_aws_analysis(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
260
|
+
requested_syncs: List[str],
|
|
261
|
+
neo4j_session: neo4j.Session,
|
|
262
|
+
common_job_parameters: Dict[str, Any],
|
|
214
263
|
) -> None:
|
|
215
264
|
"""
|
|
216
265
|
Performs AWS analysis jobs that span multiple accounts.
|
|
@@ -218,13 +267,13 @@ def _perform_aws_analysis(
|
|
|
218
267
|
requested_syncs_as_set = set(requested_syncs)
|
|
219
268
|
|
|
220
269
|
ec2_asset_exposure_requirements = {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
270
|
+
"ec2:instance",
|
|
271
|
+
"ec2:security_group",
|
|
272
|
+
"ec2:load_balancer",
|
|
273
|
+
"ec2:load_balancer_v2",
|
|
225
274
|
}
|
|
226
275
|
run_analysis_and_ensure_deps(
|
|
227
|
-
|
|
276
|
+
"aws_ec2_asset_exposure.json",
|
|
228
277
|
ec2_asset_exposure_requirements,
|
|
229
278
|
requested_syncs_as_set,
|
|
230
279
|
common_job_parameters,
|
|
@@ -232,23 +281,23 @@ def _perform_aws_analysis(
|
|
|
232
281
|
)
|
|
233
282
|
|
|
234
283
|
run_analysis_and_ensure_deps(
|
|
235
|
-
|
|
236
|
-
{
|
|
284
|
+
"aws_ec2_keypair_analysis.json",
|
|
285
|
+
{"ec2:keypair"},
|
|
237
286
|
requested_syncs_as_set,
|
|
238
287
|
common_job_parameters,
|
|
239
288
|
neo4j_session,
|
|
240
289
|
)
|
|
241
290
|
|
|
242
291
|
run_analysis_and_ensure_deps(
|
|
243
|
-
|
|
244
|
-
{
|
|
292
|
+
"aws_eks_asset_exposure.json",
|
|
293
|
+
{"eks"},
|
|
245
294
|
requested_syncs_as_set,
|
|
246
295
|
common_job_parameters,
|
|
247
296
|
neo4j_session,
|
|
248
297
|
)
|
|
249
298
|
|
|
250
299
|
run_analysis_and_ensure_deps(
|
|
251
|
-
|
|
300
|
+
"aws_foreign_accounts.json",
|
|
252
301
|
set(), # This job has no requirements
|
|
253
302
|
requested_syncs_as_set,
|
|
254
303
|
common_job_parameters,
|
|
@@ -277,7 +326,9 @@ def start_aws_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
|
277
326
|
return
|
|
278
327
|
|
|
279
328
|
if config.aws_sync_all_profiles:
|
|
280
|
-
aws_accounts = organizations.get_aws_accounts_from_botocore_config(
|
|
329
|
+
aws_accounts = organizations.get_aws_accounts_from_botocore_config(
|
|
330
|
+
boto3_session,
|
|
331
|
+
)
|
|
281
332
|
else:
|
|
282
333
|
aws_accounts = organizations.get_aws_account_default(boto3_session)
|
|
283
334
|
|
|
@@ -297,7 +348,14 @@ def start_aws_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
|
297
348
|
|
|
298
349
|
requested_syncs: List[str] = list(RESOURCE_FUNCTIONS.keys())
|
|
299
350
|
if config.aws_requested_syncs:
|
|
300
|
-
requested_syncs = parse_and_validate_aws_requested_syncs(
|
|
351
|
+
requested_syncs = parse_and_validate_aws_requested_syncs(
|
|
352
|
+
config.aws_requested_syncs,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if config.aws_regions:
|
|
356
|
+
regions = parse_and_validate_aws_regions(config.aws_regions)
|
|
357
|
+
else:
|
|
358
|
+
regions = None
|
|
301
359
|
|
|
302
360
|
sync_successful = _sync_multiple_accounts(
|
|
303
361
|
neo4j_session,
|
|
@@ -306,6 +364,7 @@ def start_aws_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
|
306
364
|
common_job_parameters,
|
|
307
365
|
config.aws_best_effort_mode,
|
|
308
366
|
requested_syncs,
|
|
367
|
+
regions=regions,
|
|
309
368
|
)
|
|
310
369
|
|
|
311
370
|
if sync_successful:
|