def test_ap_multi_sec_logs(self, request, kube_apis,
                               crd_ingress_controller_with_ap,
                               appprotect_setup, test_namespace):
        """
        Test corresponding log entries with multiple log destinations (in this case, two syslog servers)
        """
        src_syslog2_yaml = f"{TEST_DATA}/appprotect/syslog2.yaml"
        log_loc = "/var/log/messages"

        print("Create a second syslog server")
        create_items_from_yaml(kube_apis, src_syslog2_yaml, test_namespace)

        syslog_dst = f"syslog-svc.{test_namespace}"
        syslog2_dst = f"syslog2-svc.{test_namespace}"

        syslog_pod = get_pod_name_that_contains(kube_apis.v1, test_namespace,
                                                "syslog-")
        syslog2_pod = get_pod_name_that_contains(kube_apis.v1, test_namespace,
                                                 "syslog2")

        with open(src_ing_yaml) as f:
            doc = yaml.safe_load(f)

            doc["metadata"]["annotations"][
                "appprotect.f5.com/app-protect-policy"] = ap_policy
            doc["metadata"]["annotations"][
                "appprotect.f5.com/app-protect-enable"] = "True"
            doc["metadata"]["annotations"][
                "appprotect.f5.com/app-protect-security-log-enable"] = "True"

            # both lists need to be the same length, if one of the referenced configs is invalid/non-existent then no logconfs are applied.
            doc["metadata"]["annotations"][
                "appprotect.f5.com/app-protect-security-log"] = f"{test_namespace}/logconf,{test_namespace}/logconf"

            doc["metadata"]["annotations"][
                "appprotect.f5.com/app-protect-security-log-destination"] = f"syslog:server={syslog_dst}:514,syslog:server={syslog2_dst}:514"

        create_ingress(kube_apis.networking_v1, test_namespace, doc)

        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        wait_before_test(30)
        ensure_response_from_backend(appprotect_setup.req_url,
                                     ingress_host,
                                     check404=True)

        print("----------------------- Send request ----------------------")
        response = requests.get(appprotect_setup.req_url + "/<script>",
                                headers={"host": ingress_host},
                                verify=False)
        print(response.text)
        log_contents = ""
        log2_contents = ""
        retry = 0
        while ("ASM:attack_type" not in log_contents
               and "ASM:attack_type" not in log2_contents and retry <= 60):
            log_contents = get_file_contents(kube_apis.v1, log_loc, syslog_pod,
                                             test_namespace)
            log2_contents = get_file_contents(kube_apis.v1, log_loc,
                                              syslog2_pod, test_namespace)
            retry += 1
            wait_before_test(1)
            print(f"Security log not updated, retrying... #{retry}")

        reload_ms = get_last_reload_time(appprotect_setup.metrics_url, "nginx")
        print(f"last reload duration: {reload_ms} ms")
        reload_times[
            f"{request.node.name}"] = f"last reload duration: {reload_ms} ms"

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)
        delete_items_from_yaml(kube_apis, src_syslog2_yaml, test_namespace)
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod, test_namespace)

        assert_invalid_responses(response)
        # check logs in dest. #1 i.e. syslog server #1
        assert (
            'ASM:attack_type="Non-browser Client,Abuse of Functionality,Cross Site Scripting (XSS)"'
            in log_contents and 'severity="Critical"' in log_contents
            and 'request_status="blocked"' in log_contents
            and 'outcome="REJECTED"' in log_contents)
        # check logs in dest. #2 i.e. syslog server #2
        assert (
            'ASM:attack_type="Non-browser Client,Abuse of Functionality,Cross Site Scripting (XSS)"'
            in log2_contents and 'severity="Critical"' in log2_contents
            and 'request_status="blocked"' in log2_contents
            and 'outcome="REJECTED"' in log2_contents)
    def test_ap_sec_logs_on(
        self,
        request,
        kube_apis,
        ingress_controller_prerequisites,
        crd_ingress_controller_with_ap,
        appprotect_setup,
        test_namespace,
    ):
        """
        Test corresponding log entries with correct policy (includes setting up a syslog server as defined in syslog.yaml)
        """
        log_loc = "/var/log/messages"
        syslog_dst = f"syslog-svc.{test_namespace}"
        syslog_pod = get_pod_name_that_contains(kube_apis.v1, test_namespace,
                                                "syslog-")

        create_ingress_with_ap_annotations(kube_apis, src_ing_yaml,
                                           test_namespace, ap_policy, "True",
                                           "True", f"{syslog_dst}:514")
        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        print(
            "--------- Run test while AppProtect module is enabled with correct policy ---------"
        )

        ensure_response_from_backend(appprotect_setup.req_url,
                                     ingress_host,
                                     check404=True)

        print(
            "----------------------- Send invalid request ----------------------"
        )
        response_block = requests.get(appprotect_setup.req_url + "/<script>",
                                      headers={"host": ingress_host},
                                      verify=False)
        print(response_block.text)
        log_contents_block = ""
        retry = 0
        while "ASM:attack_type" not in log_contents_block and retry <= 30:
            log_contents_block = get_file_contents(kube_apis.v1, log_loc,
                                                   syslog_pod, test_namespace)
            retry += 1
            wait_before_test(1)
            print(f"Security log not updated, retrying... #{retry}")

        print(
            "----------------------- Send valid request ----------------------"
        )
        headers = {
            "Host":
            ingress_host,
            "User-Agent":
            "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0",
        }
        response = requests.get(appprotect_setup.req_url,
                                headers=headers,
                                verify=False)
        print(response.text)
        wait_before_test(10)
        log_contents = get_file_contents(kube_apis.v1, log_loc, syslog_pod,
                                         test_namespace)

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod, test_namespace)

        assert_invalid_responses(response_block)
        assert (
            'ASM:attack_type="Non-browser Client,Abuse of Functionality,Cross Site Scripting (XSS)"'
            in log_contents_block)
        assert 'severity="Critical"' in log_contents_block
        assert 'request_status="blocked"' in log_contents_block
        assert 'outcome="REJECTED"' in log_contents_block

        assert_valid_responses(response)
        assert 'ASM:attack_type="N/A"' in log_contents
        assert 'severity="Informational"' in log_contents
        assert 'request_status="passed"' in log_contents
        assert 'outcome="PASSED"' in log_contents
