diff --git a/api/src/backend/tasks/jobs/cartography/__init__.py b/api/src/backend/tasks/jobs/cartography/__init__.py index 638a52cabe..9c2d14137a 100644 --- a/api/src/backend/tasks/jobs/cartography/__init__.py +++ b/api/src/backend/tasks/jobs/cartography/__init__.py @@ -1,3 +1,5 @@ +from operator import ne +from cartography.intel import create_indexes as cartography_indexes from celery.utils.log import get_task_logger from neo4j import GraphDatabase @@ -21,7 +23,7 @@ def cartography_sync_scan( with GraphDatabase.driver("bolt://neo4j:7687", auth=("neo4j", "neo4j_password")) as driver: with driver.session() as neo4j_session: - # TODO: Add `cartography.intel.create_indexes.run` here, before `sync_aws` + cartography_indexes.run(neo4j_session, None) return sync_aws( # TODO: Depending on the provider type use the appropriate sync function tenant_id=tenant_id, @@ -30,4 +32,4 @@ def cartography_sync_scan( neo4j_session=neo4j_session, ) - # TODO: Add `cartography.intel.analysis.run` here, after `sync_aws` + # TODO: Check if we need to add `cartography.intel.analysis.run` here, after `sync_aws` diff --git a/api/src/backend/tasks/jobs/cartography/aws/__init__.py b/api/src/backend/tasks/jobs/cartography/aws/__init__.py index 3c81b1b05b..aeb51ca4fc 100644 --- a/api/src/backend/tasks/jobs/cartography/aws/__init__.py +++ b/api/src/backend/tasks/jobs/cartography/aws/__init__.py @@ -3,6 +3,8 @@ from typing import Any import neo4j +from cartography.intel import aws as cartography_aws + from api.db_utils import rls_transaction from api.models import Provider, ResourceScanSummary from tasks.jobs.cartography.aws.s3 import sync_aws_s3 @@ -29,14 +31,11 @@ def sync_aws( common_job_parameters = {"UPDATE_TAG": update_tag, "AWS_ID": account_id} return { - # "iam": sync_aws_iam(tenant_id, provider_id, account_id, scan_id, regions, neo4j_session, update_tag, common_job_parameters), # noqa: E501 + "iam": sync_aws_iam(tenant_id, provider_id, account_id, scan_id, regions, neo4j_session, update_tag, common_job_parameters), # noqa: E501 "s3": sync_aws_s3(tenant_id, provider_id, account_id, scan_id, regions, neo4j_session, update_tag, common_job_parameters), # noqa: E501 "ecs": sync_aws_ecs(tenant_id, provider_id, account_id, scan_id, regions, neo4j_session, update_tag, common_job_parameters), # noqa: E501 } - # TODO: Add `cartography.intel.aws._perform_aws_analysis` here, after all the sync functions - - def get_aws_provider_account_id(tenant_id: str, provider_id: str) -> str: """ Getting AWS account ID from Prowler DB for a provider. diff --git a/api/src/backend/tasks/jobs/cartography/aws/iam.py b/api/src/backend/tasks/jobs/cartography/aws/iam.py index bdd62088a9..32818f302c 100644 --- a/api/src/backend/tasks/jobs/cartography/aws/iam.py +++ b/api/src/backend/tasks/jobs/cartography/aws/iam.py @@ -240,7 +240,7 @@ def _get_inline_resource_policy_data(resource_data: list[dict[str, Any]]) -> dic for resource in resource_data: inline_policies[resource.get("Arn")] = { - policy_name: None # TODO: The policy document statement is missing + policy_name: {} # TODO: The policy document statement is missing for policy_name in resource.get("InlinePolicies", []) } @@ -282,7 +282,7 @@ def _get_resource_managed_policy_data(resource_data: list[dict[str, Any]]) -> di for resource in resource_data: attached_policies[resource.get("Arn")] = { - policy.get("PolicyArn"): None # TODO: The policy default version document statement is missing + policy.get("PolicyArn"): {} # TODO: The policy default version document statement is missing for policy in resource.get("AttachedPolicies", []) } @@ -465,6 +465,9 @@ def _get_roles_metadata( roles_metadata = [] for role in roles_qs: role_metadata = json.loads(role.metadata) + if not role_metadata.get("name"): + continue + role_metadata["inserted_at"] = role.inserted_at roles_metadata.append(role_metadata) diff --git a/api/src/backend/tasks/jobs/cartography/aws/s3.py b/api/src/backend/tasks/jobs/cartography/aws/s3.py index ac90cca8d1..93140a44bd 100644 --- a/api/src/backend/tasks/jobs/cartography/aws/s3.py +++ b/api/src/backend/tasks/jobs/cartography/aws/s3.py @@ -156,6 +156,16 @@ def _get_and_load_s3_bucket_details( parsed_policy = None # TODO parsed_statements = None # TODO + parsed_acls = _parse_s3_bucket_acl(bucket_metadata, account_id) + if parsed_acls is not None: + acls.append(parsed_acls) + + parsed_policy = _parse_s3_bucket_policy(bucket_metadata) + if parsed_policy is not None: + policies.append(parsed_policy) + + # TODO: More work + parsed_encryption = _parse_s3_bucket_encryption(bucket_metadata) if parsed_encryption is not None: encryption_configs.append(parsed_encryption) @@ -190,10 +200,46 @@ def _get_and_load_s3_bucket_details( cartography_s3._set_default_values(neo4j_session, account_id) +def _parse_s3_bucket_acl(bucket_metadata: dict[str, Any], account_id: str) -> dict[str, Any] | None: + """ + Code based on `cartography.intel.aws.s3.parse_acl`. + # TODO: Key `EmailAddress` is not implemented yet + """ + + if not bucket_metadata.get("acl_grantees"): + return None + + acl = { + "Grants": [], + "Owner": { + "ID": bucket_metadata.get("owner_id"), + "DisplayName": None, + } + } + + for grantee in bucket_metadata.get("acl_grantees"): + acl["Grants"].append({ + "Grantee": { + "DisplayName": grantee.get("display_name"), + # "EmailAddress" # TODO: Grantee.EmailAddress + "ID": grantee.get("ID"), + "Type": grantee.get("type"), + "URI": grantee.get("URI"), + }, + "Permission": grantee.get("permission"), + }) + + return cartography_s3.parse_acl(bucket_metadata.get("name"), bucket_metadata.get("acl_grantees"), account_id) + + +def _parse_s3_bucket_policy(bucket_metadata: dict[str, Any]) -> dict[str, Any] | None: + return None # TODO + + def _parse_s3_bucket_encryption(bucket_metadata: dict[str, Any]) -> dict[str, Any] | None: """ Code based on `cartography.intel.aws.s3.parse_encryption`. - # TODO: Keys `encryption_key_id` and `bucket_key_enabled` are implemented yet. + # TODO: Keys `encryption_key_id` and `bucket_key_enabled` are not implemented yet """ if not bucket_metadata.get("encryption"):