import logging
import boto3


""" Stop and remove VPC Flow Logs collection artifacts on the compromised instance. """

logger = logging.getLogger(__name__)


class Plugin(object):
    def __init__(
        self,
        boto_session,
        compromised_resource,
        dry_run
    ):

        self.session = boto_session
        self.compromised_resource = compromised_resource
        self.compromise_type = compromised_resource["compromise_type"]
        self.examiner_cidr_range = compromised_resource["examiner_cidr_range"]
        self.dry_run = dry_run

        self.setup()

    def setup(self) -> None:
        self.client = self._get_client()
        self.logs_client = self._get_client("logs")
        self.iam_client = self._get_client("iam")

        self._cleanup()

    def validate(self) -> bool:
        """Skip validation for now. Ideally should validate that the flow logs and the respective infra have been deleted."""
        return True

    def _get_client(self, service_name="ec2") -> boto3.session.Session:
        client = self.session.client(
            service_name=service_name
        )
        return client

    def _generate_log_group_name(self) -> str:
        return "/aws/logs/vpc-flow-logs/xv-sec-aws-ir/" + self.compromised_resource["case_number"] # Must be IR-...

    def _delete_existing_subscription_filter(self, log_group_name: str, filter_name: str) -> None:
        try:
            response = self.logs_client.describe_subscription_filters(
                logGroupName=log_group_name,
                filterNamePrefix=filter_name
            )

            filter_found = False
            for filter in response["subscriptionFilters"]:
                if filter["filterName"] == filter_name:
                    logger.info("Filter {} found. Proceeding to remove it from the target account.".format(filter_name))
                    filter_found = True
                    break

            if filter_found:
                self.logs_client.delete_subscription_filter(
                    logGroupName=log_group_name,
                    filterName=filter_name
                )
        except self.logs_client.exceptions.ResourceNotFoundException as e:
            logger.error(e)
            logger.error("{} was not found.".format(filter_name))
        except Exception as e:
            logger.error(e)
            logger.error("Failed to delete the filter {}".format(filter_name))

    def _delete_log_group(self, log_group_name: str) -> None:
        try:
            self.logs_client.delete_log_group(
                logGroupName=log_group_name
            )
        except self.logs_client.exceptions.ResourceNotFoundException as e:
            logger.error(e)
            logger.error("{} was not found.".format(log_group_name))
            raise e
        except Exception as e:
            logger.error(e)
            logger.error("Failed to delete the log group {}".format(log_group_name))
            raise e

    def _delete_flow_logs(self) -> None:
        try:
            # Get flow log ids of those with our specific tags
            flow_log_ids = []
            response = self.client.describe_flow_logs(
                DryRun=self.dry_run,
                Filters=[
                    {
                        "Name": "tag:CaseNumber",
                        "Values": [
                            self.compromised_resource["case_number"]
                        ]
                    },
                    {
                        "Name": "tag:Instance",
                        "Values": [
                            self.compromised_resource["instance_id"]
                        ]
                    }
                ]
            )

            for flowlog in response["FlowLogs"]:
                logger.info("Found flow log {}".format(flowlog["FlowLogId"]))
                flow_log_ids.append(flowlog["FlowLogId"])

            self.client.delete_flow_logs(
                DryRun=self.dry_run,
                FlowLogIds=flow_log_ids
            )
            logger.info("Deleted flow logs {}".format(flow_log_ids))
        except Exception as e:
            logger.error(e)

    def _cleanup(self) -> None:
        """Delete Cloudwatch Log Group, Subscription Filter, and VPC Flow Logs"""
        try:
            log_group_name = self._generate_log_group_name()

            # Delete any subscription filter specific to the case number
            self._delete_existing_subscription_filter(
                log_group_name,
                "xv-sec-aws-ir-cwlogs-filter-" + self.compromised_resource["case_number"]
            )

            # Delete log group
            self._delete_log_group(log_group_name)

            # Remove all flow logs
            self._delete_flow_logs()

        except Exception as e:
            logger.error(e)

import logging
import boto3


""" Stop and remove VPC Flow Logs collection artifacts on the compromised instance. """

logger = logging.getLogger(__name__)