Example #3
0
    def test_dos_arbitrator(self, kube_apis, ingress_controller_prerequisites,
                            crd_ingress_controller_with_dos, dos_setup,
                            test_namespace):
        """
        Test App Protect Dos: Check new IC pod get learning info
        """
        print(
            "----------------------- Get syslog pod name ----------------------"
        )
        syslog_pod = self.getPodNameThatContains(
            kube_apis, ingress_controller_prerequisites.namespace, "syslog")
        assert "syslog" in syslog_pod
        log_loc = f"/var/log/messages"
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod,
                            ingress_controller_prerequisites.namespace)

        print(
            "------------------------- Deploy ingress -----------------------------"
        )
        create_ingress_with_dos_annotations(kube_apis, src_ing_yaml,
                                            test_namespace,
                                            test_namespace + "/dos-protected")
        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        # print("------------------------- Learning Phase -----------------------------")
        print("start good clients requests")
        p_good_client = subprocess.Popen([
            f"exec {TEST_DATA}/dos/good_clients_xff.sh {ingress_host} {dos_setup.req_url}"
        ],
                                         preexec_fn=os.setsid,
                                         shell=True,
                                         stdout=subprocess.DEVNULL,
                                         stderr=subprocess.DEVNULL)

        print("Learning for max 10 minutes")
        find_in_log(kube_apis, log_loc, syslog_pod,
                    ingress_controller_prerequisites.namespace, 600,
                    "learning_confidence=\"Ready\"")

        print(
            "------------------------- Check new IC pod get info from arbitrator -----------------------------"
        )
        ic_ns = ingress_controller_prerequisites.namespace
        scale_deployment(kube_apis.v1, kube_apis.apps_v1_api, "nginx-ingress",
                         ic_ns, 2)
        while get_pods_amount_with_name(kube_apis.v1, "nginx-ingress",
                                        "nginx-ingress") is not 2:
            print(f"Number of replicas is not 2, retrying...")
            wait_before_test()

        print(
            "------------------------- Check if new pod receive info from arbitrator -----------------------------"
        )
        print("Wait for 30 seconds")
        wait_before_test(30)

        log_contents = get_file_contents(
            kube_apis.v1, log_loc, syslog_pod,
            ingress_controller_prerequisites.namespace)
        log_info_dic = log_content_to_dic(log_contents)

        print("Stop Good Client")
        p_good_client.terminate()

        learning_units_hostname = []
        for log in log_info_dic:
            if log['unit_hostname'] not in learning_units_hostname and log[
                    'learning_confidence'] == "Ready":
                learning_units_hostname.append(log['unit_hostname'])

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)

        assert (len(learning_units_hostname) == 2)
