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
cartography/intel/jamf/util.py
CHANGED
|
@@ -12,14 +12,19 @@ _TIMEOUT = (60, 60)
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@timeit
|
|
15
|
-
def call_jamf_api(
|
|
15
|
+
def call_jamf_api(
|
|
16
|
+
api_and_parameters: str,
|
|
17
|
+
jamf_base_uri: str,
|
|
18
|
+
jamf_user: str,
|
|
19
|
+
jamf_password: str,
|
|
20
|
+
) -> List[Dict]:
|
|
16
21
|
uri = jamf_base_uri + api_and_parameters
|
|
17
22
|
jamf_auth = requests.auth.HTTPBasicAuth(jamf_user, jamf_password)
|
|
18
23
|
try:
|
|
19
24
|
response = requests.get(
|
|
20
25
|
uri,
|
|
21
26
|
auth=jamf_auth,
|
|
22
|
-
headers={
|
|
27
|
+
headers={"Accept": "application/json"},
|
|
23
28
|
timeout=_TIMEOUT,
|
|
24
29
|
)
|
|
25
30
|
except requests.exceptions.Timeout:
|
|
@@ -19,10 +19,13 @@ def start_kandji_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
|
|
|
19
19
|
|
|
20
20
|
:return: None
|
|
21
21
|
"""
|
|
22
|
-
if
|
|
22
|
+
if (
|
|
23
|
+
config.kandji_base_uri is None
|
|
24
|
+
or config.kandji_token is None
|
|
25
|
+
or config.kandji_tenant_id is None
|
|
26
|
+
):
|
|
23
27
|
logger.warning(
|
|
24
|
-
|
|
25
|
-
'See docs to configure.',
|
|
28
|
+
"Required parameter missing. Skipping sync. " "See docs to configure.",
|
|
26
29
|
)
|
|
27
30
|
return
|
|
28
31
|
|
|
@@ -12,7 +12,6 @@ from cartography.models.kandji.device import KandjiDeviceSchema
|
|
|
12
12
|
from cartography.models.kandji.tenant import KandjiTenantSchema
|
|
13
13
|
from cartography.util import timeit
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
logger = logging.getLogger(__name__)
|
|
17
16
|
_TIMEOUT = (60, 60)
|
|
18
17
|
|
|
@@ -21,8 +20,8 @@ _TIMEOUT = (60, 60)
|
|
|
21
20
|
def get(kandji_base_uri: str, kandji_token: str) -> List[Dict[str, Any]]:
|
|
22
21
|
api_endpoint = f"{kandji_base_uri}/api/v1/devices"
|
|
23
22
|
headers = {
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
"Accept": "application/json",
|
|
24
|
+
"Authorization": f"Bearer {kandji_token}",
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
offset = 0
|
|
@@ -39,7 +38,9 @@ def get(kandji_base_uri: str, kandji_token: str) -> List[Dict[str, Any]]:
|
|
|
39
38
|
logger.debug("Kandji device offset: %s", offset)
|
|
40
39
|
|
|
41
40
|
params["offset"] = offset
|
|
42
|
-
response = session.get(
|
|
41
|
+
response = session.get(
|
|
42
|
+
api_endpoint, headers=headers, timeout=_TIMEOUT, params=params
|
|
43
|
+
)
|
|
43
44
|
response.raise_for_status()
|
|
44
45
|
|
|
45
46
|
result = response.json()
|
|
@@ -60,7 +61,7 @@ def transform(api_result: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
|
60
61
|
result: List[Dict[str, Any]] = []
|
|
61
62
|
for device in api_result:
|
|
62
63
|
n_device = device
|
|
63
|
-
n_device[
|
|
64
|
+
n_device["id"] = device["device_id"]
|
|
64
65
|
result.append(n_device)
|
|
65
66
|
return result
|
|
66
67
|
|
|
@@ -78,7 +79,7 @@ def load_devices(
|
|
|
78
79
|
load(
|
|
79
80
|
neo4j_session,
|
|
80
81
|
KandjiTenantSchema(),
|
|
81
|
-
[{
|
|
82
|
+
[{"id": tenant_id}],
|
|
82
83
|
lastupdated=update_tag,
|
|
83
84
|
)
|
|
84
85
|
|
|
@@ -91,8 +92,13 @@ def load_devices(
|
|
|
91
92
|
)
|
|
92
93
|
|
|
93
94
|
|
|
94
|
-
def cleanup(
|
|
95
|
-
|
|
95
|
+
def cleanup(
|
|
96
|
+
neo4j_session: neo4j.Session,
|
|
97
|
+
common_job_parameters: Dict[str, Any],
|
|
98
|
+
) -> None:
|
|
99
|
+
GraphJob.from_node_schema(KandjiDeviceSchema(), common_job_parameters).run(
|
|
100
|
+
neo4j_session,
|
|
101
|
+
)
|
|
96
102
|
|
|
97
103
|
|
|
98
104
|
@timeit
|
|
@@ -21,9 +21,9 @@ def sync_namespaces(session: Session, client: K8sClient, update_tag: int) -> Dic
|
|
|
21
21
|
load_namespaces(session, cluster, namespaces, update_tag)
|
|
22
22
|
merge_module_sync_metadata(
|
|
23
23
|
session,
|
|
24
|
-
group_type=
|
|
25
|
-
group_id=cluster[
|
|
26
|
-
synced_type=
|
|
24
|
+
group_type="KubernetesCluster",
|
|
25
|
+
group_id=cluster["uid"],
|
|
26
|
+
synced_type="KubernetesCluster",
|
|
27
27
|
update_tag=update_tag,
|
|
28
28
|
stat_handler=stat_handler,
|
|
29
29
|
)
|
|
@@ -49,7 +49,10 @@ def get_namespaces(client: K8sClient) -> Tuple[Dict, List[Dict]]:
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def load_namespaces(
|
|
52
|
-
session: Session,
|
|
52
|
+
session: Session,
|
|
53
|
+
cluster: Dict,
|
|
54
|
+
data: List[Dict],
|
|
55
|
+
update_tag: int,
|
|
53
56
|
) -> None:
|
|
54
57
|
ingestion_cypher_query = """
|
|
55
58
|
MERGE (cluster:KubernetesCluster {id: $cluster_id})
|
|
@@ -13,7 +13,10 @@ logger = logging.getLogger(__name__)
|
|
|
13
13
|
|
|
14
14
|
@timeit
|
|
15
15
|
def sync_pods(
|
|
16
|
-
session: Session,
|
|
16
|
+
session: Session,
|
|
17
|
+
client: K8sClient,
|
|
18
|
+
update_tag: int,
|
|
19
|
+
cluster: Dict,
|
|
17
20
|
) -> List[Dict]:
|
|
18
21
|
pods = get_pods(client, cluster)
|
|
19
22
|
load_pods(session, pods, update_tag)
|
|
@@ -34,11 +37,11 @@ def get_pods(client: K8sClient, cluster: Dict) -> List[Dict]:
|
|
|
34
37
|
if pod.status and pod.status.container_statuses:
|
|
35
38
|
for status in pod.status.container_statuses:
|
|
36
39
|
if status.name in containers:
|
|
37
|
-
_state =
|
|
40
|
+
_state = "waiting"
|
|
38
41
|
if status.state.running:
|
|
39
|
-
_state =
|
|
42
|
+
_state = "running"
|
|
40
43
|
elif status.state.terminated:
|
|
41
|
-
_state =
|
|
44
|
+
_state = "terminated"
|
|
42
45
|
try:
|
|
43
46
|
image_sha = status.image_id.split("@")[1]
|
|
44
47
|
except IndexError:
|
|
@@ -13,7 +13,11 @@ logger = logging.getLogger(__name__)
|
|
|
13
13
|
|
|
14
14
|
@timeit
|
|
15
15
|
def sync_services(
|
|
16
|
-
session: Session,
|
|
16
|
+
session: Session,
|
|
17
|
+
client: K8sClient,
|
|
18
|
+
update_tag: int,
|
|
19
|
+
cluster: Dict,
|
|
20
|
+
pods: List[Dict],
|
|
17
21
|
) -> None:
|
|
18
22
|
services = get_services(client, cluster, pods)
|
|
19
23
|
load_services(session, services, update_tag)
|
|
@@ -44,9 +48,9 @@ def get_services(client: K8sClient, cluster: Dict, pods: List[Dict]) -> List[Dic
|
|
|
44
48
|
is_service_pod = True if service.spec.selector else False
|
|
45
49
|
for selector in service.spec.selector or dict():
|
|
46
50
|
if (
|
|
47
|
-
not pod.get("labels")
|
|
48
|
-
selector not in pod["labels"]
|
|
49
|
-
service.spec.selector[selector] != pod["labels"][selector]
|
|
51
|
+
not pod.get("labels")
|
|
52
|
+
or selector not in pod["labels"]
|
|
53
|
+
or service.spec.selector[selector] != pod["labels"][selector]
|
|
50
54
|
):
|
|
51
55
|
is_service_pod = False
|
|
52
56
|
break
|
|
@@ -20,8 +20,8 @@ def start_lastpass_ingestion(neo4j_session: neo4j.Session, config: Config) -> No
|
|
|
20
20
|
|
|
21
21
|
if not config.lastpass_cid or not config.lastpass_provhash:
|
|
22
22
|
logger.info(
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
"Lastpass import is not configured - skipping this module. "
|
|
24
|
+
"See docs to configure.",
|
|
25
25
|
)
|
|
26
26
|
return
|
|
27
27
|
|
|
@@ -35,13 +35,17 @@ def sync(
|
|
|
35
35
|
@timeit
|
|
36
36
|
def get(lastpass_provhash: str, tenant_id: int) -> Dict[str, Any]:
|
|
37
37
|
payload = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
"cid": tenant_id,
|
|
39
|
+
"provhash": lastpass_provhash,
|
|
40
|
+
"cmd": "getuserdata",
|
|
41
|
+
"data": None,
|
|
42
42
|
}
|
|
43
43
|
session = Session()
|
|
44
|
-
req = session.post(
|
|
44
|
+
req = session.post(
|
|
45
|
+
"https://lastpass.com/enterpriseapi.php",
|
|
46
|
+
data=payload,
|
|
47
|
+
timeout=_TIMEOUT,
|
|
48
|
+
)
|
|
45
49
|
req.raise_for_status()
|
|
46
50
|
return req.json()
|
|
47
51
|
|
|
@@ -49,11 +53,13 @@ def get(lastpass_provhash: str, tenant_id: int) -> Dict[str, Any]:
|
|
|
49
53
|
@timeit
|
|
50
54
|
def transform(api_result: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
51
55
|
result: List[Dict[str, Any]] = []
|
|
52
|
-
for uid, user in api_result[
|
|
56
|
+
for uid, user in api_result["Users"].items():
|
|
53
57
|
n_user = user.copy()
|
|
54
|
-
n_user[
|
|
55
|
-
for k in (
|
|
56
|
-
n_user[k] =
|
|
58
|
+
n_user["id"] = int(uid)
|
|
59
|
+
for k in ("created", "last_pw_change", "last_login"):
|
|
60
|
+
n_user[k] = (
|
|
61
|
+
int(dt_parse.parse(user[k]).timestamp() * 1000) if user[k] else None
|
|
62
|
+
)
|
|
57
63
|
result.append(n_user)
|
|
58
64
|
return result
|
|
59
65
|
|
|
@@ -68,7 +74,7 @@ def load_users(
|
|
|
68
74
|
load(
|
|
69
75
|
neo4j_session,
|
|
70
76
|
LastpassTenantSchema(),
|
|
71
|
-
[{
|
|
77
|
+
[{"id": tenant_id}],
|
|
72
78
|
lastupdated=update_tag,
|
|
73
79
|
)
|
|
74
80
|
|
|
@@ -81,5 +87,10 @@ def load_users(
|
|
|
81
87
|
)
|
|
82
88
|
|
|
83
89
|
|
|
84
|
-
def cleanup(
|
|
85
|
-
|
|
90
|
+
def cleanup(
|
|
91
|
+
neo4j_session: neo4j.Session,
|
|
92
|
+
common_job_parameters: Dict[str, Any],
|
|
93
|
+
) -> None:
|
|
94
|
+
GraphJob.from_node_schema(LastpassUserSchema(), common_job_parameters).run(
|
|
95
|
+
neo4j_session,
|
|
96
|
+
)
|
|
@@ -11,17 +11,19 @@ from oci.exceptions import ConfigFileNotFound
|
|
|
11
11
|
from oci.exceptions import InvalidConfig
|
|
12
12
|
from oci.exceptions import ProfileNotFound
|
|
13
13
|
|
|
14
|
+
from cartography.config import Config
|
|
15
|
+
|
|
14
16
|
from . import iam
|
|
15
17
|
from . import organizations
|
|
16
18
|
from . import utils
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
# from cartography.util import run_analysis_job
|
|
19
21
|
# from cartography.util import run_cleanup_job
|
|
20
22
|
# from . import network
|
|
21
23
|
# from . import compute
|
|
22
24
|
|
|
23
25
|
logger = logging.getLogger(__name__)
|
|
24
|
-
Resources = namedtuple(
|
|
26
|
+
Resources = namedtuple("Resources", "compute iam network")
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def _sync_one_account(
|
|
@@ -32,11 +34,21 @@ def _sync_one_account(
|
|
|
32
34
|
common_job_parameters: Dict[str, Any],
|
|
33
35
|
) -> None:
|
|
34
36
|
logger.info("Syncing OCI IAM client for OCI Tenancy with ID '%s'.", tenancy_id)
|
|
35
|
-
iam.sync(
|
|
37
|
+
iam.sync(
|
|
38
|
+
neo4j_session,
|
|
39
|
+
resources.iam,
|
|
40
|
+
tenancy_id,
|
|
41
|
+
oci_sync_tag,
|
|
42
|
+
common_job_parameters,
|
|
43
|
+
)
|
|
36
44
|
|
|
37
45
|
regions = utils.get_regions_in_tenancy(neo4j_session, tenancy_id)
|
|
38
46
|
for region in regions:
|
|
39
|
-
logger.info(
|
|
47
|
+
logger.info(
|
|
48
|
+
"Syncing OCI region '%s' for OCI Tenancy with ID '%s'.",
|
|
49
|
+
region["name"],
|
|
50
|
+
tenancy_id,
|
|
51
|
+
)
|
|
40
52
|
_change_resources_region(resources, region["name"])
|
|
41
53
|
# compute.sync(neo4j_session, resources.compute,
|
|
42
54
|
# tenancy_id, region["name"], oci_sync_tag, common_job_parameters
|
|
@@ -56,15 +68,25 @@ def _sync_multiple_accounts(
|
|
|
56
68
|
sync_tag: int,
|
|
57
69
|
common_job_parameters: Dict[str, Any],
|
|
58
70
|
) -> None:
|
|
59
|
-
logger.debug("Syncing OCI accounts: %s",
|
|
71
|
+
logger.debug("Syncing OCI accounts: %s", ", ".join(accounts.keys()))
|
|
60
72
|
organizations.sync(neo4j_session, accounts, sync_tag, common_job_parameters)
|
|
61
73
|
|
|
62
74
|
for name in accounts:
|
|
63
|
-
logger.info(
|
|
75
|
+
logger.info(
|
|
76
|
+
"Syncing OCI Tenancy with ID '%s' using configured profile '%s'.",
|
|
77
|
+
accounts[name]["tenancy"],
|
|
78
|
+
name,
|
|
79
|
+
)
|
|
64
80
|
resources = _initialize_resources(accounts[name])
|
|
65
81
|
tenancy_id = accounts[name]["tenancy"]
|
|
66
82
|
common_job_parameters["OCI_TENANCY_ID"] = tenancy_id
|
|
67
|
-
_sync_one_account(
|
|
83
|
+
_sync_one_account(
|
|
84
|
+
neo4j_session,
|
|
85
|
+
resources,
|
|
86
|
+
tenancy_id,
|
|
87
|
+
sync_tag,
|
|
88
|
+
common_job_parameters,
|
|
89
|
+
)
|
|
68
90
|
|
|
69
91
|
del common_job_parameters["OCI_TENANCY_ID"]
|
|
70
92
|
|
|
@@ -82,7 +104,9 @@ def _change_resources_region(resources: NamedTuple, region: str) -> None:
|
|
|
82
104
|
resource.base_client.set_region(region)
|
|
83
105
|
|
|
84
106
|
|
|
85
|
-
def _get_network_resource(
|
|
107
|
+
def _get_network_resource(
|
|
108
|
+
credentials: Dict[str, Any],
|
|
109
|
+
) -> oci.core.virtual_network_client.VirtualNetworkClient:
|
|
86
110
|
"""
|
|
87
111
|
Instantiates a OCI VirtualNetworkClient resource object to call the Network API.
|
|
88
112
|
See https://docs.cloud.oracle.com/en-us/iaas/Content/Network/Concepts/overview.htm.
|
|
@@ -92,7 +116,9 @@ def _get_network_resource(credentials: Dict[str, Any]) -> oci.core.virtual_netwo
|
|
|
92
116
|
return oci.core.VirtualNetworkClient(credentials)
|
|
93
117
|
|
|
94
118
|
|
|
95
|
-
def _get_iam_resource(
|
|
119
|
+
def _get_iam_resource(
|
|
120
|
+
credentials: Dict[str, Any],
|
|
121
|
+
) -> oci.identity.identity_client.IdentityClient:
|
|
96
122
|
"""
|
|
97
123
|
Instantiates a OCI IdentityCleint resource object to call the Identity API. This is used to users,
|
|
98
124
|
..., ... and ... data. See https://docs.cloud.oracle.com/iaas/Content/Compute/Concepts/computeoverview.htm.
|
|
@@ -102,7 +128,9 @@ def _get_iam_resource(credentials: Dict[str, Any]) -> oci.identity.identity_clie
|
|
|
102
128
|
return oci.identity.IdentityClient(credentials)
|
|
103
129
|
|
|
104
130
|
|
|
105
|
-
def _get_compute_resource(
|
|
131
|
+
def _get_compute_resource(
|
|
132
|
+
credentials: Dict[str, Any],
|
|
133
|
+
) -> oci.core.compute_client.ComputeClient:
|
|
106
134
|
"""
|
|
107
135
|
Instantiates a OCI ComputeClient resource object to call the Compute API. This is used to pull zone, instance, and
|
|
108
136
|
networking data. https://docs.cloud.oracle.com/iaas/Content/Compute/Concepts/computeoverview.htm.
|
|
@@ -180,7 +208,12 @@ def start_oci_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
|
180
208
|
)
|
|
181
209
|
return
|
|
182
210
|
|
|
183
|
-
_sync_multiple_accounts(
|
|
211
|
+
_sync_multiple_accounts(
|
|
212
|
+
neo4j_session,
|
|
213
|
+
oci_accounts,
|
|
214
|
+
config.update_tag,
|
|
215
|
+
common_job_parameters,
|
|
216
|
+
)
|
|
184
217
|
|
|
185
218
|
# Look into adding analysis job once compute is implemented.
|
|
186
219
|
# run_analysis_job(
|