class Plugin(object):
    def __init__(
        self,
        boto_session,
        compromised_resource,
        dry_run
    ):

        self.session = boto_session
        self.compromised_resource = compromised_resource
        self.compromise_type = compromised_resource["compromise_type"]
        self.examiner_cidr_range = compromised_resource["examiner_cidr_range"]
        self.dry_run = dry_run

        self.setup()

    def setup(self) -> None:
        self.client = self._get_client()
        self.logs_client = self._get_client("logs")
        self.iam_client = self._get_client("iam")

        self._cleanup()

    def validate(self) -> bool:
        """Skip validation for now. Ideally should validate that the flow logs and the respective infra have been deleted."""
        return True

    def _get_client(self, service_name="ec2") -> boto3.session.Session:
        client = self.session.client(
            service_name=service_name
        )
        return client

    def _generate_log_group_name(self) -> str:
        return "/aws/logs/vpc-flow-logs/xv-sec-aws-ir/" + self.compromised_resource["case_number"] # Must be IR-...

    def _delete_existing_subscription_filter(self, log_group_name: str, filter_name: str) -> None:
        try:
            response = self.logs_client.describe_subscription_filters(
                logGroupName=log_group_name,
                filterNamePrefix=filter_name
            )

            filter_found = False
            for filter in response["subscriptionFilters"]:
                if filter["filterName"] == filter_name:
                    logger.info("Filter {} found. Proceeding to remove it from the target account.".format(filter_name))
                    filter_found = True
                    break

            if filter_found:
                self.logs_client.delete_subscription_filter(
                    logGroupName=log_group_name,
                    filterName=filter_name
                )
        except self.logs_client.exceptions.ResourceNotFoundException as e:
            logger.error(e)
            logger.error("{} was not found.".format(filter_name))
        except Exception as e:
            logger.error(e)
            logger.error("Failed to delete the filter {}".format(filter_name))

    def _delete_log_group(self, log_group_name: str) -> None:
        try:
            self.logs_client.delete_log_group(
                logGroupName=log_group_name
            )
        except self.logs_client.exceptions.ResourceNotFoundException as e:
            logger.error(e)
            logger.error("{} was not found.".format(log_group_name))
            raise e
        except Exception as e:
            logger.error(e)
            logger.error("Failed to delete the log group {}".format(log_group_name))
            raise e

    def _delete_flow_logs(self) -> None:
        try:
            # Get flow log ids of those with our specific tags
            flow_log_ids = []
            response = self.client.describe_flow_logs(
                DryRun=self.dry_run,
                Filters=[
                    {
                        "Name": "tag:CaseNumber",
                        "Values": [
                            self.compromised_resource["case_number"]
                        ]
                    },
                    {
                        "Name": "tag:Instance",
                        "Values": [
                            self.compromised_resource["instance_id"]
                        ]
                    }
                ]
            )

            for flowlog in response["FlowLogs"]:
                logger.info("Found flow log {}".format(flowlog["FlowLogId"]))
                flow_log_ids.append(flowlog["FlowLogId"])

            self.client.delete_flow_logs(
                DryRun=self.dry_run,
                FlowLogIds=flow_log_ids
            )
            logger.info("Deleted flow logs {}".format(flow_log_ids))
        except Exception as e:
            logger.error(e)

    def _cleanup(self) -> None:
        """Delete Cloudwatch Log Group, Subscription Filter, and VPC Flow Logs"""
        try:
            log_group_name = self._generate_log_group_name()

            # Delete any subscription filter specific to the case number
            self._delete_existing_subscription_filter(
                log_group_name,
                "xv-sec-aws-ir-cwlogs-filter-" + self.compromised_resource["case_number"]
            )

            # Delete log group
            self._delete_log_group(log_group_name)

            # Remove all flow logs
            self._delete_flow_logs()

        except Exception as e:
            logger.error(e)

Stop and remove VPC Flow Logs collection artifacts on the compromised instance. Skip validation for now. Ideally should validate that the flow logs and the respective infra have been deleted. # Must be IR-... # Get flow log ids of those with our specific tags Delete Cloudwatch Log Group, Subscription Filter, and VPC Flow Logs # Delete any subscription filter specific to the case number # Delete log group # Remove all flow logs