Example #4
0
    def test_dos_under_attack_with_learning(self, kube_apis,
                                            ingress_controller_prerequisites,
                                            crd_ingress_controller_with_dos,
                                            dos_setup, test_namespace):
        """
        Test App Protect Dos: Block bad clients attack with learning
        """
        log_loc = f"/var/log/messages"
        print(
            "----------------------- Get syslog pod name ----------------------"
        )
        syslog_pod = self.getPodNameThatContains(
            kube_apis, ingress_controller_prerequisites.namespace, "syslog")
        assert "syslog" in syslog_pod
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod,
                            ingress_controller_prerequisites.namespace)

        print(
            "------------------------- Deploy ingress -----------------------------"
        )
        create_ingress_with_dos_annotations(kube_apis, src_ing_yaml,
                                            test_namespace,
                                            test_namespace + "/dos-protected")
        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        print(
            "------------------------- Learning Phase -----------------------------"
        )
        print("start good clients requests")
        p_good_client = subprocess.Popen([
            f"exec {TEST_DATA}/dos/good_clients_xff.sh {ingress_host} {dos_setup.req_url}"
        ],
                                         preexec_fn=os.setsid,
                                         shell=True,
                                         stdout=subprocess.DEVNULL,
                                         stderr=subprocess.DEVNULL)

        print("Learning for max 10 minutes")
        find_in_log(kube_apis, log_loc, syslog_pod,
                    ingress_controller_prerequisites.namespace, 600,
                    "learning_confidence=\"Ready\"")

        print("------------------------- Attack -----------------------------")
        print("start bad clients requests")
        p_attack = subprocess.Popen([
            f"exec {TEST_DATA}/dos/bad_clients_xff.sh {ingress_host} {dos_setup.req_url}"
        ],
                                    preexec_fn=os.setsid,
                                    shell=True,
                                    stdout=subprocess.DEVNULL,
                                    stderr=subprocess.DEVNULL)

        print("Attack for 300 seconds")
        wait_before_test(300)

        print("Stop Attack")
        p_attack.terminate()

        print("wait max 140 seconds after attack stop, to get attack ended")
        find_in_log(kube_apis, log_loc, syslog_pod,
                    ingress_controller_prerequisites.namespace, 140,
                    "attack_event=\"Attack ended\"")

        print("Stop Good Client")
        p_good_client.terminate()

        log_contents = get_file_contents(
            kube_apis.v1, log_loc, syslog_pod,
            ingress_controller_prerequisites.namespace)
        log_info_dic = log_content_to_dic(log_contents)

        # Analyze the log
        no_attack = False
        attack_started = False
        under_attack = False
        attack_ended = False
        bad_actor_detected = False
        signature_detected = False
        health_ok = False
        bad_ip = ['1.1.1.1', '1.1.1.2', '1.1.1.3']
        fmt = '%b %d %Y %H:%M:%S'
        for log in log_info_dic:
            if log['attack_event'] == 'No Attack':
                if int(log['dos_attack_id']) == 0 and not no_attack:
                    no_attack = True
            elif log['attack_event'] == 'Attack started':
                if int(log['dos_attack_id']) > 0 and not attack_started:
                    attack_started = True
                    start_attack_time = datetime.strptime(
                        log['date_time'], fmt)
            elif log['attack_event'] == 'Under Attack':
                under_attack = True
                if not health_ok and float(log['stress_level']) < 0.6:
                    health_ok = True
                    health_ok_time = datetime.strptime(log['date_time'], fmt)
            elif log['attack_event'] == 'Attack signature detected':
                signature_detected = True
            elif log['attack_event'] == 'Bad actors detected':
                if under_attack:
                    bad_actor_detected = True
            elif log['attack_event'] == 'Bad actor detection':
                if under_attack and log['source_ip'] in bad_ip:
                    bad_ip.remove(log['source_ip'])
            elif log['attack_event'] == 'Attack ended':
                attack_ended = True

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)

        assert (no_attack and attack_started and under_attack and attack_ended
                and health_ok
                and (health_ok_time - start_attack_time).total_seconds() < 150
                and signature_detected and bad_actor_detected
                and len(bad_ip) == 0)
Example #5
0
    def test_dos_under_attack_no_learning(self, kube_apis,
                                          ingress_controller_prerequisites,
                                          crd_ingress_controller_with_dos,
                                          dos_setup, test_namespace):
        """
        Test App Protect Dos: Block bad clients attack
        """
        log_loc = f"/var/log/messages"
        print(
            "----------------------- Get syslog pod name ----------------------"
        )
        syslog_pod = self.getPodNameThatContains(
            kube_apis, ingress_controller_prerequisites.namespace, "syslog")
        assert "syslog" in syslog_pod
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod,
                            ingress_controller_prerequisites.namespace)

        print(
            "------------------------- Deploy ingress -----------------------------"
        )
        create_ingress_with_dos_annotations(kube_apis, src_ing_yaml,
                                            test_namespace,
                                            test_namespace + "/dos-protected")
        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        print("------------------------- Attack -----------------------------")
        wait_before_test(10)
        print("start bad clients requests")
        p_attack = subprocess.Popen([
            f"exec {TEST_DATA}/dos/bad_clients_xff.sh {ingress_host} {dos_setup.req_url}"
        ],
                                    shell=True,
                                    stdout=subprocess.DEVNULL,
                                    stderr=subprocess.DEVNULL)

        print("Attack for 30 seconds")
        wait_before_test(30)

        print("Stop Attack")
        p_attack.terminate()

        print("wait max 140 seconds after attack stop, to get attack ended")
        find_in_log(kube_apis, log_loc, syslog_pod,
                    ingress_controller_prerequisites.namespace, 140,
                    "attack_event=\"Attack ended\"")

        log_contents = get_file_contents(
            kube_apis.v1, log_loc, syslog_pod,
            ingress_controller_prerequisites.namespace)
        log_info_dic = log_content_to_dic(log_contents)

        # Analyze the log
        no_attack = False
        attack_started = False
        under_attack = False
        attack_ended = False
        for log in log_info_dic:
            # Start with no attack
            if log['attack_event'] == "No Attack" and int(
                    log['dos_attack_id']) == 0 and not no_attack:
                no_attack = True
            # Attack started
            elif log['attack_event'] == "Attack started" and int(
                    log['dos_attack_id']) > 0 and not attack_started:
                attack_started = True
            # Under attack
            elif log['attack_event'] == "Under Attack" and int(
                    log['dos_attack_id']) > 0 and not under_attack:
                under_attack = True
            # Attack ended
            elif log['attack_event'] == "Attack ended" and int(
                    log['dos_attack_id']) > 0 and not attack_ended:
                attack_ended = True

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)

        assert (no_attack and attack_started and under_attack and attack_ended)
Example #6
0
    def test_dos_sec_logs_on(
        self,
        kube_apis,
        ingress_controller_prerequisites,
        crd_ingress_controller_with_dos,
        dos_setup,
        test_namespace,
    ):
        """
        Test corresponding log entries with correct policy (includes setting up a syslog server as defined in syslog.yaml)
        """
        print(
            "----------------------- Get syslog pod name ----------------------"
        )
        syslog_pod = self.getPodNameThatContains(
            kube_apis, ingress_controller_prerequisites.namespace, "syslog")
        assert "syslog" in syslog_pod

        log_loc = f"/var/log/messages"
        clear_file_contents(kube_apis.v1, log_loc, syslog_pod,
                            ingress_controller_prerequisites.namespace)

        create_ingress_with_dos_annotations(kube_apis, src_ing_yaml,
                                            test_namespace,
                                            test_namespace + "/dos-protected")
        ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

        print(
            "--------- Run test while DOS module is enabled with correct policy ---------"
        )

        ensure_response_from_backend(dos_setup.req_url,
                                     ingress_host,
                                     check404=True)
        pod_name = self.getPodNameThatContains(
            kube_apis, ingress_controller_prerequisites.namespace,
            "nginx-ingress")

        get_ingress_nginx_template_conf(kube_apis.v1, test_namespace,
                                        "dos-ingress", pod_name,
                                        "nginx-ingress")

        print("----------------------- Send request ----------------------")
        response = requests.get(dos_setup.req_url,
                                headers={"host": "dos.example.com"},
                                verify=False)
        print(response.text)
        wait_before_test(10)

        print(
            f'log_loc {log_loc} syslog_pod {syslog_pod} namespace {ingress_controller_prerequisites.namespace}'
        )
        log_contents = get_file_contents(
            kube_apis.v1, log_loc, syslog_pod,
            ingress_controller_prerequisites.namespace)

        delete_items_from_yaml(kube_apis, src_ing_yaml, test_namespace)

        print(log_contents)

        assert 'product="app-protect-dos"' in log_contents
        assert f'vs_name="{test_namespace}/dos-protected/name"' in log_contents
        assert 'bad_actor' in log_contents